def transform_square(xform, center): axis, angle_deg = xform.getRotation() trans = xform.getTranslation() t1 = trans - axis*(trans*axis) import chimera t2 = chimera.cross(axis, t1) from math import pi, sin, cos angle = angle_deg * pi / 180 sa, ca = sin(angle), cos(angle) if 1-ca == 0: return None # No rotation axis_offset = t1*.5 + t2*(.5*sa/(1-ca)) c = chimera.Vector(center[0], center[1], center[2]) cd = c - axis_offset sq1 = cd - axis*(cd*axis) sq2 = axis*sq1.length e = 2 # Factor for enlarging square dz = chimera.cross(axis, sq1) * .05 # Thickness vector corners = [p.data() for p in (c - sq1 - sq2*e - dz, c - sq1 + sq2*e - dz, c + sq1*e + sq2*e - dz, c + sq1*e - sq2*e - dz, c - sq1 - sq2*e + dz, c - sq1 + sq2*e + dz, c + sq1*e + sq2*e + dz, c + sq1*e - sq2*e + dz, )] return corners
def transform_square(xform, center): axis, angle_deg = xform.getRotation() trans = xform.getTranslation() t1 = trans - axis * (trans * axis) import chimera t2 = chimera.cross(axis, t1) from math import pi, sin, cos angle = angle_deg * pi / 180 sa, ca = sin(angle), cos(angle) if 1 - ca == 0: return None # No rotation axis_offset = t1 * .5 + t2 * (.5 * sa / (1 - ca)) c = chimera.Vector(center[0], center[1], center[2]) cd = c - axis_offset sq1 = cd - axis * (cd * axis) sq2 = axis * sq1.length e = 2 # Factor for enlarging square dz = chimera.cross(axis, sq1) * .05 # Thickness vector corners = [ p.data() for p in ( c - sq1 - sq2 * e - dz, c - sq1 + sq2 * e - dz, c + sq1 * e + sq2 * e - dz, c + sq1 * e - sq2 * e - dz, c - sq1 - sq2 * e + dz, c - sq1 + sq2 * e + dz, c + sq1 * e + sq2 * e + dz, c + sq1 * e - sq2 * e + dz, ) ] return corners
def pointDistances(self, target): if isinstance(target, chimera.Point): points = [target] else: points = target from chimera import cross, Plane dists = [] minExt = min(self.extents) maxExt = max(self.extents) xfCenter = self.xformCenter() xfDirection = self.xformDirection() minPt = xfCenter + xfDirection * minExt maxPt = xfCenter + xfDirection * maxExt for pt in points: v = pt - xfCenter c1 = cross(v, xfDirection) if c1.length == 0.0: # colinear inPlane = pt else: plane = Plane(xfCenter, cross(c1, xfDirection)) inPlane = plane.nearest(pt) ptExt = (inPlane - xfCenter) * xfDirection if ptExt < minExt: measurePt = minPt elif ptExt > maxExt: measurePt = maxPt else: measurePt = inPlane dists.append(pt.distance(measurePt)) return dists
def _axisDistance(self, axis, infinite=False): from chimera import angle, cross, Plane # shortest distance between lines is perpendicular to both... sDir = self.xformDirection() aDir = axis.xformDirection() if angle(sDir, aDir) in [0.0, 180.0]: # parallel return self._axisEndsDist(axis) shortDir = cross(sDir, aDir) # can use analytically shortest dist only if each axis # penetrates the plane formed by the other axis and the # perpendicular if not infinite: for a1, a2 in [(axis, self), (self, axis)]: normal = cross(a1.xformDirection(), shortDir) plane = Plane(a1.xformCenter(), normal) d1 = plane.distance(a2.xformCenter() + a2.xformDirection() * a2.extents[0]) d2 = plane.distance(a2.xformCenter() + a2.xformDirection() * a2.extents[1]) if cmp(d1, 0.0) == cmp(d2, 0.0): # both ends on same side of plane return self._axisEndsDist(axis) # D is perpendicular distance to origin d1 = Plane(self.xformCenter(), shortDir).equation()[3] d2 = Plane(axis.xformCenter(), shortDir).equation()[3] return abs(d1 - d2)
def rotate(molecule, at, alpha): if len(at) == 3: try: a1, a2, a3 = [a.coord() for a in at] except AttributeError: a1, a2, a3 = at axis_a = a1 - a2 axis_b = a3 - a2 delta = chimera.angle(a1, a2, a3) - alpha axis = chimera.cross(axis_a, axis_b) if axis.data() == (0.0, 0.0, 0.0): axis = chimera.cross(axis_a, axis_b + chimera.Vector(1, 0, 0)) logger.warning("Had to choose arbitrary normal vector") pivot = a2 elif len(at) == 4: try: a1, a2, a3, a4 = [a.coord() for a in at] except AttributeError: a1, a2, a3, a4 = at axis = a3 - a2 delta = chimera.dihedral(a1, a2, a3, a4) - alpha pivot = a3 else: raise ValueError( "Atom list must contain 3 (angle) or 4 (dihedral) atoms only") r = X.translation(pivot - ZERO) # move to origin r.multiply(X.rotation(axis, -delta)) # rotate r.multiply(X.translation(ZERO - pivot)) # return to orig pos for a in molecule.atoms: a.setCoord(r.apply(a.coord()))
def getEndNormals(c0, c1, c2): v1 = c1 - c0 v2 = c2 - c0 binormal = chimera.cross(v1, v2) binormal.normalize() normal = chimera.cross(binormal, v1) normal.normalize() return normal, binormal
def getInteriorNormals(c0, cb, ca): vb = cb - c0 va = ca - c0 vab = ca - cb binormal = chimera.cross(va, vb) binormal.normalize() normal = chimera.cross(binormal, vab) normal.normalize() return normal, binormal
def minimizeTwist(d, nn, nb, on, ob): # To minimize twisting, we use the ribbon direction # (approximated by the vector from the previous residue # to the next residue) as the axis and project the normal # and binormal both for this (n) and previous (o) residue. # We don't care about maintaining handedness (defined by # direction, normal and binormal) or about orientation # (binormal and normal may be swapped). So we find whether # which two vectors (one from this and one from previous # residue) match best. That determines whether we match # normal to normal or normal to binormal. Once we decide # that, we can flip normal and binormal so that they never # rotate more than 90 degrees. nn0 = chimera.cross(nn, d) nn0.normalize() on0 = chimera.cross(on, d) on0.normalize() nb0 = chimera.cross(nb, d) nb0.normalize() ob0 = chimera.cross(ob, d) ob0.normalize() ndotn = nn0 * on0 bdotb = nb0 * ob0 matchBest = max(abs(ndotn), abs(bdotb)) ndotb = nn0 * ob0 bdotn = nb0 * on0 swapBest = max(abs(ndotb), abs(bdotn)) if matchBest >= swapBest: # We match normal to normal, binormal to binormal if ndotn < 0: normal = -nn else: normal = nn if bdotb < 0: binormal = -nb else: binormal = nb else: # We match normal to binormal, binormal to normal if ndotb < 0: binormal = -nn else: binormal = nn if bdotn < 0: normal = -nb else: normal = nb return normal, binormal
def interpolateCorkscrew(xf, c0, c1, f): """Interpolate by splitting the transformation into a rotation and a translation along the axis of rotation.""" import chimera, math dc = c1 - c0 vr, a = xf.getRotation() # a is in degrees tra = dc * vr # magnitude of translation # along rotation axis vt = dc - tra * vr # where c1 would end up if # only rotation is used cm = c0 + vt / 2 v0 = chimera.cross(vr, vt) if v0.sqlength() <= 0.0: ident = chimera.Xform.identity() return ident, ident v0.normalize() if a != 0.0: l = vt.length / 2 / math.tan(math.radians(a / 2)) cr = (cm + v0 * l).toVector() else: cr = chimera.Vector(0.0, 0.0, 0.0) Tinv = chimera.Xform.translation(-cr) R0 = chimera.Xform.rotation(vr, a * f) R1 = chimera.Xform.rotation(vr, -a * (1 - f)) X0 = chimera.Xform.translation(cr + vr * (f * tra)) X0.multiply(R0) X0.multiply(Tinv) X1 = chimera.Xform.translation(cr - vr * ((1 - f) * tra)) X1.multiply(R1) X1.multiply(Tinv) return X0, X1
def diha ( a1, a2, a3, a4 ) : #n1 = vnorm ( a1.coord(), a2.coord(), a3.coord() ) #n2 = vnorm ( a2.coord(), a3.coord(), a4.coord() ) #return numpy.arccos ( n2 * n1 * -1.0 ) * 180.0 / numpy.pi # http://math.stackexchange.com/questions/47059/how-do-i-calculate-a-dihedral-angle-given-cartesian-coordinates b1 = a2.coord() - a1.coord() b2 = a3.coord() - a2.coord() b3 = a4.coord() - a3.coord() n1 = chimera.cross ( b1, b2 ); n1.normalize() n2 = chimera.cross ( b2, b3 ); n2.normalize() m1 = chimera.cross ( n1, b2 ); m1.normalize() x = n1 * n2 y = m1 * n2 return -1.0 * numpy.arctan2 ( y, x) * 180.0 / numpy.pi
def _vmd_trans_angle(a, b, c, delta): """ Simulates VMD's `trans angle` command """ ZERO = Point(0, 0, 0) xf = chimera.Xform.translation(b - ZERO) xf.rotate(cross(a - b, b - c), delta) xf.translate(ZERO - b) return xf
def drawCylinder(radius, ep0, ep1, **kw): t = vrml.Transform() t.translation = chimera.Point([ep0, ep1]).data() delta = ep1 - ep0 height = delta.length axis = chimera.cross(cylAxis, delta) cos = (cylAxis * delta) / height angle = math.acos(cos) t.rotation = (axis[0], axis[1], axis[2], angle) c = vrml.Cylinder(radius=radius, height=height, **kw) t.addChild(c) return t
def AlignXf ( pos, v ) : Z = v Z.normalize() dZ = Vector( random.random(), random.random(), random.random() ) dZ.normalize() X = chimera.cross ( Z, dZ ) X.normalize () Y = chimera.cross ( Z, X ) Y.normalize () xf = chimera.Xform.xform ( X.x, Y.x, Z.x, pos.x, X.y, Y.y, Z.y, pos.y, X.z, Y.z, Z.z, pos.z ) #xf3 = chimera.Xform.xform ( # d, 0, 0, 0, # 0, d, 0, 0, # 0, 0, d, 0 ) #print xf3 return xf
def AlignXf ( pos, v ) : Z = v Z.normalize() from random import random as rand dZ = chimera.Vector( rand(), rand(), rand() ) dZ.normalize() X = chimera.cross ( Z, dZ ) X.normalize () Y = chimera.cross ( Z, X ) Y.normalize () xf = chimera.Xform.xform ( X.x, Y.x, Z.x, pos[0], X.y, Y.y, Z.y, pos[1], X.z, Y.z, Z.z, pos[2] ) #xf3 = chimera.Xform.xform ( # d, 0, 0, 0, # 0, d, 0, 0, # 0, 0, d, 0 ) #print xf3 return xf
def findPt(n1, n2, n3, dist, angle, dihed): # cribbed from Midas addgrp command v12 = n2 - n1 v13 = n3 - n1 v12.normalize() x = cross(v13, v12) x.normalize() y = cross(v12, x) y.normalize() mat = [0.0] * 12 for i in range(3): mat[i*4] = x[i] mat[1 + i*4] = y[i] mat[2 + i*4] = v12[i] mat[3 + i*4] = n1[i] xform = Xform.xform(*mat) radAngle = pi * angle / 180.0 tmp = dist * sin(radAngle) radDihed = pi * dihed / 180.0 pt = Point(tmp*sin(radDihed), tmp*cos(radDihed), dist*cos(radAngle)) return xform.apply(pt)
def findPt(n1, n2, n3, dist, angle, dihed): # cribbed from Midas addgrp command v12 = n2 - n1 v13 = n3 - n1 v12.normalize() x = cross(v13, v12) x.normalize() y = cross(v12, x) y.normalize() mat = [0.0] * 12 for i in range(3): mat[i * 4] = x[i] mat[1 + i * 4] = y[i] mat[2 + i * 4] = v12[i] mat[3 + i * 4] = n1[i] xform = Xform.xform(*mat) radAngle = pi * angle / 180.0 tmp = dist * sin(radAngle) radDihed = pi * dihed / 180.0 pt = Point(tmp * sin(radDihed), tmp * cos(radDihed), dist * cos(radAngle)) return xform.apply(pt)
def testPhi(dp, ap, bp, phiPlane, phi): if phiPlane: normal = cross(phiPlane[1] - phiPlane[0], phiPlane[2] - phiPlane[1]) normal.normalize() D = normal * phiPlane[1].toVector() bproj = project(bp, normal, D) aproj = project(ap, normal, D) dproj = project(dp, normal, D) ang = angle(bproj, aproj, dproj) if ang < phi: if base.verbose: print "phi criteria failed (%g < %g)" % (ang, phi) return 0 if base.verbose: print "phi criteria OK (%g >= %g)" % (ang, phi) else: if base.verbose: print "phi criteria irrelevant" return 1
def addDihedralBond(a1, a2, length, angleInfo, dihedInfo): """Make bond between two models. The models will be combined and the originals closed. The new model will be opened in the same id/subid as the non-moving model. a1/a2 are atoms in different models. a2 and atoms in its model will be moved to form the bond. 'length' is the bond length. 'angleInfo' is a two-tuple of sequence of three atoms and an angle that the three atoms should form. 'dihedInfo' is like 'angleInfo', but 4 atoms. angleInfo/dihedInfo can be None if insufficient atoms """ if a1.molecule == a2.molecule: raise ValueError("Atoms to be bonded must be in different models") # first, get the distance correct from chimera import Xform, cross, angle, Point dvector = a1.xformCoord() - a2.xformCoord() dvector.length = dvector.length + length openState = a2.molecule.openState openState.globalXform(Xform.translation(dvector)) # then angle if angleInfo: atoms, angleVal = angleInfo p1, p2, p3 = [a.xformCoord() for a in atoms] axis = cross(p1-p2, p2-p3) curAngle = angle(p1, p2, p3) delta = angleVal - curAngle v2 = p2 - Point(0.0, 0.0, 0.0) trans1 = Xform.translation(v2) v2.negate() trans2 = Xform.translation(v2) trans1.multiply(Xform.rotation(axis, delta)) trans1.multiply(trans2) openState.globalXform(trans1)
def addDihedralBond(a1, a2, length, angleInfo, dihedInfo): """Make bond between two models. The models will be combined and the originals closed. The new model will be opened in the same id/subid as the non-moving model. a1/a2 are atoms in different models. a2 and atoms in its model will be moved to form the bond. 'length' is the bond length. 'angleInfo' is a two-tuple of sequence of three atoms and an angle that the three atoms should form. 'dihedInfo' is like 'angleInfo', but 4 atoms. angleInfo/dihedInfo can be None if insufficient atoms """ if a1.molecule == a2.molecule: raise ValueError("Atoms to be bonded must be in different models") # first, get the distance correct from chimera import Xform, cross, angle, Point dvector = a1.xformCoord() - a2.xformCoord() dvector.length = dvector.length + length openState = a2.molecule.openState openState.globalXform(Xform.translation(dvector)) # then angle if angleInfo: atoms, angleVal = angleInfo p1, p2, p3 = [a.xformCoord() for a in atoms] axis = cross(p1 - p2, p2 - p3) curAngle = angle(p1, p2, p3) delta = angleVal - curAngle v2 = p2 - Point(0.0, 0.0, 0.0) trans1 = Xform.translation(v2) v2.negate() trans2 = Xform.translation(v2) trans1.multiply(Xform.rotation(axis, delta)) trans1.multiply(trans2) openState.globalXform(trans1)
def rotate_around_axis(axis, origin, screen_xy, last_screen_xy): # Measure drag around axis with mouse on front clip plane. sx, sy = screen_xy from VolumeViewer import slice xyz, back_xyz = slice.clip_plane_points(sx, sy) lsx, lsy = last_screen_xy last_xyz, back_last_xyz = slice.clip_plane_points(lsx, lsy) a = apply(chimera.Vector, axis) a.normalize() o = apply(chimera.Vector, origin) v = apply(chimera.Vector, xyz) lv = apply(chimera.Vector, last_xyz) t = chimera.cross(a, v - o) t2 = t.sqlength() if t2 > 0: angle = (t * (v - lv)) / t2 else: angle = 0 import math angle_deg = 180 * angle / math.pi vo = apply(chimera.Vector, origin) va = apply(chimera.Vector, axis) xf = chimera.Xform() xf.translate(vo) xf.rotate(va, angle_deg) xf.translate(-vo) # Applying xf performs the two translations and rotations in the # opposite order of the function calls. First it translates by -vo, # then rotates, then translates by +vo. move_active_models(xf)
def _draw_star(self): center_att = Point(*self.center_att) center = Point(*self.center) p6 = Point(*self.p6) vec_AB = center_att - center shape_size = self.size * 1.5 half_length = shape_size / 2.0 thickness = shape_size / 4.0 adjustment = half_length / center.distance(center_att) adj_vec_AB_1 = adjustment * vec_AB adj_vec_AB_2 = -1 * adj_vec_AB_1 x1 = adj_vec_AB_1 + center x2 = adj_vec_AB_2 + center perp1 = normalize(cross(x1 - x2, x2 - p6)) * half_length perp2 = -1 * perp1 o1 = perp1 + x1 o2 = perp1 + x2 o3 = perp2 + x1 o4 = perp2 + x2 d1 = x2 - center d2 = (x1 - center) * 0.5 # Rotate by 72 degrees to identify other points of the star outer = [ _rotate(o1, center, o2, alpha, d1) + center for alpha in (72, 144, 216, 288, 360) ] inner = [ _rotate(o1, center, o2, alpha, d2) + center for alpha in (72, 144, 216, 288, 360) ] perp_for = thickness * normalize(cross(o1 - o2, o3 - o1)) perp_back = -1 * perp_for center_1 = perp_for + center center_2 = perp_back + center color_and_points = { 'outer_{}'.format(i + 1): value for i, value in enumerate(outer) } color_and_points.update( {'inner_{}'.format(i + 1): value for i, value in enumerate(inner)}) color_and_points.update( dict(color1=self.color1, color2=self.color2, center_1=center_1, center_2=center_2)) bild = """ .color {color1} .polygon {outer_1} {center_1} {inner_3} .polygon {outer_1} {inner_3} {center_2} .polygon {outer_1} {inner_4} {center_1} .polygon {outer_1} {center_2} {inner_4} .polygon {outer_2} {center_1} {inner_4} .polygon {outer_2} {inner_4} {center_2} .polygon {outer_2} {inner_5} {center_1} .polygon {outer_2} {center_2} {inner_5} .polygon {outer_3} {center_1} {inner_5} .polygon {outer_3} {inner_5} {center_2} .polygon {outer_3} {inner_1} {center_1} .polygon {outer_3} {center_2} {inner_1} .polygon {outer_4} {center_1} {inner_1} .polygon {outer_4} {inner_1} {center_2} .polygon {outer_4} {inner_2} {center_1} .polygon {outer_4} {center_2} {inner_2} .polygon {outer_5} {center_1} {inner_2} .polygon {outer_5} {inner_2} {center_2} .polygon {outer_5} {inner_3} {center_1} .polygon {outer_5} {center_2} {inner_3} """.format(**color_and_points) return self._build_vrml(bild)
def tetraPos(bondee, bonded, bondLen, toward=None, away=None, toward2=None, away2=None): newBonded = [] curBonded = bonded[:] if len(curBonded) == 0: pos = singlePos(bondee, bondLen, toward, away) toward = toward2 away = away2 newBonded.append(pos) curBonded.append(pos) if len(curBonded) == 1: # add at 109.5 degree angle coplanar = toward or away if coplanar: coplanar = [coplanar] else: coplanar = None pos = anglePos(bondee, curBonded[0], bondLen, 109.5, coplanar=coplanar) if toward or away: # find the other 109.5 position in the toward/away # plane and the closer/farther position as appropriate old = bondee - curBonded[0] old.normalize() new = pos - bondee midpoint = bondee + old * new.length * cos705 otherPos = pos + (midpoint - pos) * 2 d1 = (pos - (toward or away)).sqlength() d2 = (otherPos - (toward or away)).sqlength() if toward: if d2 < d1: pos = otherPos elif away and d2 > d1: pos = otherPos newBonded.append(pos) curBonded.append(pos) if len(curBonded) == 2: # add along anti-bisector of current bonds and raised up # 54.75 degrees from plane of those bonds (half of 109.5) v1 = curBonded[0] - bondee v2 = curBonded[1] - bondee v1.normalize() v2.normalize() antiBi = v1 + v2 antiBi.negate() antiBi.normalize() # in order to stabilize the third and fourth tetrahedral # positions, cross the longer vector by the shorter if v1.sqlength() > v2.sqlength(): crossV = cross(v1, v2) else: crossV = cross(v2, v1) crossV.normalize() antiBi = antiBi * cos5475 * bondLen crossV = crossV * sin5475 * bondLen pos = bondee + antiBi + crossV if toward or away: otherPos = bondee + antiBi - crossV d1 = (pos - (toward or away)).sqlength() d2 = (otherPos - (toward or away)).sqlength() if toward: if d2 < d1: pos = otherPos elif away and d2 > d1: pos = otherPos newBonded.append(pos) curBonded.append(pos) if len(curBonded) == 3: unitized = [] for cb in curBonded: v = cb - bondee v.normalize() unitized.append(bondee + v) pl = Plane(unitized) norm = pl.normal # if normal on other side of plane from bondee, we need to # invert the normal; the (signed) distance from bondee # to the plane indicates if it is on the same side # (positive == same side) d = pl.distance(bondee) if d < 0.0: norm.negate() newBonded.append(bondee + norm * bondLen) return newBonded
if pyrimidine_max[2] < max[2]: pyrimidine_max[2] = max[2] pu = (purine_max[1] - purine_min[1]) py = (pyrimidine_max[1] - pyrimidine_min[1]) purine_pyrimidine_ratio = pu / (pu + py) del b, coord, min, max, pu, py # precompute z-plane rotation correction factor zAxis = chimera.Vector(0, 0, 1) for b in standard_bases.values(): pts = [chimera.Point(*b[n]) for n in b["ring atom names"][0:2]] yAxis = pts[0] - pts[1] yAxis.normalize() yAxis.z = 0.0 # should be zero already # insurance, so yAxis is perpendicular to zAxis xAxis = chimera.cross(yAxis, zAxis) xf = chimera.Xform.xform( xAxis[0], yAxis[0], zAxis[0], 0.0, xAxis[1], yAxis[1], zAxis[1], 0.0, xAxis[2], yAxis[2], zAxis[2], 0.0, orthogonalize=True ) # we can work in 2d because we know atoms are in z=0 plane #coords = [b[a][0:2] for a in atoms] #yAxis = [coords[0][0] - coords[1][0], coords[0][1] - coords[1][1]] #len = math.sqrt(yAxis[0] * yAxis[0] + yAxis[1] * yAxis[1]) #yAxis[0] /= len #yAxis[1] /= len ## x axis is perpendicular to y axis #xf = chimera.Xform.xform( # yAxis[1], yAxis[0], 0.0, 0.0,
def drawSlab(residue, style, thickness, orient, shape, showGly): try: t = residue.type if t in ('PSU', 'P'): n = 'P' elif t in ('NOS', 'I'): n = 'I' else: n = nucleic3to1[t] except KeyError: return None standard = standard_bases[n] ring_atom_names = standard["ring atom names"] atoms = getRing(residue, ring_atom_names) if not atoms: return None plane = chimera.Plane([a.coord() for a in atoms]) info = findStyle(style) type = standard['type'] slab_corners = info[type] origin = residue.findAtom(anchor(info[ANCHOR], type)).coord() origin = plane.nearest(origin) pts = [plane.nearest(a.coord()) for a in atoms[0:2]] yAxis = pts[0] - pts[1] yAxis.normalize() xAxis = chimera.cross(yAxis, plane.normal) xf = chimera.Xform.xform( xAxis[0], yAxis[0], plane.normal[0], origin[0], xAxis[1], yAxis[1], plane.normal[1], origin[1], xAxis[2], yAxis[2], plane.normal[2], origin[2] ) xf.multiply(standard["adjust"]) color_kwds = _atom_color(atoms[0]) na = vrml.Transform() na.translation = xf.getTranslation().data() axis, angle = xf.getRotation() na.rotation = (axis[0], axis[1], axis[2], math.radians(angle)) #xf.invert() # invert so xf maps residue space to standard space halfThickness = thickness / 2.0 t = vrml.Transform() na.addChild(t) llx, lly = slab_corners[0] urx, ury = slab_corners[1] t.translation = (llx + urx) / 2.0, (lly + ury) / 2.0, 0 if shape == 'box': b = vrml.Box(size=(urx - llx, ury - lly, 2.0 * halfThickness), **color_kwds) elif shape == 'tube': radius = (urx - llx) / 2 t.scale = 1, 1, halfThickness / radius b = vrml.Cylinder(radius=radius, height=(ury - lly), **color_kwds) elif shape == 'ellipsoid': # need to reach anchor atom t.scale = ((urx - llx) / 20 * _SQRT2, (ury - lly) / 20 * _SQRT2, .1 * halfThickness) b = vrml.Sphere(radius=10, **color_kwds) t.addChild(b) if showGly: c1p = residue.findAtom("C1'") ba = residue.findAtom(anchor(info[ANCHOR], type)) if c1p and ba: c1p.hide = False ba.hide = False if not orient: return na # show slab orientation by putting "bumps" on surface if standard['type'] == PYRIMIDINE: t = vrml.Transform() na.addChild(t) t.translation = (llx + urx) / 2.0, (lly + ury) / 2, halfThickness t.addChild(vrml.Sphere(radius=halfThickness, **color_kwds)) else: # purine t = vrml.Transform() na.addChild(t) t.translation = (llx + urx) / 2.0, lly + (ury - lly) / 3, halfThickness t.addChild(vrml.Sphere(radius=halfThickness, **color_kwds)) t = vrml.Transform() na.addChild(t) t.translation = (llx + urx) / 2.0, lly + (ury - lly) * 2 / 3, halfThickness t.addChild(vrml.Sphere(radius=halfThickness, **color_kwds)) return na
def _draw_cube(self): center = Point(*self.center) center_att = Point(*self.center_att) p6 = Point(*self.p6) vec_AB = center_att - center # Resize the shape. $size refers to the total size, # $half_length refers to the distance required create # points on either side of the geometric center. half_length = self.size / 2.0 # Vec_AB is currently too large, we want it to be adjusted so that the distance is equal to the offset # that will be used to place the ponits around the geometric center. The equation asks the question, # what factor should be multiplied times the distance in order to prodce $half-length? adjustment = half_length / center.distance(center_att) # Adjust vector_AB by the amount determined in both the forward and reverse directions adj_vec_AB_1 = vec_AB * adjustment adj_vec_AB_2 = adj_vec_AB_1 * -1 # Add two points along the line connecting the residues in the forward and reverse direction x1 = adj_vec_AB_1 + center x2 = adj_vec_AB_2 + center # perp_1 represents a point perpendicular to the previously created two perp_1 = normalize(cross(x1 - x2, x2 - p6)) perp1 = perp_1 * half_length perp2 = perp1 * -1 # Each 'o' represents a point on the box (o stands for original points, which are based on the two that # lie along the line connecting the two residues) o1 = perp1 + x1 o2 = perp1 + x2 o3 = perp2 + x1 o4 = perp2 + x2 # This creates 8 points (the corners of the box) based upon the coordinates of o1-o4 perp_for = normalize(cross(o1 - o2, o3 - o1)) * half_length perp_back = perp_for * -1 points = dict(s1=perp_for + o1, s2=perp_for + o2, s3=perp_for + o3, s4=perp_for + o4, s5=perp_back + o1, s6=perp_back + o2, s7=perp_back + o3, s8=perp_back + o4) # Draw the Cube - some cubes require two colors, so the triangles are intentionally divided so that one # side shows both colors # Color 1 (blue, yellow, or green) bild = """ .color {color1} .polygon {s2} {s3} {s4} .polygon {s1} {s2} {s6} .polygon {s4} {s7} {s8} .polygon {s5} {s6} {s8} .polygon {s2} {s4} {s8} .polygon {s1} {s5} {s7} .color {color2} .polygon {s1} {s3} {s2} .polygon {s3} {s7} {s4} .polygon {s1} {s6} {s5} .polygon {s5} {s8} {s7} .polygon {s2} {s8} {s6} .polygon {s1} {s7} {s3} """.format(color1=self.color1, color2=self.color2, **points) return self._build_vrml(bild)
def mult(a, b): return Quaternion(a.s * b.s - a.v * b.v, b.v * a.s + a.v * b.s + chimera.cross(a.v, b.v))
def _draw_diamond(self): center_att = Point(*self.center_att) center = Point(*self.center) p6 = Point(*self.p6) vec_AB = center_att - center shape_size = self.size * 0.5 adjustment = shape_size / center.distance(center_att) adj_vec_AB_1 = adjustment * vec_AB adj_vec_AB_2 = -adjustment * vec_AB x1 = adj_vec_AB_1 + center x2 = adj_vec_AB_2 + center perp_1 = cross(x1 - x2, x2 - p6) perp1 = perp_1 * shape_size perp2 = perp_1 * -shape_size # The number of sides to the diamond is up for debate. It was suggested to use six sides since the # diamond could look like a cube that has been rotated; however, four seems to work since the cylinder # goes directly through one corner. Maybe it could be an option for the user? # Each 'o' represents a corner of a square that is centered on $geom_center o1 = perp1 + x1 o2 = perp1 + x2 o3 = perp2 + x1 o4 = perp2 + x2 # Determine coordinates for outer points of the diamond # Top point of star is $shape_size above geometric center # Vector distance between center and top point of star d1 = x2 - center outer = [ _rotate(o1, center, o2, alpha, d1) + center for alpha in (90, 180, 270, 360) ] # The following function creates the top and bottom of the diamond by creating two points at the geometric # center that are perpendicular to the plane of the square (and parallel with the plane of the ring). perp_for = normalize(cross(o1 - o2, o3 - o1)) * shape_size top = perp_for + center bottom = perp_for * -1 + center color_and_points = { 'outer_{}'.format(i + 1): value for i, value in enumerate(outer) } color_and_points.update( dict(top=top, bottom=bottom, color1=self.color1, color2=self.color2)) bild = """ .color {color1} .polygon {outer_1} {bottom} {outer_2} .polygon {outer_1} {outer_4} {bottom} .polygon {outer_3} {top} {outer_2} .polygon {outer_3} {outer_4} {top} .color {color2} .polygon {outer_1} {outer_2} {top} .polygon {outer_1} {top} {outer_4} .polygon {outer_3} {outer_2} {bottom} .polygon {outer_3} {bottom} {outer_4} """.format(**color_and_points) return self._build_vrml(bild)
def _draw_cone(self): center_att = Point(*self.center_att) center = Point(*self.center) p6 = Point(*self.p6) vec_AB = center_att - center half_length = self.size / 2.0 # Vec_AB is currently too large, we want it to be adjusted so that the distance is equal to the offset # that will be used to place the points around the geometric center. The equation asks the question, # what factor should be multiplied times the distance in order to prodce $half-length? # Two adjustments are added to shift the geom_center of the shape. _adjustment = half_length / center.distance(center_att) adjustment1 = _adjustment * 0.66 adjustment2 = _adjustment * 1.33 # Adjust vector_AB by the amount determined in both the forward and reverse directions adj_vec_AB_1 = adjustment1 * vec_AB adj_vec_AB_2 = -adjustment2 * vec_AB # Add two points along the line connecting the residues in the forward and reverse direction x1 = adj_vec_AB_1 + center x2 = adj_vec_AB_2 + center # perp_1 represents a point perpendicular to the previously created two perp1 = normalize(cross(x1 - x2, x2 - p6)) perp2 = -0.5 * perp1 o1 = perp1 + x1 o2 = perp2 + x1 perp3 = normalize(cross(o1 - x2, x2 - center_att)) * half_length o3 = perp3 + x1 # Determine coordinates for outer points of the rectangle # Top point of rectangle is $half_length above geometric center # Vector distance between center and top point of rectangle d1 = o3 - x1 # Rotate by 90 degrees to identify other points of the rectangle - note that t5 is the same as x1 outer = [ _rotate(o1, o3, x1, alpha, d1) + x1 for alpha in (45, 90, 135, 180, 225, 270, 315, 360) ] # Draw the cone color_and_points = { 'outer_{}'.format(i + 1): value for i, value in enumerate(outer) } color_and_points.update( dict(x1=x1, x2=x2, color1=self.color1, color2=self.color2)) bild = """ .color {color1} .polygon {outer_1} {outer_2} {x1} .polygon {outer_1} {x1} {outer_8} .polygon {outer_3} {x1} {outer_2} .polygon {outer_3} {outer_4} {x1} .color {color2} .polygon {outer_5} {x1} {outer_4} .polygon {outer_5} {outer_6} {x1} .polygon {outer_7} {x1} {outer_6} .polygon {outer_7} {outer_8} {x1} .color {color1} .polygon {outer_1} {x2} {outer_2} .polygon {outer_1} {outer_8} {x2} .polygon {outer_5} {outer_4} {x2} .polygon {outer_5} {x2} {outer_6} .color {color2} .polygon {outer_3} {outer_2} {x2} .polygon {outer_3} {x2} {outer_4} .polygon {outer_7} {outer_6} {x2} .polygon {outer_7} {x2} {outer_8} """.format(**color_and_points) return self._build_vrml(bild)
def _draw_rectangle(self): center_att = Point(*self.center_att) center = Point(*self.center) p6 = Point(*self.p6) vec_AB = center_att - center half_length = self.size / 1.2 thickness = self.size / 1.8 adjustment = half_length / center.distance(center_att) adj_vec_AB_1 = adjustment * vec_AB adj_vec_AB_2 = -adjustment * vec_AB x1 = adj_vec_AB_1 + center x2 = adj_vec_AB_2 + center perp1 = normalize(cross(x1 - x2, x2 - p6)) * half_length perp2 = perp1 * -1 o1 = perp1 + x1 o2 = perp1 + x2 o3 = perp2 + x1 o4 = perp2 + x2 d1 = x2 - center outer = [ _rotate(o1, center, o2, alpha, d1) + center for alpha in (45, 90, 225, 270) ] perp_for = thickness * normalize(cross(o1 - o2, o3 - o1)) perp_back = perp_for * -1 color_and_points = dict(center_1=perp_for + center, center_2=perp_back + center, front_1=perp_for + outer[0], front_2=perp_for + outer[1], front_3=perp_for + outer[2], front_4=perp_for + outer[3], back_1=perp_back + outer[0], back_2=perp_back + outer[1], back_3=perp_back + outer[2], back_4=perp_back + outer[3], color1=self.color1, color2=self.color2) # Draw the rectangle bild = """ .color {color1} .polygon {front_1} {front_2} {center_1} .polygon {front_1} {center_1} {front_4} .polygon {front_3} {center_1} {front_2} .polygon {front_3} {front_4} {center_1} .polygon {back_1} {center_2} {back_2} .polygon {back_1} {back_4} {center_2} .polygon {back_3} {back_2} {center_2} .polygon {back_3} {center_2} {back_4} .polygon {back_1} {back_2} {front_1} .polygon {back_2} {front_2} {front_1} .polygon {back_2} {back_3} {front_2} .polygon {back_3} {front_3} {front_2} .polygon {back_3} {back_4} {front_3} .polygon {back_4} {front_4} {front_3} .polygon {back_4} {back_1} {front_4} .polygon {back_1} {front_1} {front_4} """.format(**color_and_points) return self._build_vrml(bild)
import chimera from chimera import Plane, Xform, cross, Vector, Point m = chimera.openModels.list()[0] b = chimera.selection.currentBonds()[0] bondVec = b.atoms[0].coord() - b.atoms[1].coord() bondVec.normalize() axis = Vector(1.0, 0.0, 0.0) crossProd = cross(axis, bondVec) if crossProd.sqlength() > 0: from math import acos, degrees xform = Xform.rotation(crossProd, degrees(acos(axis * bondVec))) xform.invert() else: xform = Xform.identity() m.openState.xform = xform # okay, that puts the bond parallel to the X axis, now swing the plane of # the rest of the molecule into the xy plane... molPlane = Plane([a.xformCoord() for a in m.atoms[:3]]) angle = chimera.angle(molPlane.normal, Vector(0, 0, -1)) xform2 = Xform.rotation(b.atoms[0].xformCoord() - b.atoms[1].xformCoord(), angle) xform2.multiply(xform) m.openState.xform = xform2
import chimera from chimera import Plane, Xform, cross, Vector, Point m = chimera.openModels.list()[0] b = chimera.selection.currentBonds()[0] bondVec = b.atoms[0].coord() - b.atoms[1].coord() bondVec.normalize() axis = Vector(1.0, 0.0, 0.0) crossProd = cross(axis, bondVec) if crossProd.sqlength() > 0: from math import acos, degrees xform = Xform.rotation(crossProd, degrees(acos(axis * bondVec))) xform.invert() else: xform = Xform.identity() m.openState.xform = xform # okay, that puts the bond parallel to the X axis, now swing the plane of # the rest of the molecule into the xy plane... molPlane = Plane([a.xformCoord() for a in m.atoms[:3]]) angle = chimera.angle(molPlane.normal, Vector(0, 0, -1)) xform2 = Xform.rotation(b.atoms[0].xformCoord()-b.atoms[1].xformCoord(), angle) xform2.multiply(xform) m.openState.xform = xform2
def _draw_hexagon(self): center_att = Point(*self.center_att) center = Point(*self.center) p6 = Point(*self.p6) vec_AB = center_att - center shape_size = self.size half_length = shape_size / 2.0 thickness = shape_size / 4.0 adjustment = half_length / center.distance(center_att) adj_vec_AB_1 = adjustment * vec_AB adj_vec_AB_2 = -1 * adj_vec_AB_1 x1 = adj_vec_AB_1 + center x2 = adj_vec_AB_2 + center perp1 = normalize(cross(x1 - x2, x2 - p6)) * half_length perp2 = -1 * perp1 o1 = perp1 + x1 o2 = perp1 + x2 o3 = perp2 + x1 o4 = perp2 + x2 d1 = x2 - center # Rotate by 60 degrees to identify other points of the hexagon - note that t5 is the same as n1 outer = [ _rotate(o1, center, o2, alpha, d1) + center for alpha in (0, 45, 135, 180, 225, 315) ] perp_for = thickness * normalize(cross(o1 - o2, o3 - o1)) perp_back = -1 * perp_for color_and_points = dict( front_1=perp_for + outer[0], front_2=perp_for + outer[1], front_3=perp_for + outer[2], front_4=perp_for + outer[3], front_5=perp_for + outer[4], front_6=perp_for + outer[5], back_1=perp_back + outer[0], back_2=perp_back + outer[1], back_3=perp_back + outer[2], back_4=perp_back + outer[3], back_5=perp_back + outer[4], back_6=perp_back + outer[5], center_1=perp_for + center, center_2=perp_back + center, color1=self.color1, color2=self.color2, ) bild = """ .color {color1} .polygon {front_1} {front_2} {center_1} .polygon {front_1} {center_1} {front_6} .polygon {front_3} {center_1} {front_2} .polygon {front_3} {front_4} {center_1} .polygon {front_5} {center_1} {front_4} .polygon {front_5} {front_6} {center_1} .polygon {back_1} {center_2} {back_2} .polygon {back_1} {back_6} {center_2} .polygon {back_3} {back_2} {center_2} .polygon {back_3} {center_2} {back_4} .polygon {back_5} {back_4} {center_2} .polygon {back_5} {center_2} {back_6} .polygon {back_1} {back_2} {front_1} .polygon {back_2} {front_2} {front_1} .polygon {back_2} {back_3} {front_2} .polygon {back_3} {front_3} {front_2} .polygon {back_3} {back_4} {front_3} .polygon {back_4} {front_4} {front_3} .polygon {back_4} {back_5} {front_4} .polygon {back_5} {front_5} {front_4} .polygon {back_5} {back_6} {front_5} .polygon {back_6} {front_6} {front_5} .polygon {back_6} {back_1} {front_6} .polygon {back_1} {front_1} {front_6} """.format(**color_and_points) return self._build_vrml(bild)