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()
z=c*np.cos(phi)*(h*(-1)**(np.cos(phi)<0))
is probably missing a piece. Could you please double check? Also, your example inspired me add a few things to get the "edges" that I wanted. I am putting that code and figure into a separate answer (as the comment section is really small) – Arcturus