def triangle_normals(vlist): nt = len(vlist)//3 from numpy import array, int32 ta = array(range(3*nt), int32).reshape((nt,3)) from chimerax.surface import calculate_vertex_normals na = calculate_vertex_normals(vlist, ta) return na
def spherical_surface( session, radius_function, move=None, # a Place instance to rotate and translate surface theta_steps=100, phi_steps=50, positive_color=(255, 100, 100, 255), # red, green, blue, alpha, 0-255 negative_color=(100, 100, 255, 255)): # Compute vertices and vertex colors vertices = [] colors = [] for t in range(theta_steps): theta = (t / theta_steps) * 2 * pi ct, st = cos(theta), sin(theta) for p in range(phi_steps): phi = (p / (phi_steps - 1)) * pi cp, sp = cos(phi), sin(phi) r = radius_function(theta, phi) xyz = (r * sp * ct, r * sp * st, r * cp) vertices.append(xyz) color = positive_color if r >= 0 else negative_color colors.append(color) # Compute triangles, triples of vertex indices triangles = [] for t in range(theta_steps): for p in range(phi_steps - 1): i = t * phi_steps + p t1 = (t + 1) % theta_steps i1 = t1 * phi_steps + p triangles.append((i, i + 1, i1 + 1)) triangles.append((i, i1 + 1, i1)) # Create numpy arrays from numpy import array, float32, uint8, int32 va = array(vertices, float32) ca = array(colors, uint8) ta = array(triangles, int32) # Rotate and translate vertices to a new location. if move is not None: move.transform_points(va, in_place=True) # Compute average vertex normal vectors from chimerax.surface import calculate_vertex_normals na = calculate_vertex_normals(va, ta) # Create ChimeraX surface model from chimerax.core.models import Surface s = Surface('surface', session) s.set_geometry(va, na, ta) s.vertex_colors = ca session.models.add([s]) return s
def _update_geometry(self): from chimerax.shape.shape import cylinder_geometry varray, tarray = cylinder_geometry( self.radius, self.thickness, max(2, int(self.thickness / 3 + 0.5)), max(40, int(20.0 * self.radius + 0.5)), True) from chimerax.geometry import translation, vector_rotation varray = (translation(self.plane.origin) * vector_rotation( (0, 0, 1), self.plane.normal)).transform_points(varray) from chimerax.surface import calculate_vertex_normals narray = calculate_vertex_normals(varray, tarray) self.set_geometry(varray, narray, tarray)
def triangles_model(session, points, triangles, name='vtk polygons', color=(180, 180, 180, 255)): from chimerax.core.models import Surface m = Surface(name, session) from chimerax import surface normals = surface.calculate_vertex_normals(points, triangles) m.set_geometry(points, normals, triangles) m.color = color return m
def slab_surface(va, ta, na, pad, sharp_edges=False): nv = len(va) nt = len(ta) from chimerax.surface import boundary_edges edges = boundary_edges(ta) ne = len(edges) if sharp_edges: nv2 = 4 * nv nt2 = 2 * nt + 6 * ne else: nv2 = 2 * nv nt2 = 2 * nt + 2 * ne from numpy import zeros varray = zeros((nv2, 3), va.dtype) narray = zeros((nv2, 3), na.dtype) tarray = zeros((nt2, 3), ta.dtype) # Two copies of vertices offset along normals by padding values. varray[:nv, :] = va + pad[1] * na varray[nv:2 * nv, :] = va + pad[0] * na narray[:nv, :] = na narray[nv:2 * nv, :] = -na if sharp_edges: # TODO: Copy just edge vertices instead of all vertices when making # sharp edges. e = edges[:, 0] varray[2 * nv:3 * nv, :] = varray[:nv, :] varray[3 * nv:, :] = varray[nv:2 * nv, :] tarray[:nt, :] = ta # Reverse triangle orientation for inner face. tarray[nt:2 * nt, 0] = ta[:, 0] + len(va) tarray[nt:2 * nt, 1] = ta[:, 2] + len(va) tarray[nt:2 * nt, 2] = ta[:, 1] + len(va) # Stitch faces with band of triangles, two per boundary edge. if sharp_edges: band_triangles(tarray[2 * nt:, :], edges, 0, 2 * nv) band_triangles(tarray[2 * nt + 2 * ne:, :], edges, 2 * nv, 3 * nv) band_triangles(tarray[2 * nt + 4 * ne:, :], edges, 3 * nv, nv) # Set band normals. tband = tarray[2 * nt + 2 * ne:2 * nt + 4 * ne, :] from chimerax.surface import calculate_vertex_normals narray[2 * nv:, :] = calculate_vertex_normals(varray, tband)[2 * nv:, :] else: band_triangles(tarray[2 * nt:, :], edges, 0, nv) return varray, narray, tarray
def new_object(session, object_name, vertices, normals, texcoords, faces, voffset): if _need_vertex_split(faces): # Texture coordinates or normals do not match vertices order. # Need to make additional vertices if a vertex has different texture # coordinates or normals in different faces. vertices, normals, texcoords, triangles = _split_vertices( vertices, normals, texcoords, faces) else: triangles = faces if len(vertices) == 0: raise OBJError('OBJ file has no vertices') if len(normals) > 0 and len(normals) != len(vertices): raise OBJError( 'OBJ file has different number of normals (%d) and vertices (%d)' % (len(normals), len(vertices))) if len(texcoords) > 0 and len(texcoords) != len(vertices): raise OBJError( 'OBJ file has different number of texture coordinates (%d) and vertices (%d)' % (len(texcoords), len(vertices))) from chimerax.core.models import Surface # model = Surface(object_name, session) # model.SESSION_SAVE_DRAWING = True # model.clip_cap = True model = WavefrontOBJ(object_name, session) from numpy import array, float32, int32, uint8 if texcoords: model.texture_coordinates = array(texcoords, float32) ta = array(triangles, int32) if voffset > 0: ta -= voffset ta -= 1 # OBJ first vertex index is 1 while model first vertex index is 0 va = array(vertices, float32) if normals: na = array(normals, float32) else: # na = None from chimerax.surface import calculate_vertex_normals na = calculate_vertex_normals(va, ta) model.set_geometry(va, na, ta) model.color = array((170, 170, 170, 255), uint8) return model
def meshes_as_models(session, meshes, buf_arrays): mesh_models = [] ba = buf_arrays from numpy import int32 from chimerax.core.models import Surface for m in meshes: if 'primitives' not in m: raise glTFError('glTF mesh has no "primitives": %s' % str(j)) pdlist = [] for pi, p in enumerate(m['primitives']): if 'mode' in p and p['mode'] != GLTF_TRIANGLES: raise glTFError( 'glTF reader only handles triangles, got mode %d' % p['mode']) if 'indices' not in p: raise glTFError('glTF missing "indices" in primitive %s' % str(p)) ta = ba[p['indices']] if len(ta.shape) == 1: ta = ta.reshape((len(ta) // 3, 3)) ta = ta.astype(int32, copy=False) if 'attributes' not in p: raise glTFError('glTF missing "attributes" in primitive %s' % str(p)) pa = p['attributes'] if 'POSITION' not in pa: raise glTFError( 'glTF missing "POSITION" attribute in primitive %s' % str(p)) va = ba[pa['POSITION']] if 'NORMAL' in pa: na = ba[pa['NORMAL']] else: from chimerax import surface na = surface.calculate_vertex_normals(va, ta) if 'COLOR_0' in pa: vc = ba[pa['COLOR_0']] else: vc = None pd = Surface('p%d' % pi, session) set_geometry(pd, va, na, vc, ta) pdlist.append(pd) mesh_models.append(pdlist) return mesh_models
def create_mesh(session, c, transform, rgba, name): varray, tarray = mesh_geometry(c) if len(tarray) == 0: return None transform.transform_points(varray, in_place=True) from chimerax.core.models import Surface s = Surface(name, session) s.SESSION_SAVE_DRAWING = True s.clip_cap = True # Cap surface when clipped from chimerax.surface import calculate_vertex_normals narray = calculate_vertex_normals(varray, tarray) s.set_geometry(varray, narray, tarray) rgba8 = [int(r * 255) for r in rgba] s.color = rgba8 return s
def load_surface(session, tensor_file, sc=2.09, theta_steps=100, phi_steps=50, positive_color=(255, 100, 100, 255), negative_color=(100, 100, 255, 255), marker_pos_color=(100, 255, 100, 255), marker_neg_color=(255, 255, 100, 255)): Delta, Eta, Euler, Pos, Marker = load_tensor(tensor_file) from chimerax.core.models import Surface from chimerax.surface import calculate_vertex_normals, combine_geometry_vntc geom = list() for k, (delta, eta, euler, pos, marker) in enumerate(zip(Delta, Eta, Euler, Pos, Marker)): if marker == 1: pc = marker_pos_color nc = marker_neg_color else: pc = positive_color nc = negative_color xyz,tri,colors=spherical_surface(\ delta=delta,eta=eta,euler=euler,pos=pos,\ sc=sc,theta_steps=theta_steps,\ phi_steps=phi_steps,\ positive_color=pc,\ negative_color=nc) norm_vecs = calculate_vertex_normals(xyz, tri) geom.append((xyz, norm_vecs, tri, colors)) xyz, norm_vecs, tri, colors = combine_geometry_vntc(geom) s = Surface('surface', session) s.set_geometry(xyz, norm_vecs, tri) s.vertex_colors = colors session.models.add([s]) return s
def _show_surface(session, varray, tarray, color, mesh, center, rotation, qrotation, coordinate_system, slab, model_id, shape_name, edge_mask = None, sharp_slab = False): if center is not None or rotation is not None or qrotation is not None: from chimerax.geometry import Place, translation tf = Place() if rotation is not None: tf = rotation * tf if qrotation is not None: tf = qrotation * tf if center is not None: from chimerax.core.commands import Center if isinstance(center, Center): center = center.scene_coordinates() tf = translation(center) * tf varray = tf.transform_points(varray) from chimerax.surface import calculate_vertex_normals narray = calculate_vertex_normals(varray, tarray) if slab is not None: from chimerax.mask.depthmask import slab_surface varray, narray, tarray = slab_surface(varray, tarray, narray, slab, sharp_edges = sharp_slab) s = _surface_model(session, model_id, shape_name, coordinate_system) s.set_geometry(varray, narray, tarray) if color is not None: s.color = color if mesh: s.display_style = s.Mesh if edge_mask is not None: s.edge_mask = edge_mask # Hide spokes of hexagons. _add_surface(s) return s
def calculate_segmentation_surfaces(seg, where=None, each=None, region='all', step=None, color=None): # Warn if number of surfaces is large. if where is None and each is None: max_seg_id = _maximum_segment_id(seg) if max_seg_id > 100: from chimerax.core.errors import UserError raise UserError( 'Segmentation %s (#%s) has %d segments (> 100).' ' To create surface for each segment use "each segment" option.' % (seg.name, seg.id_string, max_seg_id)) # Compute surfaces conditions = (where if where else []) + ([each] if each else []) group, attribute_name = _which_segments(seg, conditions) matrix = seg.matrix(step=step, subregion=region) from . import segmentation_surfaces surfs = segmentation_surfaces(matrix, group) # Transform vertices from index to scene units and compute normals. geom = [] tf = seg.matrix_indices_to_xyz_transform(step=step, subregion=region) for region_id, va, ta in surfs: tf.transform_points(va, in_place=True) from chimerax.surface import calculate_vertex_normals na = calculate_vertex_normals(va, ta) geom.append((region_id, va, na, ta)) # Determine surface coloring. if color is None: attr = None if attribute_name == 'segment' else attribute_name colors = _attribute_colors(seg, attr).attribute_rgba # Create one or more surface models from chimerax.core.models import Surface from chimerax.surface import combine_geometry_xvnt segsurfs = [] if each is None and len(geom) > 1: # Combine multiple surfaces into one. va, na, ta = combine_geometry_xvnt(geom) name = '%s %d %ss' % (seg.name, len(geom), attribute_name) s = Surface(name, seg.session) s.clip_cap = True # Cap surface when clipped s.set_geometry(va, na, ta) if color is None: color_counts = [(colors[region_id], len(sva)) for region_id, sva, sna, sta in geom] s.vertex_colors = _vertex_colors(len(va), color_counts) else: s.color = color segsurfs.append(s) else: # Create multiple surface models for region_id, va, na, ta in geom: name = '%s %s %d' % (seg.name, attribute_name, region_id) s = Surface(name, seg.session) s.clip_cap = True # Cap surface when clipped s.set_geometry(va, na, ta) s.color = colors[region_id] if color is None else color segsurfs.append(s) return segsurfs