def stem_residue_orientation(self, p, next_p, pair_p): from chimerax.geometry import cross_product, orthonormal_frame from numpy import array x, y = next_p - p, array(pair_p) - p z = cross_product(x, y) tf = orthonormal_frame(z, xdir=x, origin=p) return tf
def scene_position_2d(self, hand_pose, view): # Adjust origin cpos = hand_pose.origin() - self._center # Scale millimeters to scene units cpos /= self._width # millimeters to unit width # Rotate to screen orientation from chimerax.geometry import cross_product, orthonormal_frame yaxis = self._facing zaxis = cross_product(yaxis, self._cord) cpos = orthonormal_frame(zaxis, ydir=yaxis) * cpos # Convert to window pixels w, h = view.window_size win_xy = (w / 2 + w * cpos[0], h / 2 - h * cpos[1]) # Map to scene near front clip plane. xyz_min, xyz_max = view.clip_plane_points(win_xy[0], win_xy[1]) scene_point = (0, 0, 0) if xyz_min is None else (.9 * xyz_min + .1 * xyz_max) # Convert camera coordinates to scene coordinates rot = view.camera.position.zero_translation() from chimerax.geometry import translation scene_pos = translation(scene_point) * rot return scene_pos, win_xy
def scene_position_6d(self, hand_pose, view): from chimerax.geometry import translation, cross_product from chimerax.geometry import orthonormal_frame, inner_product # Adjust origin cpos = translation(-self._center) * hand_pose # Scale millimeters to scene units scene_center = view.center_of_rotation cam = view.camera factor = cam.view_width(scene_center) / self._width cpos = cpos.scale_translation(factor) # millimeters to scene units # Rotate to screen orientation yaxis = self._facing zaxis = cross_product(yaxis, self._cord) cpos = orthonormal_frame(zaxis, ydir=yaxis) * cpos # Adjust depth origin to center of rotation. cam_pos = cam.position depth = inner_product(scene_center - cam_pos.origin(), -cam_pos.z_axis()) cpos = translation( (0, 0, -depth)) * cpos # Center in front of camera (-z axis). # Convert camera coordinates to scene coordinates scene_pos = cam_pos * cpos # Map from camera to scene coordinates return scene_pos
def interface_frame(self, facing_group): r1, r2 = [self.contact_residues(g) for g in (self.group1, self.group2)] xyz1, xyz2 = [r.atoms.scene_coords.mean(axis = 0) for r in (r1,r2)] zaxis = (xyz2 - xyz1) if facing_group is self.group1 else (xyz1 - xyz2) center = 0.5 * (xyz1 + xyz2) from chimerax.geometry import orthonormal_frame f = orthonormal_frame(zaxis, origin = center) return f
def polar_angle(zaxis, v1, v2): from chimerax.geometry import orthonormal_frame f = orthonormal_frame(zaxis, xdir=v1) x, y, z = f.transpose() * v2 a = atan2(y, x) if a < 0: a += 2 * pi return a
def layout_projection(self): c = self.contact r1, r2 = (self.residues1, self.residues2) xyz1, xyz2 = [r.atoms.scene_coords.mean(axis=0) for r in (r1, r2)] zaxis = xyz2 - xyz1 center = 0.5 * (xyz1 + xyz2) from chimerax.geometry import orthonormal_frame f = orthonormal_frame(zaxis, origin=center) finv = f.inverse() return finv
def _axis_square(axis, center, width_axis, length, width, thickness): l2 = 0.5 * length t2 = 0.5 * thickness box = [(0, -t2, -l2), (width, -t2, -l2), (width, t2, -l2), (0, t2, -l2), (0, -t2, l2), (width, -t2, l2), (width, t2, l2), (0, t2, l2)] from chimerax.geometry import orthonormal_frame f = orthonormal_frame(axis, xdir=width_axis, origin=center) corners = f * box va, na, ta = _box_geometry(corners) return va, na, ta
def surface_projection_coordinates(surfaces, projection_axis, volume): g = volume.data # Scale rotated surface coordinates to grid index units. axis_aligned = (tuple(projection_axis) in ((1, 0, 0), (0, 1, 0), (0, 0, 1)) and tuple(g.cell_angles) == (90, 90, 90) and g.rotation == ((1, 0, 0), (0, 1, 0), (0, 0, 1))) if axis_aligned: grid_spacing = g.step else: s = min(g.plane_spacings()) grid_spacing = (s, s, s) # Determine transform from vertex coordinates to depth array indices # Rotate projection axis to z. from chimerax.geometry import orthonormal_frame, scale, translation tfrs = orthonormal_frame(projection_axis).inverse() * scale( [1 / s for s in grid_spacing]) # Transform vertices to depth array coordinates. zsurf = [] tcount = 0 for vertices, triangles in surfaces: varray = tfrs.transform_points(vertices) zsurf.append((varray, triangles)) tcount += len(triangles) if tcount == 0: return None # Compute origin for depth grid vmin, vmax = bounding_box(zsurf) if axis_aligned: o = tfrs * g.origin offset = [(vmin[a] - o[a]) for a in (0, 1, 2)] from math import floor align_frac = [offset[a] - floor(offset[a]) for a in (0, 1, 2)] vmin -= align_frac else: vmin -= 0.5 tf = translation(-vmin) * tfrs # Shift surface vertices by depth grid origin for varray, triangles in zsurf: varray -= vmin # Compute size of depth grid from math import ceil size = tuple(int(ceil(vmax[a] - vmin[a] + 1)) for a in (0, 1)) return zsurf, size, tf
def box_path(points, width, twist=0): from numpy import dot, concatenate, array # Find normal to bisecting plane through each point. n = len(points) p = array(points) from chimerax.geometry import normalize_vector as nv tangents = array([ nv( array(nv(p[min(i + 1, n - 1)] - p[i])) + array(nv(p[i] - p[max(i - 1, 0)]))) for i in range(n) ]) # Trace edge of square cross-section from start to finish. edges = [] y, z = p[2] - p[0], tangents[0] from chimerax.geometry import rotation, orthonormal_frame if twist != 0: y = rotation(z, twist) * y f = orthonormal_frame(z, y) xa, ya = f.axes()[:2] corners = ((1, 1), (-1, 1), (-1, -1), (1, -1)) for x, y in corners: ep = [points[0] + (x * 0.5 * width) * xa + (y * 0.5 * width) * ya] for i in range(n - 1): e0, p0, p1, t = ep[i], p[i], p[i + 1], tangents[i + 1] ep.append(e0 + (dot(p1 - e0, t) / dot(p1 - p0, t)) * (p1 - p0)) edges.append(ep) # Calculate triangles for each face of a surface model. # Make sharp edges. va = concatenate(edges + edges + edges + edges) ta = [] nc = len(corners) for s in range(n - 1): for c in range(nc): c1 = (c + 1) % nc + nc t = s + (s % 2) * 2 * nc * n ta.append((c * n + t, c1 * n + 1 + t, c * n + 1 + t)) ta.append((c * n + t, c1 * n + t, c1 * n + 1 + t)) # Add end caps. ta.extend([(nc * n + 0, nc * n + (2 + c) * n, nc * n + (1 + c) * n) for c in range(nc - 2)]) ta.extend([(n - 1, (1 + c) * n + n - 1, (2 + c) * n + n - 1) for c in range(nc - 2)]) ta = array(ta) return va, ta
def draw_circles(circles, sphere, s, offset, width, color=(0, .2, .9, 1)): cs, r = sphere from chimerax.geometry import orthonormal_frame for c in circles: f = orthonormal_frame(c.center) va, ta = sphere_band_geometry(c.angle, width=width) na = va.copy() va *= r + offset f.transform_points(va, in_place=True) f.transform_vectors(na, in_place=True) va += cs p = s.new_drawing('circles') p.set_geometry(va, na, ta) p.color = color
def draw_arc(circle, p1, p2, sphere, surf, color, width, offset): arc = polar_angle(circle.center, p1, p2) va, ta = sphere_band_arc(circle.angle, arc, width) from chimerax.geometry import orthonormal_frame f = orthonormal_frame(circle.center, xdir=p1) f.transform_points(va, in_place=True) na = va.copy() c, r = sphere va *= r + offset va += c p = surf.new_drawing('arcs') p.set_geometry(va, na, ta) p.color = color
def rna_nucleotide_templates(session, file='rna_templates_6pj6.cif', chain_id='I', residue_numbers={ 'A': 2097, 'C': 2096, 'G': 2193, 'U': 2192 }): ''' Return residues A,G,C,U with P at (0,0,0) and next residue P at (x,0,0) with x>0 and rotated so that a basepaired residue P is in the xy-plane with y > 0. These are used for building an atomic model from a P-atom backbone trace. ''' # Read template residues from mmCIF file from os.path import join, dirname path = join(dirname(__file__), file) from chimerax.mmcif import open_mmcif mols, msg = open_mmcif(session, path) m = mols[0] # Calculate transforms to standard coordinates. res_tf = [] pair_name = {'A': 'U', 'U': 'A', 'G': 'C', 'C': 'G'} from chimerax.geometry import cross_product, orthonormal_frame for resname in ('A', 'C', 'G', 'U'): r = m.find_residue(chain_id, residue_numbers[resname]) rnext = m.find_residue(chain_id, residue_numbers[resname] + 1) rpair = m.find_residue(chain_id, residue_numbers[pair_name[resname]]) a0, a1, a2 = r.find_atom('P'), rnext.find_atom('P'), rpair.find_atom( 'P') o, x, y = a0.coord, a1.coord, a2.coord z = cross_product(x - o, y - o) tf = orthonormal_frame(z, xdir=x - o, origin=o).inverse() res_tf.append((resname, r, tf)) # Transform template residues to standard coordinate frame. res = {} for name, r, tf in res_tf: ratoms = r.atoms ratoms.coords = tf * ratoms.coords res[name] = r res['T'] = res['U'] return res
def annulus_grid(radius0, radius1, center, axis, ncircum, nradius): from math import pi, cos, sin from numpy import empty, float32, multiply grid_points = empty((ncircum, nradius, 3), float32) for i in range(ncircum): a = -pi + 2 * pi * float(i) / ncircum grid_points[i, 0, :] = (cos(a), sin(a), 0) for i in range(nradius): grid_points[:, i, :] = grid_points[:, 0, :] for i in range(nradius): f = float(i) / (nradius - 1) r = radius0 + f * (radius1 - radius0) multiply(grid_points[:, i, :], r, grid_points[:, i, :]) from chimerax.geometry import translation, orthonormal_frame tf = translation(center) * orthonormal_frame(axis) tf.transform_points(grid_points.reshape((ncircum * nradius, 3)), in_place=True) return grid_points
def unroll_operation(v, r0, r1, h, center, axis, gsp, subregion, step, modelId): from math import ceil, pi zsize = int(max(1, ceil(h / gsp))) # cylinder height xsize = int(max(1, ceil((r1 - r0) / gsp))) # slab thickness rmid = 0.5 * (r0 + r1) circum = rmid * 2 * pi ysize = int(max(1, ceil(circum / gsp))) # circumference from chimerax.geometry import normalize_vector axis = normalize_vector(axis) agrid_points = annulus_grid(r0, r1, center, axis, ysize, xsize) grid_points = agrid_points.reshape((ysize * xsize, 3)) grid_points[:] += tuple([-0.5 * h * ai for ai in axis]) # Shift annulus. from numpy import empty values = empty((zsize, ysize, xsize), v.data.value_type) axis_step = tuple([h * float(ai) / (zsize - 1) for ai in axis]) for i in range(zsize): vval = v.interpolated_values(grid_points, subregion=subregion, step=step) values[i, :, :] = vval.reshape((ysize, xsize)) grid_points[:] += axis_step # Shift annulus. from chimerax.map_data import ArrayGridData gstep = (float(r1 - r0) / (xsize - 1), circum / (ysize - 1), float(h) / (zsize - 1)) gorigin = (center[0] + r0, center[1] - 0.5 * circum, center[2] - 0.5 * h) g = ArrayGridData(values, gorigin, gstep, name='unrolled %s' % v.name) from chimerax.map import volume_from_grid_data vu = volume_from_grid_data(g, v.session, model_id=modelId) vu.copy_settings_from(v, copy_region=False, copy_active=False, copy_colors=False) if axis[0] != 0 or axis[1] != 0: # Rotate so unrolled volume is tangential to cylinder from chimerax.geometry import orthonormal_frame vu.position = v.position * orthonormal_frame(axis) return vu
def path_point_axes(points, yaxis): zaxes = path_tangents(points) from chimerax.geometry import orthonormal_frame axes = [orthonormal_frame(za, ydir=yaxis) for za in zaxes] return axes
def _hand_pose(self, palm_position, palm_normal, finger_direction): from chimerax.geometry import orthonormal_frame hp = orthonormal_frame(finger_direction, ydir=-palm_normal, origin=palm_position) return hp
def random_rotation(): y, z = random_direction(), random_direction() from chimerax.geometry import orthonormal_frame f = orthonormal_frame(z, y) return f