def lattitude_longtitude_circles(n=10): cvertices, cedges = unit_circle() vertices = [] edges = [] # Make lattitude circles from math import pi, sin, cos for i in range(n): a = pi * (i + 1) / (n + 1) v, e = cvertices.copy(), cedges.copy() v *= sin(a) v[:, 2] += cos(a) e += len(vertices) * len(v) vertices.append(v) edges.append(e) # Make longitude circles from chimerax.geometry import vector_rotation for i in range(n): a = pi * i / n v, e = cvertices.copy(), cedges.copy() normal = (cos(a), sin(a), 0) vector_rotation((0, 0, 1), normal).transform_points(v, in_place=True) e += len(vertices) * len(v) vertices.append(v) edges.append(e) from numpy import concatenate return concatenate(vertices), concatenate(edges)
def _line_orientation(from_point, to_point, axis, height): if from_point is None and to_point is None and axis is None: return None c,h,r = None, height, None from chimerax.core.commands import Axis, Center if isinstance(axis, Axis): axis = axis.scene_coordinates() if isinstance(from_point, Center): from_point = from_point.scene_coordinates() if isinstance(to_point, Center): to_point = to_point.scene_coordinates() from chimerax.geometry import vector_rotation, norm if axis is not None: r = vector_rotation((0,0,1), axis) else: from numpy import array, float32 axis = array((0,0,1), float32) if from_point is not None and to_point is not None: c = 0.5 * (from_point + to_point) v = to_point - from_point r = vector_rotation((0,0,1), v) h = norm(v) elif from_point is not None and to_point is None: c = from_point + 0.5*height*axis elif from_point is None and to_point is not None: c = to_point - 0.5*height*axis return h, c, r
def extrusion_transforms(path, tangents, yaxis=None): from chimerax.geometry import identity, vector_rotation, translation tflist = [] if yaxis is None: # Make xy planes for coordinate frames at each path point not rotate # from one point to next. tf = identity() n0 = (0, 0, 1) for p1, n1 in zip(path, tangents): tf = vector_rotation(n0, n1) * tf tflist.append(translation(p1) * tf) n0 = n1 else: # Make y-axis of coordinate frames at each point align with yaxis. from chimerax.geometry import normalize_vector, cross_product, Place for p, t in zip(path, tangents): za = t xa = normalize_vector(cross_product(yaxis, za)) ya = cross_product(za, xa) tf = Place( ((xa[0], ya[0], za[0], p[0]), (xa[1], ya[1], za[1], p[1]), (xa[2], ya[2], za[2], p[2]))) tflist.append(tf) return tflist
def sphere_geometry(self, points, sphere_radius, disc_radius, num_disc_points): 'Place a disc tangent to a unit sphere centered at each point' # Disc geometry from math import sin, cos, pi from numpy import array, float32, int32, concatenate r = disc_radius n = num_disc_points cp = [(r*cos(a*2*pi/n), r*sin(a*2*pi/n), sphere_radius) for a in range(n)] dv = array([(0,0,sphere_radius)] + cp, float32) dn = array([(0,0,1)]*(n+1), float32) dt = array([(0,1+i,1+(i+1)%n) for i in range(n)], int32) # Discs for each sphere point vs = [] ns = [] ts = [] from chimerax.geometry import vector_rotation, normalize_vector for i in range(len(points)): p = points[i] rv = vector_rotation((0,0,1), p) vs.append(rv * dv) ns.append(rv * dn) ts.append(dt + i*(n+1)) va, na, ta = concatenate(vs), concatenate(ns), concatenate(ts) return va, na, ta
def helix_segment(self, base_index, count, spacing, rise): ''' Lay out a single turn helix on x axis. Radius is calculated to fit the specified number of nucleotides. ''' # Choose radius so one helix turn has desired length. # Helix arc length = s, radius = r, rise = h: s**2 = r**2 + (h/(2*pi))**2 length = spacing * count from math import sqrt, pi radius = sqrt((length / (2 * pi))**2 - (rise / (2 * pi))**2) # Compute screw motion to advance along helix angle = 2 * pi / count angle_deg = angle * 180 / pi from chimerax.geometry import translation, rotation, vector_rotation, Place step = translation((rise / count, 0, 0)) * rotation( (1, 0, 0), angle_deg, center=(0, radius, 0)) # Compute first nucleotide so P-P lies on helix. orient = vector_rotation((1, 0, 0), step * (0, 0, 0)) # Place nucleotides on helix. place = {} p = Place() for i in range(count): place[base_index + i] = p * orient p = step * p return Segment(place, rise, pad=0)
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 update_pointer(self, msg): if 'name' in msg: if 'id' in msg: # If id not in msg leave name as "my pointer". self.name = '%s pointer' % msg['name'] if 'color' in msg: self.color = msg['color'] if 'mouse' in msg: xyz, axis = msg['mouse'] from chimerax.geometry import vector_rotation, translation p = translation(xyz) * vector_rotation((0, 0, 1), axis) self.position = p
def parse_symmetry(session, group, center=None, axis=None, molecule=None): # Handle products of symmetry groups. groups = group.split('*') from chimerax.geometry import Places ops = Places() for g in groups: ops = ops * group_symmetries(session, g, molecule) # Apply center and axis transformation. if center is not None or axis is not None: from chimerax.geometry import Place, vector_rotation, translation tf = Place() if center is not None and tuple(center) != (0, 0, 0): tf = translation([-c for c in center]) if axis is not None and tuple(axis) != (0, 0, 1): tf = vector_rotation(axis, (0, 0, 1)) * tf if not tf.is_identity(): ops = ops.transform_coordinates(tf) return ops
def layout(self, params, circuit_segments): p = params from chimerax.geometry import translation, rotation, Place, vector_rotation, norm from math import pi, cos, sin # Compute helix axis direction. # The helix rotation axis is does not make a 90 degree angle with # the P-P basepair line. It makes an angle of approximately 110 degrees. pa = p.pair_tilt * pi / 180 from numpy import array axis = array((cos(pa), sin(pa), 0)) # Compute screw motion that advances basepair along helix. # Initial basepair P-P is spans (0,0,0) to (pair_width,0,0). rtf = rotation(axis, p.stem_twist, center=(0.5 * p.pair_width, 0, -p.pair_off_axis)) ttf = translation(p.pair_spacing * axis) stf = ttf * rtf # Specify initial orientations of basepair nucleotides # so P-atoms are on helix and paired P atom is in the # oriented xy plane. p0, p1 = (0, 0, 0), (p.pair_width, 0, 0) tf1 = self.stem_residue_orientation(p0, stf * p0, p1) p2 = stf.inverse() * p1 tf2 = self.stem_residue_orientation(p1, p2, p0) # Keep track of basepair P-P orientation used to # orient the loop at the end of the stem. ctf = Place() # Layout nucleotides for both strands of double helix. coords = {} for i in range(self.length): coords[self.base5p + i] = tf1 coords[self.base3p - i] = tf2 tf1 = stf * tf1 tf2 = stf * tf2 ctf = stf * ctf # The next segment after the stem should put its first # P-atom at a position on the helix so that the last # nucleotide of the stem has the right orientation to # make a base pair. To achieve this the initial basepair # P-P does not lie on the x-axis. Instead we tilt the # entire helix so the paired P is advanced up the helix # by one position. width = norm(p2) ttf = vector_rotation(p2, p1) for b, tf in coords.items(): coords[b] = ttf * coords[b] # Added circuit at end of stem. ccoords = self.circuit.layout(p, gap=width) # Position the end circuit using the P-P orientation at # the end of the stem and taking account of the tilt of # the entire helix. ctf = ttf * ctf * ttf.inverse() for b, tf in ccoords.items(): coords[b] = ctf * tf # Use segment width for the tilted helix. seg = [Segment(coords, width, 0)] return seg