def draw_mesh(coords, edof, dofsPerNode, elType, axes=None, axesAdjust=True, title=None, color=(0, 0, 0), faceColor=(1, 1, 1), filled=False): ''' Draws wire mesh of model in 2D or 3D. Returns the Mesh object that represents the mesh. Parameters: coords - An N-by-2 or N-by-3 array. Row i contains the x,y,z coordinates of node i. edof - An E-by-L array. Element topology. (E is the number of elements and L is the number of dofs per element) dofsPerNode - Integer. Dofs per node. elType - Integer. Element Type. See Gmsh manual for details. Usually 2 for triangles or 3 for quadrangles. axes - Visvis Axes. The Axes where the model will be drawn. If unspecified the current Axes will be used, or a new Axes will be created if none exist. axesAdjust - Boolean. True if the view should be changed to show the whole model. Default True. title - String. Changes title of the figure. Default "Mesh". color - 3-tuple or char. Color of the wire. Defaults to black (0,0,0). Can also be given as a character in 'rgbycmkw'. faceColor - 3-tuple or char. Color of the faces. Defaults to white (1,1,1). Parameter filled must be True or faces will not be drawn at all. filled - Boolean. Faces will be drawn if True. Otherwise only the wire is drawn. Default False. ''' #Prep: axes, verts, faces, verticesPerFace, is3D = _preMeshDrawPrep( axes, coords, edof, dofsPerNode, elType) #Create mesh: m = vv.Mesh(parent=axes, vertices=verts, faces=faces, values=color, verticesPerFace=verticesPerFace) #Settings: fShade = 'plain' if filled else None m.faceShading, m.edgeShading = (fShade, 'plain') m.edgeColor = color m.faceColor = faceColor m.specular = 0 #Adjust axes: if axesAdjust: _adjustaxes(axes, is3D) #Set title and return: vv.title(title, axes) return m
def solidLine(pp, radius=1.0, N=16, axesAdjust=True, axes=None): """ solidLine(pp, radius=1.0, N=16, axesAdjust=True, axes=None) Creates a solid line in 3D space. Parameters ---------- Note that translation, scaling, and direction can also be given using a Point instance. pp : Pointset The sequence of points of which the line consists. radius : scalar or sequence The radius of the line to create. If a sequence if given, it specifies the radius for each point in pp. N : int The number of subdivisions around its centerline. If smaller than 8, flat shading is used instead of smooth shading. axesAdjust : bool If True, this function will call axes.SetLimits(), and set the camera type to 3D. If daspectAuto has not been set yet, it is set to False. axes : Axes instance Display the bars in the given axes, or the current axes if not given. """ # Check first argument if is_Pointset(pp): pass else: raise ValueError('solidLine() needs a Pointset or list of pointsets.') # Obtain mesh and make a visualization mesh baseMesh = lineToMesh(pp, radius, N) ## Visualize # Get axes if axes is None: axes = vv.gca() # Create mesh object m = vv.Mesh(axes, baseMesh) # Adjust axes if axesAdjust: if axes.daspectAuto is None: axes.daspectAuto = False axes.cameraType = '3d' axes.SetLimits() # Return axes.Draw() return m
def draw_nodal_values(nodeVals, coords, edof, dofsPerNode, elType, clim=None, axes=None, axesAdjust=True, doDrawMesh=True, title=None): ''' Draws scalar nodal values in 2D or 3D. Returns the Mesh object that represents the mesh. Parameters: nodeVals - An N-by-1 array or a list of scalars. The Scalar values at the nodes. nodeVals[i] should be the value of node i coords - An N-by-2 or N-by-3 array. Row i contains the x,y,z coordinates of node i. edof - An E-by-L array. Element topology. (E is the number of elements and L is the number of dofs per element) dofsPerNode - Integer. Dofs per node. elType - Integer. Element Type. See Gmsh manual for details. Usually 2 for triangles or 3 for quadrangles. clim - 2-tuple. Colorbar limits (min, max). Defines the value range of the colorbar. Defaults to None, in which case min/max are set to min/max of nodeVals. axes - Visvis Axes. The Axes where the model will be drawn. If unspecified the current Axes will be used, or a new Axes will be created if none exist. axesAdjust - Boolean. True if the view should be changed to show the whole model. Default True. doDrawMesh - Boolean. True if mesh wire should be drawn. Default True. title - String. Changes title of the figure. Default "Node Values". ''' axes, verts, faces, verticesPerFace, is3D = _preMeshDrawPrep(axes, coords, edof, dofsPerNode, elType) m = vv.Mesh(parent=axes, vertices=verts, faces=faces, values=nodeVals, verticesPerFace=verticesPerFace) if clim != None: #Set colorbar limits. m.clim = clim setClim = False else: setClim = True edgeSh = 'plain' if doDrawMesh else None m.faceShading, m.edgeShading = ('smooth', edgeSh)#NOTE: It seems colormap coloring breaks when faceshading='plain'. 'smooth' must be used. m.ambient = 1 m.diffuse = 0 m.specular = 0 #Disable specular. m.SetValues(nodeVals, setClim) #Set the values again, because it doesn't work in the constructor for unknown reasons axes.light0.ambient = 1.0 axes.light0.diffuse = 0.0 #Only ambient light to avoid shadows m.colormap = vv.colormaps['jet'] _makeColorBar("Node values", axes) # Adjust axes: if axesAdjust: _adjustaxes(axes, is3D) vv.title(title, axes) return m
def plot3D(vuvi, coordSys='Cartesian', raised=True, depRange=[-40, 0], ambient=0.9, diffuse=0.4, colormap=vv.CM_JET, faceShading='smooth', edgeColor=(0.5, 0.5, 0.5, 1), edgeShading='smooth', faceColor=(1, 1, 1, 1), shininess=50, specular=0.35, emission=0.45): """ plot3D(vxyz, coordSys=['Cartesian', 'Spherical'], raised = True, depRange=[-40,0], #Note: second range limit not currently used rangeR=[-40,0], ambient = 0.9, diffuse = 0.4, colormap = vv.CM_JET, faceShading='smooth', edgeColor = (0.5,0.5,0.5,1), edgeShading = 'smooth', faceColor = (1,1,1,1), shininess = 50, specular = 0.35, emission = 0.45 )) """ if coordSys == 'Spherical': thetaPhiR = vuvi # data cols are theta, phi, radius vxyz = np.zeros(vuvi.shape) # Now find xyz data points on unit sphere (for meshing) vxyz[:, 0] = np.sin(thetaPhiR[:, 0]) * np.cos(thetaPhiR[:, 1]) vxyz[:, 1] = np.sin(thetaPhiR[:, 0]) * np.sin(thetaPhiR[:, 1]) vxyz[:, 2] = np.cos(thetaPhiR[:, 0]) #normalize and scale dependent values thetaPhiR[thetaPhiR[:, 2] < depRange[0], 2] = depRange[0] depVal = thetaPhiR[:, 2] - np.min(thetaPhiR[:, 2]) else: vxyz = vuvi vxyz[vxyz[:, 2] < depRange[0], 2] = depRange[0] numOfPts = np.shape(vxyz)[0] depVal = vxyz[:, 2] # set to convex surface for meshing # find center of data center = np.average(vxyz, 0) #center data vxyz = vxyz - center # find x-y plane distance to each point radials = np.sqrt(vxyz[:, 0]**2 + vxyz[:, 1]**2) # get max and adjust so that arctan ranges between +-45 deg maxRadial = np.max(radials) / 0.7 #get angle on sphere xi = np.arctan2(radials / maxRadial, 1) #force z axis data to sphere vxyz[:, 2] = maxRadial * np.cos(xi) vxyz = np.append(vxyz, [[0.7, 0.7, -0.7], [-0.7, 0.7, -0.7], [0.7, -0.7, -0.7], [-0.7, -0.7, -0.7]], axis=0) # Send data to convex_hull program qhull dly = Delaunay(vxyz) meshIndx = dly.convex_hull # Check each triangle facet and flip if # vertex order puts back side out for index, (I1, I2, I3) in enumerate(meshIndx): a = vxyz[I1, :] - vxyz[I2, :] b = vxyz[I2, :] - vxyz[I3, :] c = np.cross(a, b) if np.dot(c, vxyz[I2, :]) > 0: meshIndx[index] = (I1, I3, I2) # if 3D surface adjust dependent coordinates if raised: if coordSys == 'Spherical': vxyz[:, 0] = depVal * np.sin(thetaPhiR[:, 0]) * np.cos( thetaPhiR[:, 1]) vxyz[:, 1] = depVal * np.sin(thetaPhiR[:, 0]) * np.sin( thetaPhiR[:, 1]) vxyz[:, 2] = depVal * np.cos(thetaPhiR[:, 0]) else: vxyz = vxyz + center vxyz[:numOfPts, 2] = depVal else: if coordSys == 'Spherical': depRange[0] = 1.0 else: # Since qhull encloses the data with Delaunay triangles there will be # a set of facets which cover the bottom of the data. For flat # contours, the bottom facets need to be separated a fraction from # the top facets else you don't see colormap colors depValRange = np.max(vxyz[:numOfPts, 2]) - np.min(vxyz[:numOfPts, 2]) vxyz[:numOfPts, 2] = vxyz[:numOfPts, 2] / (10 * depValRange) #normalize depVal for color mapping dataRange = np.max(depVal) - np.min(depVal) depVal = (depVal - np.min(depVal)) / dataRange # Get axes ax = vv.gca() ms = vv.Mesh(ax, vxyz, faces=meshIndx, normals=vxyz) ms.SetValues(np.reshape(depVal, np.size(depVal))) ms.ambient = ambient ms.diffuse = diffuse ms.colormap = colormap ms.faceShading = faceShading ms.edgeColor = edgeColor ms.edgeShading = edgeShading ms.faceColor = faceColor ms.shininess = shininess ms.specular = specular ms.emission = emission ax.SetLimits(rangeX=[-depRange[0], depRange[0]], rangeY=[-depRange[0], depRange[0]], rangeZ=[-depRange[0], depRange[0]])
def mesh(vertices, faces=None, normals=None, values=None, verticesPerFace=3, colormap=None, clim=None, texture=None, axesAdjust=True, axes=None): """ mesh(vertices, faces=None, normals=None, values=None, verticesPerFace=3, colormap=None, clim=None, texture=None, axesAdjust=True, axes=None) Display a mesh of polygons, either triangles or quads. Parameters ---------- vertices : Nx3 array The positions of the vertices in 3D space. faces : array or list of indices The faces given in terms of the vertex indices. Should be 1D, in which case the indices are grouped into groups of verticesPerFace, or Mx3 or Mx4, in which case verticesPerFace is ignored. The front of the face is defined using the right-hand-rule. normals : Nx3 A list of vectors specifying the vertex normals. values : N, Nx2, Nx3, or Nx4 array Sets the color of each vertex, using values from a colormap (1D), colors from a texture (Nx2), RGB values (Nx3), or RGBA value (Nx4). verticesPerFace : 3 or 4 Whether the faces are triangle or quads, if not specified in faces. colormap : a Colormap If values is 1D, the vertex colors are set from this colormap. clim : 2 element array If values is 1D, sets the values to be mapped to the limits of the colormap. If None, the min and max of values are used. texture : a Texture If values is Nx2, the vertex colors are set from this texture. axesAdjust : bool Whether to adjust the view after the mesh is drawn. axes : Axes instance The axes into which the mesh will be added. If None, the current axes will be used. """ if axes is None: axes = vv.gca() # Accept basemesh instances if isinstance(vertices, vv.BaseMesh): other = vertices vertices = other._vertices faces = other._faces normals = other._normals values = other._values verticesPerFace = other._verticesPerFace # Check that vertices is (converted to) a Nx3 array; otherwise user # will see odd behavior from Mesh if not isinstance(vertices, vv.BaseMesh): try: vertices = checkDimsOfArray(vertices, 3) except ValueError: raise ValueError( "Vertices should represent an array of 3D vertices.") # Set the method for coloring if values is not None: try: values = checkDimsOfArray(values, 0, 1, 2, 3, 4) # Returned values is always a 2D numpy array except ValueError: raise ValueError('values must be 1D, Nx2, Nx3, or Nx4 array.') if values.shape[0] != vertices.shape[0]: raise ValueError( 'First dimension of values must be same length as vertices.') # Instantiate Mesh m = vv.Mesh(axes, vertices, faces, normals, values, verticesPerFace) # Set colormap or texture if values is not None and values.shape[1] == 1: if colormap is not None: m.colormap = colormap if clim is not None and len(clim) == 2: m.clim = clim else: m.clim = values.min(), values.max() elif texture is not None and values is not None and values.shape[1] == 2: m.SetTexture(texture) # Adjust axes if axesAdjust: if axes.daspectAuto is None: axes.daspectAuto = False axes.cameraType = '3d' axes.SetLimits() # Return axes.Draw() return m
def surf(*args, **kwargs): """ surf(..., axesAdjust=True, axes=None) Shaded surface plot. Usage ----- * surf(Z) - create a surface using the given image with z coordinates. * surf(Z, C) - also supply a texture image to map. * surf(X, Y, Z) - give x, y and z coordinates. * surf(X, Y, Z, C) - also supply a texture image to map. Parameters ---------- Z : A MxN 2D array X : A length N 1D array, or a MxN 2D array Y : A length M 1D array, or a MxN 2D array C : A MxN 2D array, or a AxBx3 3D array If 2D, C specifies a colormap index for each vertex of Z. If 3D, C gives a RGB image to be mapped over Z. In this case, the sizes of C and Z need not match. Keyword arguments ----------------- axesAdjust : bool If axesAdjust==True, this function will call axes.SetLimits(), and set the camera type to 3D. If daspectAuto has not been set yet, it is set to False. axes : Axes instance Display the image in this axes, or the current axes if not given. Also see grid() """ def checkZ(z): if z.ndim != 2: raise ValueError('Z must be a 2D array.') # Parse input if len(args) == 1: z = np.asanyarray(args[0]) checkZ(z) y = np.arange(z.shape[0]) x = np.arange(z.shape[1]) c = None elif len(args) == 2: z, c = map(np.asanyarray, args) checkZ(z) y = np.arange(z.shape[0]) x = np.arange(z.shape[1]) elif len(args) == 3: x, y, z = map(np.asanyarray, args) checkZ(z) c = None elif len(args) == 4: x, y, z, c = map(np.asanyarray, args) checkZ(z) else: raise ValueError( 'Invalid number of arguments. Must pass 1-4 arguments.') # Parse kwargs axes = None if 'axes' in kwargs: axes = kwargs['axes'] axesAdjust = True if 'axesAdjust' in kwargs: axesAdjust = kwargs['axesAdjust'] # Set y vertices if y.shape == (z.shape[0], ): y = y.reshape(z.shape[0], 1).repeat(z.shape[1], axis=1) elif y.shape != z.shape: raise ValueError( 'Y must have same shape as Z, or be 1D with length of rows of Z.') # Set x vertices if x.shape == (z.shape[1], ): x = x.reshape(1, z.shape[1]).repeat(z.shape[0], axis=0) elif x.shape != z.shape: raise ValueError( 'X must have same shape as Z, or be 1D with length of columns of Z.' ) # Set vertices vertices = np.column_stack((x.ravel(), y.ravel(), z.ravel())) # Create texcoords if c is None or c.shape == z.shape: # No texture -> colormap on the z value # Grayscale texture -> color mapping texcoords = (c if c is not None else z).ravel() elif c.ndim == 3: # color texture -> use texture mapping U, V = np.meshgrid(np.linspace(0, 1, z.shape[1]), np.linspace(0, 1, z.shape[0])) texcoords = np.column_stack((U.ravel(), V.ravel())) else: raise ValueError('C must have same shape as Z, or be 3D array.') # Create faces w = z.shape[1] i = np.arange(z.shape[0] - 1) faces = np.row_stack( np.column_stack((j + w * i, j + 1 + w * i, j + 1 + w * (i + 1), j + w * (i + 1))) for j in range(w - 1)) ## Visualize # Get axes if axes is None: axes = vv.gca() # Create mesh m = vv.Mesh(axes, vertices, faces, values=texcoords, verticesPerFace=4) # Should we apply a texture? if c is not None and c.ndim == 3: m.SetTexture(c) else: m.clim = m.clim # trigger correct limits # Adjust axes if axesAdjust: if axes.daspectAuto is None: axes.daspectAuto = False axes.cameraType = '3d' axes.SetLimits() # Return axes.Draw() return m
vesselType=1, climEditor=True, removeStent=removeStent, meshColor=meshColor) axes1 = axes1[0] axes1.position = 0, 0, 0.6, 1 # Show or hide the volume (showing is nice, but also slows things down) tex3d = axes1.wobjects[1] tex3d.visible = False # VesselMeshes vesselVisMesh1 = axes1.wobjects[4] vesselVisMesh1.cullFaces = "front" # Show the back # vesselVisMesh2 = vv.Mesh(axes1, *vesselMesh.get_vertices_and_faces()) vesselVisMesh2 = vv.Mesh(axes1, np.zeros((6, 3), np.float32), np.zeros((3, 3), np.int32)) vesselVisMesh2.cullFaces = "back" vesselVisMesh2.faceColor = "red" # Show the centerline vv.plot(centerline, ms='.', ls='', mw=8, mc='b', alpha=0.5) # Initialize 2D view axes2 = vv.Axes(vv.gcf()) axes2.position = 0.65, 0.05, 0.3, 0.4 axes2.daspectAuto = False axes2.camera = '2d' axes2.axis.showGrid = True axes2.axis.axisColor = 'k' # Initialize axes to put widgets and labels in
# Create deformable mesh dm = DeformableMesh(a, modelmesh) dm.SetDeforms(*[list(reversed(deform)) for deform in deforms) dm.clim = 0, 5 dm.colormap = vv.CM_JET vv.colorbar() # Instantiate measure ring mr = MeasuringRing(modelmesh._vertices, , ) ## Old # Load data patnr = 1 dataDir = 'c:/almar/data/stentMotionData' s = vv.ssdf.load(dataDir + '/motionMesh_pat%02i.bsdf' % patnr) # Prepare axes a = vv.gca() a.daspectAuto = False a.daspect = 1, -1, -1 a.bgcolors = (0.2, 0.4, 0.6), 'k' # Create mesg object m = vv.Mesh(a, s.vertices, s.faces, s.values) m.colormap = (0.1,1,0.1), (0.1,0.8,0.3), (0.8,0.3,0.1) a.SetLimits() # Instantiate measure ring mr = MeasuringRing(m._vertices, s.verticesDeltas, s.valuesList)