def distance(self, items, **kw): from Axes import Axis from Planes import Plane numAxes = len([i for i in items if isinstance(i, Axis)]) numPlanes = len([i for i in items if isinstance(i, Plane)]) if numAxes == 2: axis1, axis2 = items dist = axis1._axisDistance(axis2, **kw) elif numAxes == numPlanes == 1: if isinstance(items[0], Axis): axis, plane = items else: plane, axis = items xformPlane = chimera.Plane(plane.xformOrigin(), plane.xformNormal()) xc = axis.xformCenter() d1, d2 = [xformPlane.distance(pt) for pt in [xc + axis.direction * e for e in axis.extents]] if d1 * d2 < 0.0: dist = 0.0 else: dist = min([abs(d) for d in (d1, d2)]) elif numPlanes == 2: plane1, plane2 = items angle = self.angle(items) if angle == 0.0: o1 = plane1.xformOrigin() p2 = chimera.Plane(plane2.xformOrigin(), plane2.xformNormal()) dist = (o1 - p2.nearest(o1)).length else: dist = 0.0 else: raise ValueError("distance calculation not implemented") return dist
def orientPlanarRing(atoms, ringIndices=[], convex=True): r = atoms[0].residue if not r.fillDisplay or r.fillMode != chimera.Residue.Thick: # can't show orientation of thin nor aromatic ring return [] pts = [a.coord() for a in atoms] bonds = bondsBetween(atoms) if chimera.Bond.Wire in [b.drawMode for b in bonds]: radius = 0 else: radius = min([b.radius for b in bonds]) radius *= atoms[0].molecule.stickScale color_kwds = _atom_color(atoms[0]) if radius == 0: # can't show orientation of thin ring return [] # non-zero radius planeEq = chimera.Plane(pts) offset = planeEq.normal * radius result = [] for r in ringIndices: center = chimera.Point([pts[i] for i in r]) + offset t = vrml.Transform() t.translation = center.data() s = vrml.Sphere(radius=radius, **color_kwds) t.addChild(s) result.append(t) return result
def pointDistances(self, target, signed=False): if isinstance(target, chimera.Point): points = [target] else: points = target measurePlane = chimera.Plane(self.xformOrigin(), self.xformNormal()) if signed: return [measurePlane.distance(pt) for pt in points] return [abs(measurePlane.distance(pt)) for pt in points]
def _restoreSession(self, planeData, fromGeom=False): from SimpleSession import getColor, idLookup maxNumber = 0 for data, atomIDs in planeData.items(): number, name, cmpVal, radius, thickness, colorID, origin, normal\ = data atoms = [idLookup(a) for a in atomIDs] self._instantiatePlane(number, name, self.planeOrdinal + number, getColor(colorID), radius, thickness, self._getSourceModel(atoms), atoms, chimera.Plane(Point(*origin), Vector(*normal))) maxNumber = max(number, maxNumber) self.planeOrdinal += maxNumber
def findRotamerNearest(atPos, idatmType, atom, neighbor, checkDist): # find atom that approaches nearest to a methyl-type rotamer nPos = neighbor.xformCoord() v = atPos - nPos bondLen = bondWithHLength(atom, typeInfo[idatmType].geometry) v.length = cos70_5 * bondLen center = atPos + v plane = chimera.Plane(center, v) radius = sin70_5 * bondLen checkDist += radius nearby = searchTree.searchTree(center.data(), checkDist) nearPos = n = nearAtom = None for nb in nearby: if nb.xformCoord() in [atPos, nPos]: # exclude atoms from identical-copy molecules also... continue if nb.molecule != atom.molecule \ and nb.molecule.id == atom.molecule.id: # don't consider atoms in sibling submodels continue candidates = [(nb, vdwRadius(nb))] # only heavy atoms in tree... for nbb in nb.primaryNeighbors(): if nbb.element.number != 1: continue if nbb == neighbor: continue candidates.append((nbb, Hrad)) for candidate, aRad in candidates: cPos = candidate.xformCoord() # project into plane... proj = plane.nearest(cPos) # find nearest approach of circle... cv = proj - center if cv.length == 0.0: continue cv.length = radius app = center + cv d = (cPos - app).length - aRad if not nearPos or d < n: nearPos = cPos n = d nearAtom = candidate return nearPos, n, nearAtom
def _align(self, refModel): if not refModel.useClipPlane: from chimera import LimitationError raise LimitationError("Cannot align clip planes:" " both models must have clipping on") matchModel = self.menu.getvalue() refMat = refModel.openState.xform matchMat = matchModel.openState.xform if refMat == matchMat: matchModel.clipPlane = refModel.clipPlane return xf = matchMat.inverse() xf.multiply(refMat) refClip = refModel.clipPlane matchModel.clipPlane = chimera.Plane(xf.apply(refClip.origin), xf.apply(refClip.normal))
class XS: def __init__(self, name, points=None, sw=None, sl=None, closed=None, grid=None): # "points" should be integer coordinates in # the range [0, grid]. This is necessary to # make the cross section displayable in the editor. if name is None: global xsId name = "%s%d" % (xsUnnamed, xsId) xsId += 1 self.name = name self.points = points self.sw = sw self.sl = sl self.closed = closed self.grid = grid self.xs = None self.mode = Residue.Ribbon_Custom def setXS(self, xs, mode, grid): self.xs = xs self.mode = mode def mapToGrid(c): return int(round(((c / 2 + 0.5) * grid))) self.points = [(mapToGrid(x), mapToGrid(y)) for x, y in xs.outline] self.sw = xs.smoothWidth self.sl = xs.smoothLength self.closed = xs.closed self.grid = grid def setResidue(self, r): if self.mode == Residue.Ribbon_Custom: r.ribbonDrawMode = r.Ribbon_Custom r.ribbonXSection = self.getXS() else: r.ribbonDrawMode = self.mode r.ribbonXSection = None def getXS(self): if self.xs is None: self._makeXSection() return self.xs def _makeXSection(self): try: checkXSection(self.closed, self.points) except ValueError, s: from chimera import replyobj replyobj.error(s) return False xs = chimera.RibbonXSection(self.sw, self.sl, self.closed) # Figure out whether the points are in clockwise # or counterclockwise order. Back-face culling # of polygons requires one particular direction. try: p = chimera.Plane([chimera.Point(x, y, 0) for x, y in self.points]) except chimera.error: # probably caused by colinear points pass else: if p.normal.z > 0: self.points.reverse() outline = [] g = float(self.grid) for x, y in self.points: mx = ((x / g) - 0.5) * 2.0 my = ((y / g) - 0.5) * 2.0 outline.append((mx, my)) xs.outline = outline self.xs = xs xsName[xs] = (self.name, self.grid)
def fill5Ring(atoms, c5p=None): pts = [a.coord() for a in atoms] bonds = bondsBetween(atoms) if chimera.Bond.Wire in [b.drawMode for b in bonds]: radius = 0 else: radius = min([b.radius for b in bonds]) radius *= atoms[0].molecule.stickScale color_kwds = _atom_color(atoms[0]) # see how planar ring is indices = (0, 1, 2, 3, 4, 0, 1, 2, 3, 4) distC5p = None fake_bonds = [(0, 5), (1, 5), (2, 5), (3, 5), (4, 5)] for i in range(5): atoms[i].pucker = 'plane' # Find twist plane. Note: due to floating point limitations, # dist3 and dist4 will virtually never be zero. for i in range(5): planeEq = chimera.Plane([pts[indices[j]] for j in range(i, i + 3)]) dist3 = planeEq.distance(pts[indices[i + 3]]) dist4 = planeEq.distance(pts[indices[i + 4]]) if c5p: distC5p = planeEq.distance(c5p.coord()) if dist3 == 0 or dist4 == 0 \ or (dist3 < 0 and dist4 > 0) or (dist3 > 0 and dist4 < 0): break abs_dist3 = abs(dist3) abs_dist4 = abs(dist4) if abs_dist3 < planar_cutoff and abs_dist4 < planar_cutoff: # planar, new_vertex is centroid of pts new_vertex = chimera.Point(pts) elif abs_dist3 < abs_dist4 and abs_dist4 / abs_dist3 >= envelope_ratio: # envelope, new_vertex is mid-point of separating edge new_vertex = chimera.Point([pts[indices[i]], pts[indices[i + 3]]]) atoms[indices[i + 4]].pucker = 'envelope' del fake_bonds[indices[i + 4]] elif abs_dist4 < abs_dist3 and abs_dist3 / abs_dist4 >= envelope_ratio: # envelope, new_vertex is mid-point of separating edge new_vertex = chimera.Point([pts[indices[i + 2]], pts[indices[i + 4]]]) atoms[indices[i + 3]].pucker = 'envelope' del fake_bonds[indices[i + 3]] else: # if (dist3 < 0 and dist4 > 0) or (dist3 > 0 and dist4 < 0): # twist, new_vertex is placed in twist plane near twist pts centroid = chimera.Point([ pts[indices[i + 1]], pts[indices[i + 3]], pts[indices[i + 4]] ]) new_vertex = planeEq.nearest(centroid) del fake_bonds[indices[i + 1]] if cmp(dist3, 0) == cmp(distC5p, 0): atoms[indices[i + 3]].pucker = 'endo' else: atoms[indices[i + 3]].pucker = 'exo' if cmp(dist4, 0) == cmp(distC5p, 0): atoms[indices[i + 4]].pucker = 'endo' else: atoms[indices[i + 4]].pucker = 'exo' pts.append(new_vertex) # new_vertex has index 5 triangles = ((0, 1, 5), (1, 2, 5), (2, 3, 5), (3, 4, 5), (4, 0, 5)) if radius == 0: f = TriangleNode(solid=False, coordList=[p.data() for p in pts], coordIndices=triangles, colorPerVertex=False, **color_kwds ) return [f] # non-zero radius f = vrml.Faces(**color_kwds) for t in triangles: # t is a list of 3 indices t = [pts[i] for i in t] # t is a list of 3 Points planeEq = chimera.Plane(t) offset = planeEq.normal * radius top = [(p + offset).data() for p in t] bot = [(p - offset).data() for p in t] f.addFace(top) if 1: # STL wants manifold objects for i in range(len(t) - 1): f.addFace([top[i], bot[i], bot[i + 1], top[i + 1]]) f.addFace([top[-1], bot[-1], bot[0], top[0]]) bot.reverse() f.addFace(bot) result = [f] for b in fake_bonds: node = drawCylinder(radius, pts[b[0]], pts[b[1]], **color_kwds) result.append(node) t = vrml.Transform() t.translation = pts[5].data() s = vrml.Sphere(radius=radius, **color_kwds) t.addChild(s) result.append(t) return result
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