如何在Mayavi2中加入/连接/分组多个对象

时间:2014-03-07 04:32:46

标签: python vtk enthought mayavi

我想将多个Mayavi对象组合成一个“分组”对象,以便我一起控制它们的所有属性。例如,我通过组合3个内置表面(两个球体和一个圆柱体)创建了以下双凸透镜形状。现在我想一次为所有组成表面分配统一的属性(镜面反射,环境颜色等)(不是单独的)。另外,我想翻译/旋转镜头作为一个整体。我不知道如何做到这一点。

这是在Mayavi中创建的双凸透镜(下面给出的代码):

enter image description here

如下图所示,上述镜头由三个表面组成:

enter image description here


以下是构建双凸透镜的代码:


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 lensUsingMayaviBuiltinSphere(radius=0.5, semiDiam=0.25, thickness=0.9):
    """
    Render a bi-convex lens
    """
    engine = mlab.get_engine()
    sag = radius - np.sqrt(radius**2 - semiDiam**2)
    cyl_height = thickness - 2.0*sag   # thickness of the cylinder in between
    # Create Mayavi data sources -- sphere_h1_src, sphere_h2_src, cylinder_src    
    # half 1: source = sphere_h1_src
    sphere_h1_src = BuiltinSurface()
    engine.add_source(sphere_h1_src)
    sphere_h1_src.source = 'sphere'
    sphere_h1_src.data_source.radius = radius
    sphere_h1_src.data_source.center = np.array([ 0.,  0.,  -np.sqrt(radius**2 - semiDiam**2) + cyl_height/2.0])
    sphere_h1_src.data_source.end_phi = np.rad2deg(np.arcsin(semiDiam/radius)) #60.0
    sphere_h1_src.data_source.end_theta = 360.0
    sphere_h1_src.data_source.phi_resolution = 300
    sphere_h1_src.data_source.theta_resolution = 300
    # half 2: source = sphere_h2_src
    sphere_h2_src = BuiltinSurface()
    engine.add_source(sphere_h2_src)
    sphere_h2_src.source = 'sphere'
    sphere_h2_src.data_source.radius = radius
    sphere_h2_src.data_source.center = np.array([ 0.,  0.,  np.sqrt(radius**2 - semiDiam**2) - cyl_height/2.0])
    sphere_h2_src.data_source.start_phi = 180.0 - np.rad2deg(np.arcsin(semiDiam/radius))
    sphere_h2_src.data_source.end_phi = 180.0
    sphere_h2_src.data_source.end_theta = 360.0
    sphere_h2_src.data_source.phi_resolution = 300
    sphere_h2_src.data_source.theta_resolution = 300
    # cylinder source data in between 
    cylinder_src = BuiltinSurface()
    engine.add_source(cylinder_src)
    cylinder_src.source = 'cylinder'
    cylinder_src.data_source.center = np.array([ 0.,  0.,  0.])
    if cyl_height > 0:
        cylinder_src.data_source.height = cyl_height
    else:
        cylinder_src.data_source.height = 0.0
    cylinder_src.data_source.radius = semiDiam
    cylinder_src.data_source.capping = False
    cylinder_src.data_source.resolution = 50

    # Add transformation filter to align cylinder length along z-axis
    transform_data_filter = TransformData()
    engine.add_filter(transform_data_filter, cylinder_src)
    Rt_c = [ 1.0000,  0.0000,  0.0000,  0.00,
             0.0000,  0.0000, -1.0000,  0.00,
             0.0000,  1.0000,  0.0000,  0.00, 
             0.0000,  0.0000,  0.0000,  1.00]
    transform_data_filter.transform.matrix.__setstate__({'elements': Rt_c})
    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 modules to each source
    right_surface = Surface()
    engine.add_filter(right_surface, sphere_h1_src)
    left_surface = Surface()
    engine.add_filter(left_surface, sphere_h2_src)
    cyl_surface = Surface()
    engine.add_filter(cyl_surface, transform_data_filter)


fig = mlab.figure()
# Add lens
lensUsingMayaviBuiltinSphere(radius=2, semiDiam=1.2)
mlab.show()

2 个答案:

答案 0 :(得分:1)

我不知道如何以您想要的方式组合来源。我认为实际上这可能是不可能的,因为BuiltinSurface对象具有特定的vtk源,而不是你想要的。然而,应该可以简单地使用提供您想要的不同来源。在这种情况下,您可以使用mlab.mesh生成双凸透镜:

a,c,h=3,1,.2

phi,theta = np.mgrid[0:2*np.pi:np.pi/250, 0:2*np.pi:np.pi/250]
x=a*np.cos(theta)*np.sin(phi)
y=a*np.sin(theta)*np.sin(phi)
z=c*np.cos(phi)+(h*(-1)**(np.cos(phi)<0))

mlab.mesh(x,y,z,color=(1,1,1)
mlab.show()

enter image description here

一个小的区别是这个表面是光滑的。这是对单个表面进行采样的本质 - 即,这个结果是您的问题所要求的直接结果。如果这是你图中的一个重要特征,我建议采用一种完全不同的方法:将3个源包装在一个类中,让事件处理程序更新所有三个的相关属性。

答案 1 :(得分:1)

基于@aestrivex的代码,这是获得所需输出的一种方法(具有锐边的镜头)。请注意,这不是连接多个Mayavi对象的解决方案。

import numpy as np
from mayavi import mlab

# Control parameters
# r is the semi-diameter of the lens 
# c controls the center thickness of the lens
# h controls the curvature of the surfaces (lesser the value more the curvature)

r, c, h = 3, .75, .9 

delta_phi = np.pi/250.0             # phi == azimuth  (0 <= phi <= pi)
delta_theta = np.pi/100.0           # theta == zenith (0 <= theta <= pi)
phi, theta = np.mgrid[0:2.0*np.pi + delta_phi:delta_phi,0:np.pi + delta_theta:delta_theta]
# The Exact threshold values for masking tz, txy will change depending upon the
# sampling of theta. txy is always slightly less than tz. tz should be around 0.3
tz, txy = 0.279, 0.275
x = r*np.sin(theta)*np.cos(phi)*(np.abs(np.cos(theta)) > txy)
y = r*np.sin(theta)*np.sin(phi)*(np.abs(np.cos(theta)) > txy)
z = c*np.cos(theta)*(h**(-1)*( np.abs(np.cos(theta)) > tz))

mlab.mesh(x,y,z,color=(1,1,1))

mlab.show()

这是输出: enter image description here