class VarVisMeshVisual(MeshVisual): """Variable Visibility Mesh visual Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None The values to use for each vertex (for colormapping). meshdata : instance of MeshData | None The meshdata. shading : str | None Shading to use. mode : str The drawing mode. variable_vis : bool If instance of UpdatableMeshVisual has variable visibility **kwargs : dict Keyword arguments to pass to `Visual`. """ def __init__(self, nb_boxes, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=(0.5, 0.5, 1, 1), vertex_values=None, meshdata=None, shading=None, mode='triangles', variable_vis=False, **kwargs): # Visual.__init__ -> prepare_transforms() -> uses shading if shading is not None: raise ValueError('"shading" must be "None"') self.shading = shading self._variable_vis = variable_vis if variable_vis: Visual.__init__(self, vcode=vertex_template_vis, fcode=fragment_template_vis, **kwargs) else: Visual.__init__(self, vcode=vertex_template, fcode=fragment_template, **kwargs) self.set_gl_state('translucent', depth_test=True, cull_face=False) # Define buffers self._vertices = VertexBuffer(np.zeros((0, 3), dtype=np.float32)) self._normals = None self._faces = IndexBuffer() self._normals = VertexBuffer(np.zeros((0, 3), dtype=np.float32)) self._ambient_light_color = Color((0.3, 0.3, 0.3, 1.0)) self._light_dir = (10, 5, -5) self._shininess = 1. / 200. self._cmap = get_colormap('cubehelix') self._clim = 'auto' self._mode = mode # Uniform color self._color = Color(color) # primitive mode self._draw_mode = mode # Init self._bounds = None # Note we do not call subclass set_data -- often the signatures # do no match. VarVisMeshVisual.set_data(self, vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, color=color, vertex_values=vertex_values, meshdata=meshdata) self.freeze() def set_data(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=None, vertex_values=None, meshdata=None): """Set the mesh data Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None Values for each vertex. meshdata : instance of MeshData | None The meshdata. """ if meshdata is not None: self._meshdata = meshdata else: self._meshdata = MeshData(vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, vertex_values=vertex_values) self._bounds = self._meshdata.get_bounds() if color is not None: self._color = Color(color) self.mesh_data_changed() if self.variable_vis: # Initialize all faces as visible if self.mode is 'lines': self._visible_verts = np.ones((faces.shape[0], 2, 1), dtype=np.int8) else: self._visible_verts = np.ones((faces.shape[0], 3, 1), dtype=np.int8) # Create visibility VertexBuffer self.vis_buffer = VertexBuffer() self.vis_buffer.set_data(self._visible_verts) self.shared_program.vert['vis_vert'] = self.vis_buffer def set_visible_faces(self, idx_vis): """Set idx_vis indexes of visible_verts to "visible" (1). """ self.visible_verts[idx_vis, :, :] = 1 def set_invisible_faces(self, idx_vis): """Set idx_vis indexes of visible_verts to "invisible" (0). """ self.visible_verts[idx_vis, :, :] = 0 def update_vis_buffer(self): """Update the visibility VertexBuffer. """ self.vis_buffer.set_data(self.visible_verts) self.shared_program.vert['vis_vert'] = self.vis_buffer @property def visible_verts(self): """Bool (float) array indicating which vertices are visible (1) and which are invisible (0). """ return self._visible_verts @visible_verts.setter def visible_verts(self, visible_verts): self._visible_verts = visible_verts @property def variable_vis(self): """Bool if instance of UpdatableMeshVisual posseses variable visibility. """ return self._variable_vis @variable_vis.setter def variable_vis(self, variable_vis): raise ValueError( 'Not allowed to change "variable_vis" after initialization.')
class MeshVisual(Visual): """Mesh visual Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None The values to use for each vertex (for colormapping). meshdata : instance of MeshData | None The meshdata. shading : str | None Shading to use. This uses the :class:`~vispy.visuals.filters.mesh.ShadingFilter` filter introduced in VisPy 0.7. This class provides additional features that are available when the filter is attached manually. See 'examples/basics/scene/mesh_shading.py' for an example. mode : str The drawing mode. **kwargs : dict Keyword arguments to pass to `Visual`. Notes ----- Additional functionality is available through filters. Mesh-specific filters can be found in the :mod:`vispy.visuals.filters.mesh` module. This class emits a `data_updated` event when the mesh data is updated. This is used for example by filters for synchronization. """ def __init__(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=(0.5, 0.5, 1, 1), vertex_values=None, meshdata=None, shading=None, mode='triangles', **kwargs): Visual.__init__(self, vcode=vertex_template, fcode=fragment_template, **kwargs) self.set_gl_state('translucent', depth_test=True, cull_face=False) self.events.add(data_updated=Event) # Define buffers self._vertices = VertexBuffer(np.zeros((0, 3), dtype=np.float32)) self._cmap = get_colormap('cubehelix') self._clim = 'auto' # Uniform color self._color = Color(color) # add filters for various modifiers self.shading_filter = None self.shading = shading # Init self._bounds = None # Note we do not call subclass set_data -- often the signatures # do no match. MeshVisual.set_data( self, vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, vertex_values=vertex_values, meshdata=meshdata, color=color) # primitive mode self._draw_mode = mode self.freeze() @property def shading(self): """The shading method.""" return self._shading @shading.setter def shading(self, shading): assert shading in (None, 'flat', 'smooth') self._shading = shading if shading is None and self.shading_filter is None: # Delay creation of filter until necessary. return if self.shading_filter is None: from .filters import ShadingFilter self.shading_filter = ShadingFilter(shading=shading) else: self.shading_filter.shading = shading self.attach(self.shading_filter) def set_data(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=None, vertex_values=None, meshdata=None): """Set the mesh data Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None Values for each vertex. meshdata : instance of MeshData | None The meshdata. """ if meshdata is not None: self._meshdata = meshdata else: self._meshdata = MeshData(vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, vertex_values=vertex_values) self._bounds = self._meshdata.get_bounds() if color is not None: self._color = Color(color) self.mesh_data_changed() @property def clim(self): return (self._clim if isinstance(self._clim, str) else tuple(self._clim)) @clim.setter def clim(self, clim): if isinstance(clim, str): if clim != 'auto': raise ValueError('clim must be "auto" if a string') else: clim = np.array(clim, float) if clim.shape != (2,): raise ValueError('clim must have two elements') self._clim = clim self.mesh_data_changed() @property def _clim_values(self): if isinstance(self._clim, str): # == 'auto' if self._meshdata.has_vertex_value(): clim = self._meshdata.get_vertex_values() clim = (np.min(clim), np.max(clim)) else: clim = (0, 1) else: clim = self._clim return clim @property def cmap(self): return self._cmap @cmap.setter def cmap(self, cmap): self._cmap = get_colormap(cmap) self.mesh_data_changed() @property def mode(self): """The triangle mode used to draw this mesh. Options are: * 'triangles': Draw one triangle for every three vertices (eg, [1,2,3], [4,5,6], [7,8,9) * 'triangle_strip': Draw one strip for every vertex excluding the first two (eg, [1,2,3], [2,3,4], [3,4,5]) * 'triangle_fan': Draw each triangle from the first vertex and the last two vertices (eg, [1,2,3], [1,3,4], [1,4,5]) """ return self._draw_mode @mode.setter def mode(self, m): modes = ['triangles', 'triangle_strip', 'triangle_fan'] if m not in modes: raise ValueError("Mesh mode must be one of %s" % ', '.join(modes)) self._draw_mode = m @property def mesh_data(self): """The mesh data""" return self._meshdata @property def color(self): """The uniform color for this mesh""" return self._color @color.setter def color(self, c): """Set the uniform color of the mesh This value is only used if per-vertex or per-face colors are not specified. Parameters ---------- c : instance of Color The color to use. """ if c is not None: self._color = Color(c) self.mesh_data_changed() def mesh_data_changed(self): self._data_changed = True self.update() def _update_data(self): md = self.mesh_data v = md.get_vertices(indexed='faces') if v is None: return False if v.shape[-1] == 2: v = np.concatenate((v, np.zeros((v.shape[:-1] + (1,)))), -1) self._vertices.set_data(v, convert=True) if md.has_vertex_color(): colors = md.get_vertex_colors(indexed='faces') colors = colors.astype(np.float32) elif md.has_face_color(): colors = md.get_face_colors(indexed='faces') colors = colors.astype(np.float32) elif md.has_vertex_value(): colors = md.get_vertex_values(indexed='faces') colors = colors.ravel()[:, np.newaxis] colors = colors.astype(np.float32) else: colors = self._color.rgba self.shared_program.vert['position'] = self._vertices self.shared_program['texture2D_LUT'] = self._cmap.texture_lut() \ if (hasattr(self._cmap, 'texture_lut')) else None # Position input handling if v.shape[-1] == 2: self.shared_program.vert['to_vec4'] = vec2to4 elif v.shape[-1] == 3: self.shared_program.vert['to_vec4'] = vec3to4 else: raise TypeError("Vertex data must have shape (...,2) or (...,3).") # Set the base color. # # The base color is mixed further by the material filters for texture # or shading effects. self.shared_program.vert['color_transform'] = \ _build_color_transform(colors, self._cmap, self._clim_values) if colors.ndim == 1: self.shared_program.vert['base_color'] = colors else: self.shared_program.vert['base_color'] = VertexBuffer(colors) self._data_changed = False self.events.data_updated() def _prepare_draw(self, view): if self._data_changed: if self._update_data() is False: return False self._data_changed = False def draw(self, *args, **kwds): Visual.draw(self, *args, **kwds) @staticmethod def _prepare_transforms(view): tr = view.transforms.get_transform() view.view_program.vert['transform'] = tr def _compute_bounds(self, axis, view): if self._bounds is None: return None if axis >= len(self._bounds): return (0, 0) else: return self._bounds[axis]