How to join/connect/group multiple objects in Mayavi2

醉酒当歌 提交于 2019-12-13 16:09:12

问题


I would like to combine multiple Mayavi objects into a single "grouped" object so that I control all of their properties together. For example I created the following bi-convex lens shape by combining 3 built-in surfaces (two spheres and one cylinder). Now I would like to assign uniform properties (specularity, ambient color, etc) to all of the constituent surfaces at a time (not individually). Also, I would like to translate/rotate the lens as a whole. I am not sure how to accomplish this.

Here is the bi-convex lens created in Mayavi (code given below):

As it can be seen in the following figure, the above lens is composed of three surfaces:


Here is the code for building the bi-convex lens:


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()

回答1:


Based on the code by @aestrivex, here is one way of getting the desired output (lens with sharp edges). Note that this is not a solution for connecting multiple Mayavi objects.

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()

And here is the output:




回答2:


I don't know of a way to combine sources in the way you are looking for. I think in fact that is probably impossible since under the hood the BuiltinSurface object has specific vtk sources that are not what you want. It should however be possible to simply use a different source that gives what you want. In this case you could generate a biconvex lens with 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()

One minor difference is that this surface is smooth. This is the nature of sampling a single surface --i.e., this result is a direct consequence of what your question asks to do. If this is an important feature of your figure, I would suggest an entirely different approach: wrap the 3 sources in a class and have the event handler update the relevant attributes on all three.



来源:https://stackoverflow.com/questions/22241499/how-to-join-connect-group-multiple-objects-in-mayavi2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!