How to connect / connect / group multiple objects in Mayavi2

I would like to combine several Mayavi objects into one “grouped” object so that I control all their properties together. For example, I created the following bivalve lens shape by combining 3 built-in surfaces (two spheres and one cylinder). Now I would like to assign homogeneous properties (specularity, ambient color, etc.) to all constituent surfaces simultaneously (not individually). In addition, I would like to translate / rotate the lens as a whole. I am not sure how to do this.

Here is a two-convex lens created in Mayavi (code below):

enter image description here

As you can see in the following figure, the above lens consists of three surfaces:

enter image description here


Here is the code for building a bicuspid 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() 
+2
source share
2 answers

I do not know how to combine sources in the way you are looking. I think that this is actually possibly impossible, since under the hood the BuiltinSurface object has certain vtk sources that are not what you want. However, it should be possible to simply use a different source that gives what you want. In this case, you can create 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() 

enter image description here

One minor difference is that this surface is smooth. This is the nature of the selection of one surface - i.e. This result is a direct consequence of what your question requires. If this is an important function of your figure, I would suggest a completely different approach: wrap 3 sources in the class and the event handler will update the corresponding attributes for all three.

+1
source

Based on the code from @aestrivex, here is one way to get the desired result (a sharp-edged lens). Please 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 result: enter image description here

+1
source

Source: https://habr.com/ru/post/944240/


All Articles