def init_motors(): ###data structure to construct the rotation sign for rotary motor numSeg = 20 rotS = map((lambda n: pi / 2 + n * 2.0 * pi / numSeg), range(numSeg * 3 / 4 + 1)) zOffset = 0.005 scaleS = 0.4 drawing_globals.rotS0n = rotS0n = map( (lambda a: (scaleS * cos(a), scaleS * sin(a), 0.0 - zOffset)), rotS) drawing_globals.rotS1n = rotS1n = map( (lambda a: (scaleS * cos(a), scaleS * sin(a), 1.0 + zOffset)), rotS) ###Linear motor arrow sign data structure drawing_globals.halfHeight = 0.45 drawing_globals.halfEdge = halfEdge = 3.0 * scaleS * sin(pi / numSeg) arrow0Vertices = [(rotS0n[-1][0] - halfEdge, rotS0n[-1][1], rotS0n[-1][2]), (rotS0n[-1][0] + halfEdge, rotS0n[-1][1], rotS0n[-1][2]), (rotS0n[-1][0], rotS0n[-1][1] + 2.0 * halfEdge, rotS0n[-1][2])] arrow0Vertices.reverse() drawing_globals.arrow0Vertices = arrow0Vertices drawing_globals.arrow1Vertices = [ (rotS1n[-1][0] - halfEdge, rotS1n[-1][1], rotS1n[-1][2]), (rotS1n[-1][0] + halfEdge, rotS1n[-1][1], rotS1n[-1][2]), (rotS1n[-1][0], rotS1n[-1][1] + 2.0 * halfEdge, rotS1n[-1][2]) ] drawing_globals.halfEdge = halfEdge = 1.0 / 3.0 ##1.0/8.0 drawing_globals.linearArrowVertices = [(0.0, -halfEdge, 0.0), (0.0, halfEdge, 0.0), (0.0, 0.0, 2 * halfEdge)] return
def init_motors(): ###data structure to construct the rotation sign for rotary motor numSeg = 20 rotS = map((lambda n: pi/2+n*2.0*pi/numSeg), range(numSeg*3/4 + 1)) zOffset = 0.005 scaleS = 0.4 drawing_globals.rotS0n = rotS0n = map( (lambda a: (scaleS*cos(a), scaleS*sin(a), 0.0 - zOffset)), rotS) drawing_globals.rotS1n = rotS1n = map( (lambda a: (scaleS*cos(a), scaleS*sin(a), 1.0 + zOffset)), rotS) ###Linear motor arrow sign data structure drawing_globals.halfHeight = 0.45 drawing_globals.halfEdge = halfEdge = 3.0 * scaleS * sin(pi/numSeg) arrow0Vertices = [ (rotS0n[-1][0]-halfEdge, rotS0n[-1][1], rotS0n[-1][2]), (rotS0n[-1][0]+halfEdge, rotS0n[-1][1], rotS0n[-1][2]), (rotS0n[-1][0], rotS0n[-1][1] + 2.0*halfEdge, rotS0n[-1][2])] arrow0Vertices.reverse() drawing_globals.arrow0Vertices = arrow0Vertices drawing_globals.arrow1Vertices = [ (rotS1n[-1][0]-halfEdge, rotS1n[-1][1], rotS1n[-1][2]), (rotS1n[-1][0]+halfEdge, rotS1n[-1][1], rotS1n[-1][2]), (rotS1n[-1][0], rotS1n[-1][1] + 2.0*halfEdge, rotS1n[-1][2])] drawing_globals.halfEdge = halfEdge = 1.0/3.0 ##1.0/8.0 drawing_globals.linearArrowVertices = [ (0.0, -halfEdge, 0.0), (0.0, halfEdge, 0.0), (0.0, 0.0,2*halfEdge)] return
def CalculateTorus(self, a, b, u, v): """calculate point on torus""" pi2 = 2 * pi #transformation function - torus cf = cos(pi2*u) sf = sin(pi2*u) ct = cos(pi2*v) st = sin(pi2*v) #point on torus return Triple((a+b*ct)*cf, (a+b*ct)*sf, b*st)
def CalculateTorus(self, a, b, u, v): """calculate point on torus""" pi2 = 2 * pi #transformation function - torus cf = cos(pi2 * u) sf = sin(pi2 * u) ct = cos(pi2 * v) st = sin(pi2 * v) #point on torus return Triple((a + b * ct) * cf, (a + b * ct) * sf, b * st)
def _compute_vertices(self): theta = 2*pi/self.numVertices*arange(self.numVertices) + \ self.orientation self.xs = self.xy[0] + self.radius * cos(theta) self.ys = self.xy[1] + self.radius * sin(theta)
def _compute_ribbon_point(origin, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn , theta_offset ): """ """ ##handedness = -1 ##theta_offset = 0.0 #turn_angle = twistPerBase ##turn_angle = (handedness * 2 * pi) / basesPerTurn turn_angle = (2 * pi) / basesPerTurn ## axial_offset = unitVectorAlongLength * duplexRise cY = unitVectorAlongLadderStep cZ = unitDepthVector theta = turn_angle * numberOfBasesDrawn + theta_offset # in radians y = cos(theta) * peakDeviationFromCenter z = sin(theta) * peakDeviationFromCenter ## vx = axial_offset # a Vector p = origin + y * cY + z * cZ return p
def _compute_vertices(self): theta = 2*pi/self.numVertices*arange(self.numVertices) + \ self.orientation self.xs = self.xy[0] + self.radius*cos(theta) self.ys = self.xy[1] + self.radius*sin(theta)
def init_cyls(): # generate two circles in space as 13-gons, one rotated half a segment with # respect to the other these are used as cylinder ends [not quite true # anymore, see comments just below] slices = 13 circ1 = map((lambda n: n*2.0*pi/slices), range(slices+1)) circ2 = map((lambda a: a+pi/slices), circ1) drawing_globals.drum0 = drum0 = map((lambda a: (cos(a), sin(a), 0.0)), circ1) drum1 = map((lambda a: (cos(a), sin(a), 1.0)), circ2) drum1n = map((lambda a: (cos(a), sin(a), 0.0)), circ2) #grantham 20051213 I finally decided the look of the oddly twisted cylinder # bonds was not pretty enough, so I made a "drum2" which is just drum0 with # a 1.0 Z coordinate, a la drum1. #bruce 060609: this apparently introduced the bug of the drum1 end-cap of a # cylinder being "ragged" (letting empty space show through), which I fixed # by using drum2 for that cap rather than drum1. drum1 is no longer used # except as an intermediate value in the next few lines. drawing_globals.drum2 = drum2 = map((lambda a: (cos(a), sin(a), 1.0)), circ1) # This edge list zips up the "top" vertex and normal and then the "bottom" # vertex and normal. Thus each tuple in the sequence would be (vtop, ntop, # vbot, nbot) [grantham 20051213] # (bruce 051215 simplified the python usage in a way which should create the # same list.) drawing_globals.cylinderEdges = zip(drum0, drum0, drum2, drum0) circle = zip(drum0[:-1],drum0[1:],drum1[:-1]) +\ zip(drum1[:-1],drum0[1:],drum1[1:]) circlen = zip(drum0[:-1],drum0[1:],drum1n[:-1]) +\ zip(drum1n[:-1],drum0[1:],drum1n[1:]) drawing_globals.cap0n = (0.0, 0.0, -1.0) drawing_globals.cap1n = (0.0, 0.0, 1.0) drum0.reverse() return
def init_cyls(): # generate two circles in space as 13-gons, one rotated half a segment with # respect to the other these are used as cylinder ends [not quite true # anymore, see comments just below] slices = 13 circ1 = map((lambda n: n * 2.0 * pi / slices), range(slices + 1)) circ2 = map((lambda a: a + pi / slices), circ1) drawing_globals.drum0 = drum0 = map((lambda a: (cos(a), sin(a), 0.0)), circ1) drum1 = map((lambda a: (cos(a), sin(a), 1.0)), circ2) drum1n = map((lambda a: (cos(a), sin(a), 0.0)), circ2) #grantham 20051213 I finally decided the look of the oddly twisted cylinder # bonds was not pretty enough, so I made a "drum2" which is just drum0 with # a 1.0 Z coordinate, a la drum1. #bruce 060609: this apparently introduced the bug of the drum1 end-cap of a # cylinder being "ragged" (letting empty space show through), which I fixed # by using drum2 for that cap rather than drum1. drum1 is no longer used # except as an intermediate value in the next few lines. drawing_globals.drum2 = drum2 = map((lambda a: (cos(a), sin(a), 1.0)), circ1) # This edge list zips up the "top" vertex and normal and then the "bottom" # vertex and normal. Thus each tuple in the sequence would be (vtop, ntop, # vbot, nbot) [grantham 20051213] # (bruce 051215 simplified the python usage in a way which should create the # same list.) drawing_globals.cylinderEdges = zip(drum0, drum0, drum2, drum0) circle = zip(drum0[:-1],drum0[1:],drum1[:-1]) +\ zip(drum1[:-1],drum0[1:],drum1[1:]) circlen = zip(drum0[:-1],drum0[1:],drum1n[:-1]) +\ zip(drum1n[:-1],drum0[1:],drum1n[1:]) drawing_globals.cap0n = (0.0, 0.0, -1.0) drawing_globals.cap1n = (0.0, 0.0, 1.0) drum0.reverse() return
def vector_to_axis(line, point): """ Returns the vector between a point and the closest point on a line (ie. the perpendicular projection of the point on the line). @type line: L{Vector} @param line: vector defining a line @type point: L{Vector} @param point: vector defining the point """ line=line.normalized() np=point.norm() angle=line.angle(point) return point-line**(np*cos(angle))
def rotaxis2m(theta, vector): """ Calculate a left multiplying rotation matrix that rotates theta rad around vector. Example: >>> m=rotaxis(pi, Vector(1,0,0)) >>> rotated_vector=any_vector.left_multiply(m) @type theta: float @param theta: the rotation angle @type vector: L{Vector} @param vector: the rotation axis @return: The rotation matrix, a 3x3 Numeric array. """ vector=vector.copy() vector.normalize() c=cos(theta) s=sin(theta) t=1-c x,y,z=vector.get_array() rot=zeros((3,3), "d") # 1st row rot[0,0]=t*x*x+c rot[0,1]=t*x*y-s*z rot[0,2]=t*x*z+s*y # 2nd row rot[1,0]=t*x*y+s*z rot[1,1]=t*y*y+c rot[1,2]=t*y*z-s*x # 3rd row rot[2,0]=t*x*z-s*y rot[2,1]=t*y*z+s*x rot[2,2]=t*z*z+c return rot
def getSphereTriStrips(level): steps = 2**level points = [] # Triangle Strip vertices o be returned. # Construct an icosahedron with two vertices at the North and South Poles, # +-1 on the Y axis, as you look toward the X-Y plane with the Z axis # pointing out at you. The "middle ring" vertices are all at the same # +-latitudes, on the intersection circles of the globe with a polar-axis # cylinder of the proper radius. # # The third "master vertex" of the icosahedron is placed on the X-Y plane, # which intersects the globe at the Greenwich Meridian (the semi-circle at # longitude 0, through Greenwich Observatory, 5 miles south-east of London.) # # The X (distance from the polar axis) and Y (height above the equatorial # plane) of the master vertex make a "golden rectangle", one unit high by # "phi" (1.6180339887498949) wide. We normalize this to put it on the # unit-radius sphere, and take the distance from the axis as the cylinder # radius used to generate the rest of the vertices of the two middle rings. # # Plotted on the globe, the master vertex (first vertex of the North ring) # is lat-long 31.72,0 due south of London in Africa, about 45 miles # south-southwest of Benoud, Algeria. The first vertex of the south ring is # rotated 1/10 of a circle east, at lat-long -31.72,36 in the south end of # the Indian Ocean, about 350 miles east-southeast of Durban, South Africa. # vert0 = norm(V(phi,1,0)) # Project the "master vertex" onto a unit sphere. cylRad = vert0[0] # Icos vertex distance from the Y axis. ringLat = atan2(vert0[1], vert0[0]) * degreesPerRadian # Latitude +-31.72 . # Basic triangle-strip icosahedron vertices. Start and end with the Poles. # Reflect the master vertex into the southern hemisphere and rotate 5 copies # to make the middle rings of 5 vertices at North and South latitudes. p2_5 = 2*pi / 5.0 # Simplify indexing by replicating the Poles, so everything is in fives. icosRings = [ 5 * [V(0.0, -1.0, 0.0)], # South Pole. # South ring, first edge *centered on* the Greenwich Meridian. [V(cylRad*cos((i-.5)*p2_5),-vert0[1], cylRad*sin((i-.5)*p2_5)) for i in range(5)], # North ring, first vertex *on* the Greenwich Meridian. [V(cylRad*cos(i*p2_5 ), vert0[1], cylRad*sin(i*p2_5)) for i in range(5)], 5 * [V(0.0, 1.0, 0.0)] ] # North Pole. # Three bands, going from bottom to top (South to North.) for band in range(3): lowerRing = icosRings[band] upperRing = icosRings[band+1] # Subdivide bands into sub-bands. When level == 0, steps == 1, # subBand == 0, and we get just the icosahedron out. (Really!) for subBand in range(steps): # Account for the tapering-in at the poles, making less points on # one edge of a sub-band than there are on the other edge. botOffset = 0 if band is 0: # South. botSteps = max(subBand, 1) # Don't divide by zero. topSteps = subBand + 1 # Collapse the *first* triangle of south sub-band bottom edges. botOffset = -1 elif band is 1: # Middle. botSteps = topSteps = steps else: # band is 2: North. botSteps = steps - subBand topSteps = max(steps - (subBand+1), 1) pass subBandSteps = max(botSteps, topSteps) # Do five segments, clockwise around the North Pole (East to West.) for seg in range(5): nextseg = (seg+1) % 5 # Wrap-around. # Interpolate ends of bottom & top edges of a sub-band segment. fractBot = float(subBand)/float(steps) fractTop = float(subBand+1)/float(steps) sbBotRight = fractBot * upperRing[seg] + \ (1.0-fractBot) * lowerRing[seg] sbTopRight = fractTop * upperRing[seg] + \ (1.0-fractTop) * lowerRing[seg] sbBotLeft = fractBot * upperRing[nextseg] + \ (1.0-fractBot) * lowerRing[nextseg] sbTopLeft = fractTop * upperRing[nextseg] + \ (1.0-fractTop) * lowerRing[nextseg] # Output the right end of the first segment of the sub-band. # We'll end up wrapping around to this same pair of points at # the left end of the last segment of the sub-band. if seg == 0: # Project verts from icosahedron faces onto the unit sphere. points += [norm(sbBotRight), norm(sbTopRight)] # Step across the sub-band edges from right to left, # stitching triangle pairs from their lower to upper edges. for step in range(1, subBandSteps+1): # Interpolate step point pairs along the sub-band edges. fractLower = float(step+botOffset)/float(botSteps) lower = fractLower * sbBotLeft + \ (1.0-fractLower) * sbBotRight # Collapse the *last* triangle of north sub-band top edges. fractUpper = float(min(step, topSteps))/float(topSteps) upper = fractUpper * sbTopLeft + \ (1.0-fractUpper) * sbTopRight # Output verts, projected from icos faces onto unit sphere. points += [norm(lower), norm(upper)] continue # step continue # seg continue # subBand continue # band return points
def setup_drawer(): """ Set up the usual constant display lists in the current OpenGL context. WARNING: THIS IS ONLY CORRECT IF ONLY ONE GL CONTEXT CONTAINS DISPLAY LISTS -- or more precisely, only the GL context this has last been called in (or one which shares its display lists) will work properly with the routines in drawer.py, since the allocated display list names are stored in globals set by this function, but in general those names might differ if this was called in different GL contexts. """ spherelistbase = glGenLists(_NUM_SPHERE_SIZES) sphereList = [] for i in range(_NUM_SPHERE_SIZES): sphereList += [spherelistbase+i] glNewList(sphereList[i], GL_COMPILE) glBegin(GL_TRIANGLE_STRIP) # GL_LINE_LOOP to see edges stripVerts = getSphereTriStrips(i) for vertNorm in stripVerts: glNormal3fv(vertNorm) glVertex3fv(vertNorm) continue glEnd() glEndList() continue drawing_globals.sphereList = sphereList # Sphere triangle-strip vertices for each level of detail. # (Cache and re-use the work of making them.) # Can use in converter-wrappered calls like glVertexPointerfv, # but the python arrays are re-copied to C each time. sphereArrays = [] for i in range(_NUM_SPHERE_SIZES): sphereArrays += [getSphereTriStrips(i)] continue drawing_globals.sphereArrays = sphereArrays # Sphere glDrawArrays triangle-strip vertices for C calls. # (Cache and re-use the work of converting a C version.) # Used in thinly-wrappered calls like glVertexPointer. sphereCArrays = [] for i in range(_NUM_SPHERE_SIZES): CArray = numpy.array(sphereArrays[i], dtype = numpy.float32) sphereCArrays += [CArray] continue drawing_globals.sphereCArrays = sphereCArrays # Sphere indexed vertices. # (Cache and re-use the work of making the indexes.) # Can use in converter-wrappered calls like glDrawElementsui, # but the python arrays are re-copied to C each time. sphereElements = [] # Pairs of lists (index, verts) . for i in range(_NUM_SPHERE_SIZES): sphereElements += [indexVerts(sphereArrays[i], .0001)] continue drawing_globals.sphereElements = sphereElements # Sphere glDrawElements index and vertex arrays for C calls. sphereCIndexTypes = [] # numpy index unsigned types. sphereGLIndexTypes = [] # GL index types for drawElements. sphereCElements = [] # Pairs of numpy arrays (Cindex, Cverts) . for i in range(_NUM_SPHERE_SIZES): (index, verts) = sphereElements[i] if len(index) < 256: Ctype = numpy.uint8 GLtype = GL_UNSIGNED_BYTE else: Ctype = numpy.uint16 GLtype = GL_UNSIGNED_SHORT pass sphereCIndexTypes += [Ctype] sphereGLIndexTypes += [GLtype] sphereCIndex = numpy.array(index, dtype = Ctype) sphereCVerts = numpy.array(verts, dtype = numpy.float32) sphereCElements += [(sphereCIndex, sphereCVerts)] continue drawing_globals.sphereCIndexTypes = sphereCIndexTypes drawing_globals.sphereGLIndexTypes = sphereGLIndexTypes drawing_globals.sphereCElements = sphereCElements if glGetString(GL_EXTENSIONS).find("GL_ARB_vertex_buffer_object") >= 0: # A GLBufferObject version for glDrawArrays. sphereArrayVBOs = [] for i in range(_NUM_SPHERE_SIZES): vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, sphereCArrays[i], GL_STATIC_DRAW) sphereArrayVBOs += [vbo] continue drawing_globals.sphereArrayVBOs = sphereArrayVBOs # A GLBufferObject version for glDrawElements indexed verts. sphereElementVBOs = [] # Pairs of (IBO, VBO) for i in range(_NUM_SPHERE_SIZES): ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, sphereCElements[i][0], GL_STATIC_DRAW) vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, sphereCElements[i][1], GL_STATIC_DRAW) sphereElementVBOs += [(ibo, vbo)] continue drawing_globals.sphereElementVBOs = sphereElementVBOs ibo.unbind() vbo.unbind() pass #bruce 060415 drawing_globals.wiresphere1list = wiresphere1list = glGenLists(1) glNewList(wiresphere1list, GL_COMPILE) didlines = {} # don't draw each triangle edge more than once def shoulddoline(v1,v2): # make sure not list (unhashable) or Numeric array (bug in __eq__) v1 = tuple(v1) v2 = tuple(v2) if (v1,v2) not in didlines: didlines[(v1,v2)] = didlines[(v2,v1)] = None return True return False def doline(v1,v2): if shoulddoline(v1,v2): glVertex3fv(v1) glVertex3fv(v2) return glBegin(GL_LINES) ocdec = getSphereTriangles(1) for tri in ocdec: #e Could probably optim this more, e.g. using a vertex array or VBO or # maybe GL_LINE_STRIP. doline(tri[0], tri[1]) doline(tri[1], tri[2]) doline(tri[2], tri[0]) glEnd() glEndList() drawing_globals.CylList = CylList = glGenLists(1) glNewList(CylList, GL_COMPILE) glBegin(GL_TRIANGLE_STRIP) for (vtop, ntop, vbot, nbot) in drawing_globals.cylinderEdges: glNormal3fv(nbot) glVertex3fv(vbot) glNormal3fv(ntop) glVertex3fv(vtop) glEnd() glEndList() drawing_globals.CapList = CapList = glGenLists(1) glNewList(CapList, GL_COMPILE) glNormal3fv(drawing_globals.cap0n) glBegin(GL_POLYGON) for p in drawing_globals.drum0: glVertex3fv(p) glEnd() glNormal3fv(drawing_globals.cap1n) glBegin(GL_POLYGON) #bruce 060609 fix "ragged edge" bug in this endcap: drum1 -> drum2 for p in drawing_globals.drum2: glVertex3fv(p) glEnd() glEndList() drawing_globals.diamondGridList = diamondGridList = glGenLists(1) glNewList(diamondGridList, GL_COMPILE) glBegin(GL_LINES) for p in drawing_globals.digrid: glVertex(p[0]) glVertex(p[1]) glEnd() glEndList() drawing_globals.lonsGridList = lonsGridList = glGenLists(1) glNewList(lonsGridList, GL_COMPILE) glBegin(GL_LINES) for p in drawing_globals.lonsEdges: glVertex(p[0]) glVertex(p[1]) glEnd() glEndList() drawing_globals.CubeList = CubeList = glGenLists(1) glNewList(CubeList, GL_COMPILE) glBegin(GL_QUAD_STRIP) # note: CubeList has only 4 faces of the cube; only suitable for use in # wireframes; see also solidCubeList [bruce 051215 comment reporting # grantham 20051213 observation] glVertex((-1,-1,-1)) glVertex(( 1,-1,-1)) glVertex((-1, 1,-1)) glVertex(( 1, 1,-1)) glVertex((-1, 1, 1)) glVertex(( 1, 1, 1)) glVertex((-1,-1, 1)) glVertex(( 1,-1, 1)) glVertex((-1,-1,-1)) glVertex(( 1,-1,-1)) glEnd() glEndList() drawing_globals.solidCubeList = solidCubeList = glGenLists(1) glNewList(solidCubeList, GL_COMPILE) glBegin(GL_QUADS) for i in xrange(len(drawing_globals.cubeIndices)): avenormals = V(0,0,0) #bruce 060302 fixed normals for flat shading for j in xrange(4) : nTuple = tuple( drawing_globals.cubeNormals[drawing_globals.cubeIndices[i][j]]) avenormals += A(nTuple) avenormals = norm(avenormals) for j in xrange(4) : vTuple = tuple( drawing_globals.cubeVertices[drawing_globals.cubeIndices[i][j]]) #bruce 060302 made size compatible with glut.glutSolidCube(1.0) vTuple = A(vTuple) * 0.5 glNormal3fv(avenormals) glVertex3fv(vTuple) glEnd() glEndList() drawing_globals.rotSignList = rotSignList = glGenLists(1) glNewList(rotSignList, GL_COMPILE) glBegin(GL_LINE_STRIP) for ii in xrange(len(drawing_globals.rotS0n)): glVertex3fv(tuple(drawing_globals.rotS0n[ii])) glEnd() glBegin(GL_LINE_STRIP) for ii in xrange(len(drawing_globals.rotS1n)): glVertex3fv(tuple(drawing_globals.rotS1n[ii])) glEnd() glBegin(GL_TRIANGLES) for v in drawing_globals.arrow0Vertices + drawing_globals.arrow1Vertices: glVertex3f(v[0], v[1], v[2]) glEnd() glEndList() drawing_globals.linearArrowList = linearArrowList = glGenLists(1) glNewList(linearArrowList, GL_COMPILE) glBegin(GL_TRIANGLES) for v in drawing_globals.linearArrowVertices: glVertex3f(v[0], v[1], v[2]) glEnd() glEndList() drawing_globals.linearLineList = linearLineList = glGenLists(1) glNewList(linearLineList, GL_COMPILE) glEnable(GL_LINE_SMOOTH) glBegin(GL_LINES) glVertex3f(0.0, 0.0, -drawing_globals.halfHeight) glVertex3f(0.0, 0.0, drawing_globals.halfHeight) glEnd() glDisable(GL_LINE_SMOOTH) glEndList() drawing_globals.circleList = circleList = glGenLists(1) glNewList(circleList, GL_COMPILE) glBegin(GL_LINE_LOOP) for ii in range(60): x = cos(ii*2.0*pi/60) y = sin(ii*2.0*pi/60) glVertex3f(x, y, 0.0) glEnd() glEndList() # piotr 080405 drawing_globals.filledCircleList = filledCircleList = glGenLists(1) glNewList(filledCircleList, GL_COMPILE) glBegin(GL_POLYGON) for ii in range(60): x = cos(ii*2.0*pi/60) y = sin(ii*2.0*pi/60) glVertex3f(x, y, 0.0) glEnd() glEndList() drawing_globals.lineCubeList = lineCubeList = glGenLists(1) glNewList(lineCubeList, GL_COMPILE) glBegin(GL_LINES) cvIndices = [0,1, 2,3, 4,5, 6,7, 0,3, 1,2, 5,6, 4,7, 0,4, 1,5, 2,6, 3,7] for i in cvIndices: glVertex3fv(tuple(drawing_globals.cubeVertices[i])) glEnd() glEndList() #initTexture('C:\\Huaicai\\atom\\temp\\newSample.png', 128,128) return # from setup_drawer
def func(x): return ((2*x*cos(x) - sin(x))*cos(x) - x + pi/4.0)
def drawDnaRibbons(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = None, ribbon2_start_point = None, ribbon1_direction = None, ribbon2_direction = None, peakDeviationFromCenter = 9.5, ribbonThickness = 2.0, ribbon1Color = None, ribbon2Color = None, stepColor = None): """ Draw DNA ribbons where each strand is represented as a ribbon. DNA ribbons are drawn as sine waves with appropriate phase angles, with the phase angles computed in this method. @param endCenter1: Axis end 1 @type endCenter1: B{V} @param endCenter2: Axis end 2 @type endCenter2: B{V} @param basesPerTurn: Number of bases in a full turn. @type basesPerTurn: float @param duplexRise: Center to center distance between consecutive steps @type duplexRise: float @param glpaneScale: GLPane scale used in scaling arrow head drawing @type glpaneScale: float @param lineOfSightVector: Glpane lineOfSight vector, used to compute the the vector along the ladder step. @type: B{V} @param displayStyle: Rubberband display style (specified as an integer) see comment in the method below. See also GLPane.displayMode. @type displayStyle: int @param peakDeviationFromCenter: Distance of a peak from the axis Also known as 'Amplitude' of a sine wave. @type peakDeviationFromCenter: float @param ribbonThickness: Thickness of each of the the two ribbons @type ribbonThickness: float @param ribbon1Color: Color of ribbon1 @param ribbon2Color: Color of ribbon2 @see: B{DnaLineMode.Draw } (where it is used) for comments on color convention TODO: as of 2008-04-22 - Need more documentation - This method is long mainly because of a number of custom drawing See if that can be refactored e.g. methods like _drawRibbon1/strand1, drawRibbon2 / strand2 etc. - Further optimization / refactoring (low priority) """ #Try to match the rubberband display style as closely as possible to #either the glpane's current display or the chunk display of the segment #being edited. The caller should do the job of specifying the display style #it desires. As of 2008-02-20, this method only supports following display #styles --Tubes, Ball and Stick, CPK and lines. the sphere radius #for ball and stick or CPK is calculated approximately. if displayStyle == diTrueCPK: SPHERE_RADIUS = 3.5 ribbonThickness = 2.0 elif displayStyle == diTUBES: SPHERE_RADIUS = 0.01 ribbonThickness = 5.0 elif displayStyle == diLINES: #Lines display and all other unsupported display styles SPHERE_RADIUS = 0.01 ribbonThickness = 1.0 else: #ball and stick display style. All other unsupported displays #will be rendered in ball and stick display style SPHERE_RADIUS = 1.0 ribbonThickness = 3.0 ribbonLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ribbonLength is at least equal to the duplexRise. # i.e. do the drawing only when there are at least two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint if ribbonLength < duplexRise: return unitVectorAlongLength = norm(endCenter2 - endCenter1) ###=== pointOnAxis = endCenter1 axial_shift_1 = V(0.0, 0.0, 0.0) # might be changed below axial_shift_2 = V(0.0, 0.0, 0.0) # [these might be discarded and recomputed just below; # the case where they aren't is (and I think was) untested. # -- bruce 080422 comment] vectorAlongLadderStep = cross(-lineOfSightVector, unitVectorAlongLength) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 numberOfBasesDrawn = 0 theta_offset = 0 x = 0 ### #Formula .. Its a Sine Wave. # y(x) = A.sin(2*pi*f*x + phase_angle) ------[1] # where -- # f = 1/T # A = Amplitude of the sine wave (or 'peak deviation from center') # y = y coordinate of the sine wave -- distance is in Angstroms # x = the x coordinate # phase_angle is computed for each wave. We know y at x =0. For example, # for ribbon_1, , at x = 0, y = A. Putting these values in equation [1] # we get the phase_angle. Similarly, for ribbon_2, at x = 0, y = -6 # Putting these values will give use the phase_angle_2. # Note that for ribbon2_point, we subtract the value of equation [1] from # the point on axis. x = 0.0 T = duplexRise * basesPerTurn # The 'Period' of the sine wave # (i.e. peak to peak distance between consecutive crests) amplitude = peakDeviationFromCenter amplitudeVector = unitVectorAlongLadderStep * amplitude depthVector = unitDepthVector * amplitude # Note: to reduce the effect of perspective view on rung direction, # we could multiply depthVector by 0.1 or 0.01. But this would lessen # the depth realism of line/sphere intersections. [bruce 080216] ### if ribbon1_start_point is not None: ribbon1_point = ribbon1_start_point else: if ribbon2_start_point is not None: ribbon1_point = _get_ribbon_point_on_other_ribbon( ribbon2_start_point, ribbon2_direction, endCenter1, unitVectorAlongLength) else: phase_angle_ribbon_1 = HALF_PI theta_ribbon_1 = (TWICE_PI * x / T) + phase_angle_ribbon_1 #Initialize ribbon1_point and ribbon2_point ribbon1_point = pointOnAxis + \ amplitudeVector * sin(theta_ribbon_1) + \ depthVector * cos(theta_ribbon_1) ribbon1_direction = +1 drawDnaSingleRibbon(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = ribbon1_point, ribbon1_direction = ribbon1_direction, peakDeviationFromCenter = peakDeviationFromCenter, ribbonThickness = ribbonThickness, ribbon1Color = ribbon1Color, stepColor = stepColor) if ribbon2_start_point is not None: ribbon2_point = ribbon2_start_point else: if ribbon1_start_point is not None: ribbon2_point = _get_ribbon_point_on_other_ribbon( ribbon1_start_point, ribbon1_direction, endCenter1, unitVectorAlongLength) else: phase_angle_ribbon_2 = asin(-6.0/(amplitude)) theta_ribbon_2 = (TWICE_PI * x / T) - phase_angle_ribbon_2 ribbon2_point = pointOnAxis - \ amplitudeVector * sin(theta_ribbon_2) + \ depthVector * cos(theta_ribbon_2) ribbon2_direction = -1 drawDnaSingleRibbon(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = ribbon2_point, ribbon1_direction = ribbon2_direction, peakDeviationFromCenter = peakDeviationFromCenter, ribbonThickness = ribbonThickness, ribbon1Color = ribbon2Color, stepColor = stepColor) del vectorAlongLadderStep return
def _buildResiduum(self, mol, zmatrix, n_atoms, phi, psi, init_pos, symbol): """ Builds cartesian coordinates for an amino acid from the internal coordinates table. mol is a chunk to which the amino acid will be added. zmatrix is an internal coordinates array corresponding to a given amino acid. n_atoms is a number of atoms to be build + 3 dummy atoms. phi is a peptide bond PHI angle. psi is a peptide bond PSI angle. init_pos are optional postions of previous CA, C and O atoms. symbol is a current amino acid symbol (used for proline case) Note: currently, it doesn't rebuild bonds, so inferBonds has to be called after. Unfortunately, the proper bond order can not be correctly recognized this way. """ if mol == None: return if not init_pos: # assign three previous atom positions for i in range (0,3): self.coords[i][0] = self.prev_coords[i][0] self.coords[i][1] = self.prev_coords[i][1] self.coords[i][2] = self.prev_coords[i][2] else: # if no prev_coords are given, compute the first three atom positions num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[1] self.coords[0][0] = 0.0; self.coords[0][1] = 0.0; self.coords[0][2] = 0.0; self.coords[1][0] = r; self.coords[1][1] = 0.0; self.coords[1][2] = 0.0; ccos = cos(DEG2RAD*a) num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[2] if atom_c == 1: self.coords[2][0] = self.coords[0][0] + r*ccos else: self.coords[2][0] = self.coords[0][0] - r*ccos self.coords[2][1] = r * sin(DEG2RAD*a) self.coords[2][2] = 0.0 for i in range (0, 3): self.prev_coords[i][0] = self.coords[i][0] + init_pos[0] self.prev_coords[i][1] = self.coords[i][1] + init_pos[1] self.prev_coords[i][2] = self.coords[i][2] + init_pos[2] for n in range (3, n_atoms): # Generate all coordinates using three previous atoms # as a frame of reference, num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[n] cosa = cos(DEG2RAD * a) xb = self.coords[atom_b][0] - self.coords[atom_c][0] yb = self.coords[atom_b][1] - self.coords[atom_c][1] zb = self.coords[atom_b][2] - self.coords[atom_c][2] rbc = 1.0 / sqrt(xb*xb + yb*yb + zb*zb) if abs(cosa) >= 0.999: # Linear bond case # Skip angles, just extend along the bond. rbc = r * rbc * cosa self.coords[n][0] = self.coords[atom_c][0] + xb*rbc self.coords[n][1] = self.coords[atom_c][1] + yb*rbc self.coords[n][2] = self.coords[atom_c][2] + zb*rbc else: xa = self.coords[atom_a][0] - self.coords[atom_c][0] ya = self.coords[atom_a][1] - self.coords[atom_c][1] za = self.coords[atom_a][2] - self.coords[atom_c][2] xyb = sqrt(xb*xb + yb*yb) inv = False if xyb < 0.001: xpa = za za = -xa xa = xpa xpb = zb zb = -xb xb = xpb xyb = sqrt(xb*xb + yb*yb) inv = True costh = xb / xyb sinth = yb / xyb xpa = xa * costh + ya * sinth ypa = ya * costh - xa * sinth sinph = zb * rbc cosph = sqrt(abs(1.0- sinph * sinph)) xqa = xpa * cosph + za * sinph zqa = za * cosph - xpa * sinph yza = sqrt(ypa * ypa + zqa * zqa) if yza < 1e-8: coskh = 1.0 sinkh = 0.0 else: coskh = ypa / yza sinkh = zqa / yza # Apply the peptide bond conformation if symbol != "P": if name == "N " and not init_pos: t = self.prev_psi + 0.0 if name == "O ": t = psi + 180.0 if name == "HA " or name == "HA2": t = 120.0 + phi if name == "CB " or name == "HA3": t = 240.0 + phi if name == "C ": t = phi else: # proline if name == "N " and not init_pos: t = self.prev_psi + 0.0 if name == "O ": t = psi + 180.0 if name == "CA ": t = phi - 120.0 if name == "CD ": t = phi + 60.0 sina = sin(DEG2RAD * a) sind = -sin(DEG2RAD * t) cosd = cos(DEG2RAD * t) # Apply the bond length. xd = r * cosa yd = r * sina * cosd zd = r * sina * sind # Compute the atom position using bond and torsional angles. ypd = yd * coskh - zd * sinkh zpd = zd * coskh + yd * sinkh xpd = xd * cosph - zpd * sinph zqd = zpd * cosph + xd * sinph xqd = xpd * costh - ypd * sinth yqd = ypd * costh + xpd * sinth if inv: tmp = -zqd zqd = xqd xqd = tmp self.coords[n][0] = xqd + self.coords[atom_c][0] self.coords[n][1] = yqd + self.coords[atom_c][1] self.coords[n][2] = zqd + self.coords[atom_c][2] if self.nterm_hydrogen: # It is a hack for the first hydrogen atom # to make sure the bond length is correct. self.nterm_hydrogen.setposn( self.nterm_hydrogen.posn() + 0.325 * norm(V(xqd, yqd, zqd))) self.nterm_hydrogen = None ax = self.coords[n][0] ay = self.coords[n][1] az = self.coords[n][2] # Store previous coordinates for the next building step if not init_pos: if name=="N ": self.prev_coords[0][0] = self.coords[n][0] self.prev_coords[0][1] = self.coords[n][1] self.prev_coords[0][2] = self.coords[n][2] if name=="CA ": self.prev_coords[1][0] = self.coords[n][0] self.prev_coords[1][1] = self.coords[n][1] self.prev_coords[1][2] = self.coords[n][2] if name=="C ": self.prev_coords[2][0] = self.coords[n][0] self.prev_coords[2][1] = self.coords[n][1] self.prev_coords[2][2] = self.coords[n][2] # Add a new atom to the molecule atom = Atom( atom_name, V(self.coords[n][0], self.coords[n][1], self.coords[n][2]), mol) # Create temporary attributes for proper bond assignment. atom._is_aromatic = False atom._is_single = False if atom_type == "sp2a": atom_type = "sp2" atom._is_aromatic = True if atom_type == "sp2s": atom_type = "sp2" atom._is_single = True atom.set_atomtype_but_dont_revise_singlets(atom_type) if name == "CA ": # Set c-alpha flag for protein main chain visualization. atom._protein_ca = True else: atom._protein_ca = False if name == "CB ": # Set c-alpha flag for protein main chain visualization. atom._protein_cb = True else: atom._protein_cb = False if name == "N ": # Set c-alpha flag for protein main chain visualization. atom._protein_n = True else: atom._protein_n = False if name == "C ": # Set c-alpha flag for protein main chain visualization. atom._protein_c = True else: atom._protein_c = False if name == "O ": # Set c-alpha flag for protein main chain visualization. atom._protein_o = True else: atom._protein_o = False # debug - output in PDB format # print "ATOM %5d %-3s %3s %c%4d %8.3f%8.3f%8.3f" % ( n, name, "ALA", ' ', res_num, coords[n][0], coords[n][1], coords[n][2]) self.prev_psi = psi # Remember previous psi angle. self.length += 1 # Increase the amino acid counter. return
def getSphereTriStrips(level): steps = 2**level points = [] # Triangle Strip vertices o be returned. # Construct an icosahedron with two vertices at the North and South Poles, # +-1 on the Y axis, as you look toward the X-Y plane with the Z axis # pointing out at you. The "middle ring" vertices are all at the same # +-latitudes, on the intersection circles of the globe with a polar-axis # cylinder of the proper radius. # # The third "master vertex" of the icosahedron is placed on the X-Y plane, # which intersects the globe at the Greenwich Meridian (the semi-circle at # longitude 0, through Greenwich Observatory, 5 miles south-east of London.) # # The X (distance from the polar axis) and Y (height above the equatorial # plane) of the master vertex make a "golden rectangle", one unit high by # "phi" (1.6180339887498949) wide. We normalize this to put it on the # unit-radius sphere, and take the distance from the axis as the cylinder # radius used to generate the rest of the vertices of the two middle rings. # # Plotted on the globe, the master vertex (first vertex of the North ring) # is lat-long 31.72,0 due south of London in Africa, about 45 miles # south-southwest of Benoud, Algeria. The first vertex of the south ring is # rotated 1/10 of a circle east, at lat-long -31.72,36 in the south end of # the Indian Ocean, about 350 miles east-southeast of Durban, South Africa. # vert0 = norm(V(phi, 1, 0)) # Project the "master vertex" onto a unit sphere. cylRad = vert0[0] # Icos vertex distance from the Y axis. ringLat = atan2(vert0[1], vert0[0]) * degreesPerRadian # Latitude +-31.72 . # Basic triangle-strip icosahedron vertices. Start and end with the Poles. # Reflect the master vertex into the southern hemisphere and rotate 5 copies # to make the middle rings of 5 vertices at North and South latitudes. p2_5 = 2 * pi / 5.0 # Simplify indexing by replicating the Poles, so everything is in fives. icosRings = [ 5 * [V(0.0, -1.0, 0.0)], # South Pole. # South ring, first edge *centered on* the Greenwich Meridian. [ V(cylRad * cos((i - .5) * p2_5), -vert0[1], cylRad * sin((i - .5) * p2_5)) for i in range(5) ], # North ring, first vertex *on* the Greenwich Meridian. [ V(cylRad * cos(i * p2_5), vert0[1], cylRad * sin(i * p2_5)) for i in range(5) ], 5 * [V(0.0, 1.0, 0.0)] ] # North Pole. # Three bands, going from bottom to top (South to North.) for band in range(3): lowerRing = icosRings[band] upperRing = icosRings[band + 1] # Subdivide bands into sub-bands. When level == 0, steps == 1, # subBand == 0, and we get just the icosahedron out. (Really!) for subBand in range(steps): # Account for the tapering-in at the poles, making less points on # one edge of a sub-band than there are on the other edge. botOffset = 0 if band is 0: # South. botSteps = max(subBand, 1) # Don't divide by zero. topSteps = subBand + 1 # Collapse the *first* triangle of south sub-band bottom edges. botOffset = -1 elif band is 1: # Middle. botSteps = topSteps = steps else: # band is 2: North. botSteps = steps - subBand topSteps = max(steps - (subBand + 1), 1) pass subBandSteps = max(botSteps, topSteps) # Do five segments, clockwise around the North Pole (East to West.) for seg in range(5): nextseg = (seg + 1) % 5 # Wrap-around. # Interpolate ends of bottom & top edges of a sub-band segment. fractBot = float(subBand) / float(steps) fractTop = float(subBand + 1) / float(steps) sbBotRight = fractBot * upperRing[seg] + \ (1.0-fractBot) * lowerRing[seg] sbTopRight = fractTop * upperRing[seg] + \ (1.0-fractTop) * lowerRing[seg] sbBotLeft = fractBot * upperRing[nextseg] + \ (1.0-fractBot) * lowerRing[nextseg] sbTopLeft = fractTop * upperRing[nextseg] + \ (1.0-fractTop) * lowerRing[nextseg] # Output the right end of the first segment of the sub-band. # We'll end up wrapping around to this same pair of points at # the left end of the last segment of the sub-band. if seg == 0: # Project verts from icosahedron faces onto the unit sphere. points += [norm(sbBotRight), norm(sbTopRight)] # Step across the sub-band edges from right to left, # stitching triangle pairs from their lower to upper edges. for step in range(1, subBandSteps + 1): # Interpolate step point pairs along the sub-band edges. fractLower = float(step + botOffset) / float(botSteps) lower = fractLower * sbBotLeft + \ (1.0-fractLower) * sbBotRight # Collapse the *last* triangle of north sub-band top edges. fractUpper = float(min(step, topSteps)) / float(topSteps) upper = fractUpper * sbTopLeft + \ (1.0-fractUpper) * sbTopRight # Output verts, projected from icos faces onto unit sphere. points += [norm(lower), norm(upper)] continue # step continue # seg continue # subBand continue # band return points
def _buildResiduum(self, mol, zmatrix, n_atoms, phi, psi, init_pos, symbol): """ Builds cartesian coordinates for an amino acid from the internal coordinates table. mol is a chunk to which the amino acid will be added. zmatrix is an internal coordinates array corresponding to a given amino acid. n_atoms is a number of atoms to be build + 3 dummy atoms. phi is a peptide bond PHI angle. psi is a peptide bond PSI angle. init_pos are optional postions of previous CA, C and O atoms. symbol is a current amino acid symbol (used for proline case) Note: currently, it doesn't rebuild bonds, so inferBonds has to be called after. Unfortunately, the proper bond order can not be correctly recognized this way. """ if mol == None: return if not init_pos: # assign three previous atom positions for i in range(0, 3): self.coords[i][0] = self.prev_coords[i][0] self.coords[i][1] = self.prev_coords[i][1] self.coords[i][2] = self.prev_coords[i][2] else: # if no prev_coords are given, compute the first three atom positions num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[1] self.coords[0][0] = 0.0 self.coords[0][1] = 0.0 self.coords[0][2] = 0.0 self.coords[1][0] = r self.coords[1][1] = 0.0 self.coords[1][2] = 0.0 ccos = cos(DEG2RAD * a) num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[2] if atom_c == 1: self.coords[2][0] = self.coords[0][0] + r * ccos else: self.coords[2][0] = self.coords[0][0] - r * ccos self.coords[2][1] = r * sin(DEG2RAD * a) self.coords[2][2] = 0.0 for i in range(0, 3): self.prev_coords[i][0] = self.coords[i][0] + init_pos[0] self.prev_coords[i][1] = self.coords[i][1] + init_pos[1] self.prev_coords[i][2] = self.coords[i][2] + init_pos[2] for n in range(3, n_atoms): # Generate all coordinates using three previous atoms # as a frame of reference, num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[n] cosa = cos(DEG2RAD * a) xb = self.coords[atom_b][0] - self.coords[atom_c][0] yb = self.coords[atom_b][1] - self.coords[atom_c][1] zb = self.coords[atom_b][2] - self.coords[atom_c][2] rbc = 1.0 / sqrt(xb * xb + yb * yb + zb * zb) if abs(cosa) >= 0.999: # Linear bond case # Skip angles, just extend along the bond. rbc = r * rbc * cosa self.coords[n][0] = self.coords[atom_c][0] + xb * rbc self.coords[n][1] = self.coords[atom_c][1] + yb * rbc self.coords[n][2] = self.coords[atom_c][2] + zb * rbc else: xa = self.coords[atom_a][0] - self.coords[atom_c][0] ya = self.coords[atom_a][1] - self.coords[atom_c][1] za = self.coords[atom_a][2] - self.coords[atom_c][2] xyb = sqrt(xb * xb + yb * yb) inv = False if xyb < 0.001: xpa = za za = -xa xa = xpa xpb = zb zb = -xb xb = xpb xyb = sqrt(xb * xb + yb * yb) inv = True costh = xb / xyb sinth = yb / xyb xpa = xa * costh + ya * sinth ypa = ya * costh - xa * sinth sinph = zb * rbc cosph = sqrt(abs(1.0 - sinph * sinph)) xqa = xpa * cosph + za * sinph zqa = za * cosph - xpa * sinph yza = sqrt(ypa * ypa + zqa * zqa) if yza < 1e-8: coskh = 1.0 sinkh = 0.0 else: coskh = ypa / yza sinkh = zqa / yza # Apply the peptide bond conformation if symbol != "P": if name == "N " and not init_pos: t = self.prev_psi + 0.0 if name == "O ": t = psi + 180.0 if name == "HA " or name == "HA2": t = 120.0 + phi if name == "CB " or name == "HA3": t = 240.0 + phi if name == "C ": t = phi else: # proline if name == "N " and not init_pos: t = self.prev_psi + 0.0 if name == "O ": t = psi + 180.0 if name == "CA ": t = phi - 120.0 if name == "CD ": t = phi + 60.0 sina = sin(DEG2RAD * a) sind = -sin(DEG2RAD * t) cosd = cos(DEG2RAD * t) # Apply the bond length. xd = r * cosa yd = r * sina * cosd zd = r * sina * sind # Compute the atom position using bond and torsional angles. ypd = yd * coskh - zd * sinkh zpd = zd * coskh + yd * sinkh xpd = xd * cosph - zpd * sinph zqd = zpd * cosph + xd * sinph xqd = xpd * costh - ypd * sinth yqd = ypd * costh + xpd * sinth if inv: tmp = -zqd zqd = xqd xqd = tmp self.coords[n][0] = xqd + self.coords[atom_c][0] self.coords[n][1] = yqd + self.coords[atom_c][1] self.coords[n][2] = zqd + self.coords[atom_c][2] if self.nterm_hydrogen: # It is a hack for the first hydrogen atom # to make sure the bond length is correct. self.nterm_hydrogen.setposn(self.nterm_hydrogen.posn() + 0.325 * norm(V(xqd, yqd, zqd))) self.nterm_hydrogen = None ax = self.coords[n][0] ay = self.coords[n][1] az = self.coords[n][2] # Store previous coordinates for the next building step if not init_pos: if name == "N ": self.prev_coords[0][0] = self.coords[n][0] self.prev_coords[0][1] = self.coords[n][1] self.prev_coords[0][2] = self.coords[n][2] if name == "CA ": self.prev_coords[1][0] = self.coords[n][0] self.prev_coords[1][1] = self.coords[n][1] self.prev_coords[1][2] = self.coords[n][2] if name == "C ": self.prev_coords[2][0] = self.coords[n][0] self.prev_coords[2][1] = self.coords[n][1] self.prev_coords[2][2] = self.coords[n][2] # Add a new atom to the molecule atom = Atom( atom_name, V(self.coords[n][0], self.coords[n][1], self.coords[n][2]), mol) # Create temporary attributes for proper bond assignment. atom._is_aromatic = False atom._is_single = False if atom_type == "sp2a": atom_type = "sp2" atom._is_aromatic = True if atom_type == "sp2s": atom_type = "sp2" atom._is_single = True atom.set_atomtype_but_dont_revise_singlets(atom_type) if name == "CA ": # Set c-alpha flag for protein main chain visualization. atom._protein_ca = True else: atom._protein_ca = False if name == "CB ": # Set c-alpha flag for protein main chain visualization. atom._protein_cb = True else: atom._protein_cb = False if name == "N ": # Set c-alpha flag for protein main chain visualization. atom._protein_n = True else: atom._protein_n = False if name == "C ": # Set c-alpha flag for protein main chain visualization. atom._protein_c = True else: atom._protein_c = False if name == "O ": # Set c-alpha flag for protein main chain visualization. atom._protein_o = True else: atom._protein_o = False # debug - output in PDB format # print "ATOM %5d %-3s %3s %c%4d %8.3f%8.3f%8.3f" % ( n, name, "ALA", ' ', res_num, coords[n][0], coords[n][1], coords[n][2]) self.prev_psi = psi # Remember previous psi angle. self.length += 1 # Increase the amino acid counter. return
def drawDnaRibbons(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = None, ribbon2_start_point = None, ribbon1_direction = None, ribbon2_direction = None, peakDeviationFromCenter = 9.5, ribbonThickness = 2.0, ribbon1Color = None, ribbon2Color = None, stepColor = None): """ Draw DNA ribbons where each strand is represented as a ribbon. DNA ribbons are drawn as sine waves with appropriate phase angles, with the phase angles computed in this method. @param endCenter1: Axis end 1 @type endCenter1: B{V} @param endCenter2: Axis end 2 @type endCenter2: B{V} @param basesPerTurn: Number of bases in a full turn. @type basesPerTurn: float @param duplexRise: Center to center distance between consecutive steps @type duplexRise: float @param glpaneScale: GLPane scale used in scaling arrow head drawing @type glpaneScale: float @param lineOfSightVector: Glpane lineOfSight vector, used to compute the the vector along the ladder step. @type: B{V} @param displayStyle: Rubberband display style (specified as an integer) see comment in the method below. See also GLpane.displayStyle. @type displayStyle: int @param peakDeviationFromCenter: Distance of a peak from the axis Also known as 'Amplitude' of a sine wave. @type peakDeviationFromCenter: float @param ribbonThickness: Thickness of each of the the two ribbons @type ribbonThickness: float @param ribbon1Color: Color of ribbon1 @param ribbon2Color: Color of ribbon2 @see: B{DnaLineMode.Draw } (where it is used) for comments on color convention TODO: as of 2008-04-22 - Need more documentation - This method is long mainly because of a number of custom drawing See if that can be refactored e.g. methods like _drawRibbon1/strand1, drawRibbon2 / strand2 etc. - Further optimization / refactoring (low priority) """ #Try to match the rubberband display style as closely as possible to #either the glpane's current display or the chunk display of the segment #being edited. The caller should do the job of specifying the display style #it desires. As of 2008-02-20, this method only supports following display #styles --Tubes, Ball and Stick, CPK and lines. the sphere radius #for ball and stick or CPK is calculated approximately. if displayStyle == diTrueCPK: SPHERE_RADIUS = 3.5 ribbonThickness = 2.0 elif displayStyle == diTUBES: SPHERE_RADIUS = 0.01 ribbonThickness = 5.0 elif displayStyle == diLINES: #Lines display and all other unsupported display styles SPHERE_RADIUS = 0.01 ribbonThickness = 1.0 else: #ball and stick display style. All other unsupported displays #will be rendered in ball and stick display style SPHERE_RADIUS = 1.0 ribbonThickness = 3.0 ribbonLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ribbonLength is at least equal to the duplexRise. # i.e. do the drawing only when there are at least two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint if ribbonLength < duplexRise: return unitVectorAlongLength = norm(endCenter2 - endCenter1) ############## pointOnAxis = endCenter1 axial_shift_1 = V(0.0, 0.0, 0.0) # might be changed below axial_shift_2 = V(0.0, 0.0, 0.0) # [these might be discarded and recomputed just below; # the case where they aren't is (and I think was) untested. # -- bruce 080422 comment] vectorAlongLadderStep = cross(-lineOfSightVector, unitVectorAlongLength) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 numberOfBasesDrawn = 0 theta_offset = 0 x = 0 ### #Formula .. Its a Sine Wave. # y(x) = A.sin(2*pi*f*x + phase_angle) ------[1] # where -- # f = 1/T # A = Amplitude of the sine wave (or 'peak deviation from center') # y = y coordinate of the sine wave -- distance is in Angstroms # x = the x coordinate # phase_angle is computed for each wave. We know y at x =0. For example, # for ribbon_1, , at x = 0, y = A. Putting these values in equation [1] # we get the phase_angle. Similarly, for ribbon_2, at x = 0, y = -6 # Putting these values will give use the phase_angle_2. # Note that for ribbon2_point, we subtract the value of equation [1] from # the point on axis. x = 0.0 T = duplexRise * basesPerTurn # The 'Period' of the sine wave # (i.e. peak to peak distance between consecutive crests) amplitude = peakDeviationFromCenter amplitudeVector = unitVectorAlongLadderStep * amplitude depthVector = unitDepthVector * amplitude # Note: to reduce the effect of perspective view on rung direction, # we could multiply depthVector by 0.1 or 0.01. But this would lessen # the depth realism of line/sphere intersections. [bruce 080216] ### if ribbon1_start_point is not None: ribbon1_point = ribbon1_start_point else: if ribbon2_start_point is not None: ribbon1_point = _get_ribbon_point_on_other_ribbon( ribbon2_start_point, ribbon2_direction, endCenter1, unitVectorAlongLength) else: phase_angle_ribbon_1 = HALF_PI theta_ribbon_1 = (TWICE_PI * x / T) + phase_angle_ribbon_1 #Initialize ribbon1_point and ribbon2_point ribbon1_point = pointOnAxis + \ amplitudeVector * sin(theta_ribbon_1) + \ depthVector * cos(theta_ribbon_1) ribbon1_direction = +1 drawDnaSingleRibbon(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = ribbon1_point, ribbon1_direction = ribbon1_direction, peakDeviationFromCenter = peakDeviationFromCenter, ribbonThickness = ribbonThickness, ribbon1Color = ribbon1Color, stepColor = stepColor) if ribbon2_start_point is not None: ribbon2_point = ribbon2_start_point else: if ribbon1_start_point is not None: ribbon2_point = _get_ribbon_point_on_other_ribbon( ribbon1_start_point, ribbon1_direction, endCenter1, unitVectorAlongLength) else: phase_angle_ribbon_2 = asin(-6.0/(amplitude)) theta_ribbon_2 = (TWICE_PI * x / T) - phase_angle_ribbon_2 ribbon2_point = pointOnAxis - \ amplitudeVector * sin(theta_ribbon_2) + \ depthVector * cos(theta_ribbon_2) ribbon2_direction = -1 drawDnaSingleRibbon(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = ribbon2_point, ribbon1_direction = ribbon2_direction, peakDeviationFromCenter = peakDeviationFromCenter, ribbonThickness = ribbonThickness, ribbon1Color = ribbon2Color, stepColor = stepColor) del vectorAlongLadderStep return
def _buildResidue(self, mol, zmatrix, n_atoms, idx, phi, psi, secondary, init_pos, residue_name, fake_chain=False): """ Builds cartesian coordinates for an amino acid from the internal coordinates table. @param mol: a chunk to which the amino acid will be added. @type mol: Chunk @param zmatrix: is an internal coordinates array corresponding to a given amino acid. @type zmatrix: list @param n_atoms: size of z-matrix (a number of atoms to be build + 3 dummy atoms) @type n_atoms: int @param idx: is a residue index (1..length). @type idx: integer @param phi, psi: peptide bond phi and psi angles @type phi, psi: float @param init_pos: optional postions of previous CA, C and O atoms. @type init_pos: V @param symbol: current amino acid symbol (used to derermine proline case) @type symbol: string """ # note: currently, it doesn't rebuild bonds, so inferBonds has to be # called after this method. Unfortunately, the proper bond order can # not be correctly recognized this way. Therefore, temporary atom flags # _is_aromatic and _is_single are used. #this code was re-factored by EricM and internal-to-cartesian # conversion method was moved to geometry.InternalCoordinatesToCartesian if mol is None: return if not init_pos: # assign three previous atom positions coords = self.prev_coords else: # if no prev_coords are given, compute the first three atom positions coords = zeros([3,3], Float) num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[1] coords[0][0] = 0.0; coords[0][1] = 0.0; coords[0][2] = 0.0; coords[1][0] = r; coords[1][1] = 0.0; coords[1][2] = 0.0; ccos = cos(DEG2RAD*a) num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[2] if atom_c == 1: coords[2][0] = coords[0][0] + r*ccos else: coords[2][0] = coords[0][0] - r*ccos coords[2][1] = r * sin(DEG2RAD*a) coords[2][2] = 0.0 for i in range (0, 3): self.prev_coords[i][0] = coords[i][0] + init_pos[0] self.prev_coords[i][1] = coords[i][1] + init_pos[1] self.prev_coords[i][2] = coords[i][2] + init_pos[2] translator = InternalCoordinatesToCartesian(n_atoms, coords) for n in range (3, n_atoms): # Generate all coordinates using three previous atoms # as a frame of reference, num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[n] # Apply the peptide bond conformation if residue_name != "PRO": if name == "N " and not init_pos: t = self.prev_psi + 0.0 if name == "O ": t = psi + 180.0 if name == "HA " or name == "HA2": t = 120.0 + phi if name == "CB " or name == "HA3": t = 240.0 + phi if name == "C ": t = phi else: # proline if name == "N " and not init_pos: t = self.prev_psi + 0.0 if name == "O ": t = psi + 180.0 if name == "CA ": t = phi - 120.0 if name == "CD ": t = phi + 60.0 translator.addInternal(n+1, atom_c+1, atom_b+1, atom_a+1, r, a, t) xyz = translator.getCartesian(n+1) if self.nterm_hydrogen: # This is a hack for the first hydrogen atom # to make sure the bond length is correct. self.nterm_hydrogen.setposn( self.nterm_hydrogen.posn() + \ 0.325 * norm(xyz)) self.nterm_hydrogen = None # Store previous coordinates for the next building step if not init_pos: if name=="N ": self.prev_coords[0][0] = xyz[0] self.prev_coords[0][1] = xyz[1] self.prev_coords[0][2] = xyz[2] if name=="CA ": self.prev_coords[1][0] = xyz[0] self.prev_coords[1][1] = xyz[1] self.prev_coords[1][2] = xyz[2] if name=="C ": self.prev_coords[2][0] = xyz[0] self.prev_coords[2][1] = xyz[1] self.prev_coords[2][2] = xyz[2] # Add a new atom to the molecule if not fake_chain or \ name == "CA ": atom = Atom( atom_name, xyz, mol) if not self.init_ca and \ name == "CA ": self.init_ca = atom if mol.protein: aa = mol.protein.add_pdb_atom(atom, name.replace(' ',''), idx, AA_3_TO_1[residue_name]) atom.pdb_info = {} atom.pdb_info['atom_name'] = name.replace(' ','') atom.pdb_info['residue_name'] = residue_name residue_id = "%3d " % idx atom.pdb_info['residue_id'] = residue_id atom.pdb_info['standard_atom'] = True atom.pdb_info['chain_id'] = True if aa: aa.set_secondary_structure(secondary) # Create temporary attributes for proper bond assignment. atom._is_aromatic = False atom._is_single = False if atom_type == "sp2a": atom_type = "sp2" atom._is_aromatic = True if atom_type == "sp2s": atom_type = "sp2" atom._is_single = True atom.set_atomtype_but_dont_revise_singlets(atom_type) ### debug - output in PDB format ### print "ATOM %5d %-3s %3s %c%4d %8.3f%8.3f%8.3f" % ( n, name, "ALA", ' ', res_num, xyz[0], xyz[1], xyz[2]) self.prev_psi = psi # Remember previous psi angle. return
def setup_drawer(): """ Set up the usual constant display lists in the current OpenGL context. WARNING: THIS IS ONLY CORRECT IF ONLY ONE GL CONTEXT CONTAINS DISPLAY LISTS -- or more precisely, only the GL context this has last been called in (or one which shares its display lists) will work properly with the routines in drawer.py, since the allocated display list names are stored in globals set by this function, but in general those names might differ if this was called in different GL contexts. """ #bruce 060613 added docstring, cleaned up display list name allocation # bruce 071030 renamed from setup to setup_drawer spherelistbase = glGenLists(numSphereSizes) sphereList = [] for i in range(numSphereSizes): sphereList += [spherelistbase+i] glNewList(sphereList[i], GL_COMPILE) glBegin(GL_TRIANGLE_STRIP) # GL_LINE_LOOP to see edges. stripVerts = getSphereTriStrips(i) for vertNorm in stripVerts: glNormal3fv(vertNorm) glVertex3fv(vertNorm) continue glEnd() glEndList() continue drawing_globals.sphereList = sphereList # Sphere triangle-strip vertices for each level of detail. # (Cache and re-use the work of making them.) # Can use in converter-wrappered calls like glVertexPointerfv, # but the python arrays are re-copied to C each time. sphereArrays = [] for i in range(numSphereSizes): sphereArrays += [getSphereTriStrips(i)] continue drawing_globals.sphereArrays = sphereArrays # Sphere glDrawArrays triangle-strip vertices for C calls. # (Cache and re-use the work of converting a C version.) # Used in thinly-wrappered calls like glVertexPointer. sphereCArrays = [] for i in range(numSphereSizes): CArray = numpy.array(sphereArrays[i], dtype=numpy.float32) sphereCArrays += [CArray] continue drawing_globals.sphereCArrays = sphereCArrays # Sphere indexed vertices. # (Cache and re-use the work of making the indexes.) # Can use in converter-wrappered calls like glDrawElementsui, # but the python arrays are re-copied to C each time. sphereElements = [] # Pairs of lists (index, verts) . for i in range(numSphereSizes): sphereElements += [indexVerts(sphereArrays[i], .0001)] continue drawing_globals.sphereElements = sphereElements # Sphere glDrawElements index and vertex arrays for C calls. sphereCIndexTypes = [] # numpy index unsigned types. sphereGLIndexTypes = [] # GL index types for drawElements. sphereCElements = [] # Pairs of numpy arrays (Cindex, Cverts) . for i in range(numSphereSizes): (index, verts) = sphereElements[i] if len(index) < 256: Ctype = numpy.uint8 GLtype = GL_UNSIGNED_BYTE else: Ctype = numpy.uint16 GLtype = GL_UNSIGNED_SHORT pass sphereCIndexTypes += [Ctype] sphereGLIndexTypes += [GLtype] sphereCIndex = numpy.array(index, dtype=Ctype) sphereCVerts = numpy.array(verts, dtype=numpy.float32) sphereCElements += [(sphereCIndex, sphereCVerts)] continue drawing_globals.sphereCIndexTypes = sphereCIndexTypes drawing_globals.sphereGLIndexTypes = sphereGLIndexTypes drawing_globals.sphereCElements = sphereCElements if glGetString(GL_EXTENSIONS).find("GL_ARB_vertex_buffer_object") >= 0: # A GLBufferObject version for glDrawArrays. sphereArrayVBOs = [] for i in range(numSphereSizes): vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, sphereCArrays[i], GL_STATIC_DRAW) sphereArrayVBOs += [vbo] continue drawing_globals.sphereArrayVBOs = sphereArrayVBOs # A GLBufferObject version for glDrawElements indexed verts. sphereElementVBOs = [] # Pairs of (IBO, VBO) for i in range(numSphereSizes): ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, sphereCElements[i][0], GL_STATIC_DRAW) vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, sphereCElements[i][1], GL_STATIC_DRAW) sphereElementVBOs += [(ibo, vbo)] continue drawing_globals.sphereElementVBOs = sphereElementVBOs ibo.unbind() vbo.unbind() pass #bruce 060415 drawing_globals.wiresphere1list = wiresphere1list = glGenLists(1) glNewList(wiresphere1list, GL_COMPILE) didlines = {} # don't draw each triangle edge more than once def shoulddoline(v1,v2): # make sure not list (unhashable) or Numeric array (bug in __eq__) v1 = tuple(v1) v2 = tuple(v2) if (v1,v2) not in didlines: didlines[(v1,v2)] = didlines[(v2,v1)] = None return True return False def doline(v1,v2): if shoulddoline(v1,v2): glVertex3fv(v1) glVertex3fv(v2) return glBegin(GL_LINES) ocdec = getSphereTriangles(1) for tri in ocdec: #e Could probably optim this more, e.g. using a vertex array or VBO or # maybe GL_LINE_STRIP. doline(tri[0], tri[1]) doline(tri[1], tri[2]) doline(tri[2], tri[0]) glEnd() glEndList() drawing_globals.CylList = CylList = glGenLists(1) glNewList(CylList, GL_COMPILE) glBegin(GL_TRIANGLE_STRIP) for (vtop, ntop, vbot, nbot) in drawing_globals.cylinderEdges: glNormal3fv(nbot) glVertex3fv(vbot) glNormal3fv(ntop) glVertex3fv(vtop) glEnd() glEndList() drawing_globals.CapList = CapList = glGenLists(1) glNewList(CapList, GL_COMPILE) glNormal3fv(drawing_globals.cap0n) glBegin(GL_POLYGON) for p in drawing_globals.drum0: glVertex3fv(p) glEnd() glNormal3fv(drawing_globals.cap1n) glBegin(GL_POLYGON) #bruce 060609 fix "ragged edge" bug in this endcap: drum1 -> drum2 for p in drawing_globals.drum2: glVertex3fv(p) glEnd() glEndList() drawing_globals.diamondGridList = diamondGridList = glGenLists(1) glNewList(diamondGridList, GL_COMPILE) glBegin(GL_LINES) for p in drawing_globals.digrid: glVertex(p[0]) glVertex(p[1]) glEnd() glEndList() drawing_globals.lonsGridList = lonsGridList = glGenLists(1) glNewList(lonsGridList, GL_COMPILE) glBegin(GL_LINES) for p in drawing_globals.lonsEdges: glVertex(p[0]) glVertex(p[1]) glEnd() glEndList() drawing_globals.CubeList = CubeList = glGenLists(1) glNewList(CubeList, GL_COMPILE) glBegin(GL_QUAD_STRIP) # note: CubeList has only 4 faces of the cube; only suitable for use in # wireframes; see also solidCubeList [bruce 051215 comment reporting # grantham 20051213 observation] glVertex((-1,-1,-1)) glVertex(( 1,-1,-1)) glVertex((-1, 1,-1)) glVertex(( 1, 1,-1)) glVertex((-1, 1, 1)) glVertex(( 1, 1, 1)) glVertex((-1,-1, 1)) glVertex(( 1,-1, 1)) glVertex((-1,-1,-1)) glVertex(( 1,-1,-1)) glEnd() glEndList() drawing_globals.solidCubeList = solidCubeList = glGenLists(1) glNewList(solidCubeList, GL_COMPILE) glBegin(GL_QUADS) for i in xrange(len(drawing_globals.cubeIndices)): avenormals = V(0,0,0) #bruce 060302 fixed normals for flat shading for j in xrange(4) : nTuple = tuple( drawing_globals.cubeNormals[drawing_globals.cubeIndices[i][j]]) avenormals += A(nTuple) avenormals = norm(avenormals) for j in xrange(4) : vTuple = tuple( drawing_globals.cubeVertices[drawing_globals.cubeIndices[i][j]]) #bruce 060302 made size compatible with glut.glutSolidCube(1.0) vTuple = A(vTuple) * 0.5 glNormal3fv(avenormals) glVertex3fv(vTuple) glEnd() glEndList() drawing_globals.rotSignList = rotSignList = glGenLists(1) glNewList(rotSignList, GL_COMPILE) glBegin(GL_LINE_STRIP) for ii in xrange(len(drawing_globals.rotS0n)): glVertex3fv(tuple(drawing_globals.rotS0n[ii])) glEnd() glBegin(GL_LINE_STRIP) for ii in xrange(len(drawing_globals.rotS1n)): glVertex3fv(tuple(drawing_globals.rotS1n[ii])) glEnd() glBegin(GL_TRIANGLES) for v in drawing_globals.arrow0Vertices + drawing_globals.arrow1Vertices: glVertex3f(v[0], v[1], v[2]) glEnd() glEndList() drawing_globals.linearArrowList = linearArrowList = glGenLists(1) glNewList(linearArrowList, GL_COMPILE) glBegin(GL_TRIANGLES) for v in drawing_globals.linearArrowVertices: glVertex3f(v[0], v[1], v[2]) glEnd() glEndList() drawing_globals.linearLineList = linearLineList = glGenLists(1) glNewList(linearLineList, GL_COMPILE) glEnable(GL_LINE_SMOOTH) glBegin(GL_LINES) glVertex3f(0.0, 0.0, -drawing_globals.halfHeight) glVertex3f(0.0, 0.0, drawing_globals.halfHeight) glEnd() glDisable(GL_LINE_SMOOTH) glEndList() drawing_globals.circleList = circleList = glGenLists(1) glNewList(circleList, GL_COMPILE) glBegin(GL_LINE_LOOP) for ii in range(60): x = cos(ii*2.0*pi/60) y = sin(ii*2.0*pi/60) glVertex3f(x, y, 0.0) glEnd() glEndList() # piotr 080405 drawing_globals.filledCircleList = filledCircleList = glGenLists(1) glNewList(filledCircleList, GL_COMPILE) glBegin(GL_POLYGON) for ii in range(60): x = cos(ii*2.0*pi/60) y = sin(ii*2.0*pi/60) glVertex3f(x, y, 0.0) glEnd() glEndList() drawing_globals.lineCubeList = lineCubeList = glGenLists(1) glNewList(lineCubeList, GL_COMPILE) glBegin(GL_LINES) cvIndices = [0,1, 2,3, 4,5, 6,7, 0,3, 1,2, 5,6, 4,7, 0,4, 1,5, 2,6, 3,7] for i in cvIndices: glVertex3fv(tuple(drawing_globals.cubeVertices[i])) glEnd() glEndList() # Debug Preferences from utilities.debug_prefs import debug_pref, Choice_boolean_True from utilities.debug_prefs import Choice_boolean_False choices = [Choice_boolean_False, Choice_boolean_True] # 20060314 grantham initial_choice = choices[drawing_globals.allow_color_sorting_default] drawing_globals.allow_color_sorting_pref = debug_pref( "Use Color Sorting?", initial_choice, prefs_key = drawing_globals.allow_color_sorting_prefs_key) #bruce 060323 removed non_debug = True for A7 release, changed default #value to False (far above), and changed its prefs_key so developers #start with the new default value. #russ 080225: Added. initial_choice = choices[drawing_globals.use_color_sorted_dls_default] drawing_globals.use_color_sorted_dls_pref = debug_pref( "Use Color-sorted Display Lists?", initial_choice, prefs_key = drawing_globals.use_color_sorted_dls_prefs_key) #russ 080225: Added. initial_choice = choices[drawing_globals.use_color_sorted_vbos_default] drawing_globals.use_color_sorted_vbos_pref = debug_pref( "Use Color-sorted Vertex Buffer Objects?", initial_choice, prefs_key = drawing_globals.use_color_sorted_vbos_prefs_key) #russ 080403: Added drawing variant selection variants = [ "0. OpenGL 1.0 - glBegin/glEnd tri-strips vertex-by-vertex.", "1. OpenGL 1.1 - glDrawArrays from CPU RAM.", "2. OpenGL 1.1 - glDrawElements indexed arrays from CPU RAM.", "3. OpenGL 1.5 - glDrawArrays from graphics RAM VBO.", "4. OpenGL 1.5 - glDrawElements, verts in VBO, index in CPU.", "5. OpenGL 1.5 - VBO/IBO buffered glDrawElements."] drawing_globals.use_drawing_variant = debug_pref( "GLPane: drawing method", Choice(names = variants, values = range(len(variants)), defaultValue = drawing_globals.use_drawing_variant_default), prefs_key = drawing_globals.use_drawing_variant_prefs_key) # temporarily always print this, while default setting might be in flux, # and to avoid confusion if the two necessary prefs are set differently # [bruce 080305] if (drawing_globals.allow_color_sorting_pref and drawing_globals.use_color_sorted_dls_pref): print "\nnote: this session WILL use color sorted display lists" else: print "\nnote: this session will NOT use color sorted display lists" if (drawing_globals.allow_color_sorting_pref and drawing_globals.use_color_sorted_vbos_pref): print "note: this session WILL use", \ "color sorted Vertex Buffer Objects\n" else: print "note: this session will NOT use", \ "color sorted Vertex Buffer Objects\n" # 20060313 grantham Added use_c_renderer debug pref, can # take out when C renderer used by default. if drawing_globals.quux_module_import_succeeded: initial_choice = choices[drawing_globals.use_c_renderer_default] drawing_globals.use_c_renderer = ( debug_pref("Use native C renderer?", initial_choice, prefs_key = drawing_globals.use_c_renderer_prefs_key)) #bruce 060323 removed non_debug = True for A7 release, and changed # its prefs_key so developers start over with the default value. #initTexture('C:\\Huaicai\\atom\\temp\\newSample.png', 128,128) return # from setup_drawer
def func(x): return ((2 * x * cos(x) - sin(x)) * cos(x) - x + pi / 4.0)
def _buildResidue(self, mol, zmatrix, n_atoms, idx, phi, psi, secondary, init_pos, residue_name, fake_chain=False): """ Builds cartesian coordinates for an amino acid from the internal coordinates table. @param mol: a chunk to which the amino acid will be added. @type mol: Chunk @param zmatrix: is an internal coordinates array corresponding to a given amino acid. @type zmatrix: list @param n_atoms: size of z-matrix (a number of atoms to be build + 3 dummy atoms) @type n_atoms: int @param idx: is a residue index (1..length). @type idx: integer @param phi, psi: peptide bond phi and psi angles @type phi, psi: float @param init_pos: optional postions of previous CA, C and O atoms. @type init_pos: V @param symbol: current amino acid symbol (used to derermine proline case) @type symbol: string """ # note: currently, it doesn't rebuild bonds, so inferBonds has to be # called after this method. Unfortunately, the proper bond order can # not be correctly recognized this way. Therefore, temporary atom flags # _is_aromatic and _is_single are used. #this code was re-factored by EricM and internal-to-cartesian # conversion method was moved to geometry.InternalCoordinatesToCartesian if mol is None: return if not init_pos: # assign three previous atom positions coords = self.prev_coords else: # if no prev_coords are given, compute the first three atom positions coords = zeros([3, 3], Float) num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[1] coords[0][0] = 0.0 coords[0][1] = 0.0 coords[0][2] = 0.0 coords[1][0] = r coords[1][1] = 0.0 coords[1][2] = 0.0 ccos = cos(DEG2RAD * a) num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[2] if atom_c == 1: coords[2][0] = coords[0][0] + r * ccos else: coords[2][0] = coords[0][0] - r * ccos coords[2][1] = r * sin(DEG2RAD * a) coords[2][2] = 0.0 for i in range(0, 3): self.prev_coords[i][0] = coords[i][0] + init_pos[0] self.prev_coords[i][1] = coords[i][1] + init_pos[1] self.prev_coords[i][2] = coords[i][2] + init_pos[2] translator = InternalCoordinatesToCartesian(n_atoms, coords) for n in range(3, n_atoms): # Generate all coordinates using three previous atoms # as a frame of reference, num, name, atom_name, atom_type, \ atom_c, atom_b, atom_a, r, a, t = zmatrix[n] # Apply the peptide bond conformation if residue_name != "PRO": if name == "N " and not init_pos: t = self.prev_psi + 0.0 if name == "O ": t = psi + 180.0 if name == "HA " or name == "HA2": t = 120.0 + phi if name == "CB " or name == "HA3": t = 240.0 + phi if name == "C ": t = phi else: # proline if name == "N " and not init_pos: t = self.prev_psi + 0.0 if name == "O ": t = psi + 180.0 if name == "CA ": t = phi - 120.0 if name == "CD ": t = phi + 60.0 translator.addInternal(n + 1, atom_c + 1, atom_b + 1, atom_a + 1, r, a, t) xyz = translator.getCartesian(n + 1) if self.nterm_hydrogen: # This is a hack for the first hydrogen atom # to make sure the bond length is correct. self.nterm_hydrogen.setposn( self.nterm_hydrogen.posn() + \ 0.325 * norm(xyz)) self.nterm_hydrogen = None # Store previous coordinates for the next building step if not init_pos: if name == "N ": self.prev_coords[0][0] = xyz[0] self.prev_coords[0][1] = xyz[1] self.prev_coords[0][2] = xyz[2] if name == "CA ": self.prev_coords[1][0] = xyz[0] self.prev_coords[1][1] = xyz[1] self.prev_coords[1][2] = xyz[2] if name == "C ": self.prev_coords[2][0] = xyz[0] self.prev_coords[2][1] = xyz[1] self.prev_coords[2][2] = xyz[2] # Add a new atom to the molecule if not fake_chain or \ name == "CA ": atom = Atom(atom_name, xyz, mol) if not self.init_ca and \ name == "CA ": self.init_ca = atom if mol.protein: aa = mol.protein.add_pdb_atom(atom, name.replace(' ', ''), idx, AA_3_TO_1[residue_name]) atom.pdb_info = {} atom.pdb_info['atom_name'] = name.replace(' ', '') atom.pdb_info['residue_name'] = residue_name residue_id = "%3d " % idx atom.pdb_info['residue_id'] = residue_id atom.pdb_info['standard_atom'] = True atom.pdb_info['chain_id'] = True if aa: aa.set_secondary_structure(secondary) # Create temporary attributes for proper bond assignment. atom._is_aromatic = False atom._is_single = False if atom_type == "sp2a": atom_type = "sp2" atom._is_aromatic = True if atom_type == "sp2s": atom_type = "sp2" atom._is_single = True atom.set_atomtype_but_dont_revise_singlets(atom_type) ### debug - output in PDB format ### print "ATOM %5d %-3s %3s %c%4d %8.3f%8.3f%8.3f" % ( n, name, "ALA", ' ', res_num, xyz[0], xyz[1], xyz[2]) self.prev_psi = psi # Remember previous psi angle. return
def setup_drawer(): """ Set up the usual constant display lists in the current OpenGL context. WARNING: THIS IS ONLY CORRECT IF ONLY ONE GL CONTEXT CONTAINS DISPLAY LISTS -- or more precisely, only the GL context this has last been called in (or one which shares its display lists) will work properly with the routines in drawer.py, since the allocated display list names are stored in globals set by this function, but in general those names might differ if this was called in different GL contexts. """ #bruce 060613 added docstring, cleaned up display list name allocation # bruce 071030 renamed from setup to setup_drawer spherelistbase = glGenLists(numSphereSizes) sphereList = [] for i in range(numSphereSizes): sphereList += [spherelistbase + i] glNewList(sphereList[i], GL_COMPILE) glBegin(GL_TRIANGLE_STRIP) # GL_LINE_LOOP to see edges. stripVerts = getSphereTriStrips(i) for vertNorm in stripVerts: glNormal3fv(vertNorm) glVertex3fv(vertNorm) continue glEnd() glEndList() continue drawing_globals.sphereList = sphereList # Sphere triangle-strip vertices for each level of detail. # (Cache and re-use the work of making them.) # Can use in converter-wrappered calls like glVertexPointerfv, # but the python arrays are re-copied to C each time. sphereArrays = [] for i in range(numSphereSizes): sphereArrays += [getSphereTriStrips(i)] continue drawing_globals.sphereArrays = sphereArrays # Sphere glDrawArrays triangle-strip vertices for C calls. # (Cache and re-use the work of converting a C version.) # Used in thinly-wrappered calls like glVertexPointer. sphereCArrays = [] for i in range(numSphereSizes): CArray = numpy.array(sphereArrays[i], dtype=numpy.float32) sphereCArrays += [CArray] continue drawing_globals.sphereCArrays = sphereCArrays # Sphere indexed vertices. # (Cache and re-use the work of making the indexes.) # Can use in converter-wrappered calls like glDrawElementsui, # but the python arrays are re-copied to C each time. sphereElements = [] # Pairs of lists (index, verts) . for i in range(numSphereSizes): sphereElements += [indexVerts(sphereArrays[i], .0001)] continue drawing_globals.sphereElements = sphereElements # Sphere glDrawElements index and vertex arrays for C calls. sphereCIndexTypes = [] # numpy index unsigned types. sphereGLIndexTypes = [] # GL index types for drawElements. sphereCElements = [] # Pairs of numpy arrays (Cindex, Cverts) . for i in range(numSphereSizes): (index, verts) = sphereElements[i] if len(index) < 256: Ctype = numpy.uint8 GLtype = GL_UNSIGNED_BYTE else: Ctype = numpy.uint16 GLtype = GL_UNSIGNED_SHORT pass sphereCIndexTypes += [Ctype] sphereGLIndexTypes += [GLtype] sphereCIndex = numpy.array(index, dtype=Ctype) sphereCVerts = numpy.array(verts, dtype=numpy.float32) sphereCElements += [(sphereCIndex, sphereCVerts)] continue drawing_globals.sphereCIndexTypes = sphereCIndexTypes drawing_globals.sphereGLIndexTypes = sphereGLIndexTypes drawing_globals.sphereCElements = sphereCElements if glGetString(GL_EXTENSIONS).find("GL_ARB_vertex_buffer_object") >= 0: # A GLBufferObject version for glDrawArrays. sphereArrayVBOs = [] for i in range(numSphereSizes): vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, sphereCArrays[i], GL_STATIC_DRAW) sphereArrayVBOs += [vbo] continue drawing_globals.sphereArrayVBOs = sphereArrayVBOs # A GLBufferObject version for glDrawElements indexed verts. sphereElementVBOs = [] # Pairs of (IBO, VBO) for i in range(numSphereSizes): ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, sphereCElements[i][0], GL_STATIC_DRAW) vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, sphereCElements[i][1], GL_STATIC_DRAW) sphereElementVBOs += [(ibo, vbo)] continue drawing_globals.sphereElementVBOs = sphereElementVBOs ibo.unbind() vbo.unbind() pass #bruce 060415 drawing_globals.wiresphere1list = wiresphere1list = glGenLists(1) glNewList(wiresphere1list, GL_COMPILE) didlines = {} # don't draw each triangle edge more than once def shoulddoline(v1, v2): # make sure not list (unhashable) or Numeric array (bug in __eq__) v1 = tuple(v1) v2 = tuple(v2) if (v1, v2) not in didlines: didlines[(v1, v2)] = didlines[(v2, v1)] = None return True return False def doline(v1, v2): if shoulddoline(v1, v2): glVertex3fv(v1) glVertex3fv(v2) return glBegin(GL_LINES) ocdec = getSphereTriangles(1) for tri in ocdec: #e Could probably optim this more, e.g. using a vertex array or VBO or # maybe GL_LINE_STRIP. doline(tri[0], tri[1]) doline(tri[1], tri[2]) doline(tri[2], tri[0]) glEnd() glEndList() drawing_globals.CylList = CylList = glGenLists(1) glNewList(CylList, GL_COMPILE) glBegin(GL_TRIANGLE_STRIP) for (vtop, ntop, vbot, nbot) in drawing_globals.cylinderEdges: glNormal3fv(nbot) glVertex3fv(vbot) glNormal3fv(ntop) glVertex3fv(vtop) glEnd() glEndList() drawing_globals.CapList = CapList = glGenLists(1) glNewList(CapList, GL_COMPILE) glNormal3fv(drawing_globals.cap0n) glBegin(GL_POLYGON) for p in drawing_globals.drum0: glVertex3fv(p) glEnd() glNormal3fv(drawing_globals.cap1n) glBegin(GL_POLYGON) #bruce 060609 fix "ragged edge" bug in this endcap: drum1 -> drum2 for p in drawing_globals.drum2: glVertex3fv(p) glEnd() glEndList() drawing_globals.diamondGridList = diamondGridList = glGenLists(1) glNewList(diamondGridList, GL_COMPILE) glBegin(GL_LINES) for p in drawing_globals.digrid: glVertex(p[0]) glVertex(p[1]) glEnd() glEndList() drawing_globals.lonsGridList = lonsGridList = glGenLists(1) glNewList(lonsGridList, GL_COMPILE) glBegin(GL_LINES) for p in drawing_globals.lonsEdges: glVertex(p[0]) glVertex(p[1]) glEnd() glEndList() drawing_globals.CubeList = CubeList = glGenLists(1) glNewList(CubeList, GL_COMPILE) glBegin(GL_QUAD_STRIP) # note: CubeList has only 4 faces of the cube; only suitable for use in # wireframes; see also solidCubeList [bruce 051215 comment reporting # grantham 20051213 observation] glVertex((-1, -1, -1)) glVertex((1, -1, -1)) glVertex((-1, 1, -1)) glVertex((1, 1, -1)) glVertex((-1, 1, 1)) glVertex((1, 1, 1)) glVertex((-1, -1, 1)) glVertex((1, -1, 1)) glVertex((-1, -1, -1)) glVertex((1, -1, -1)) glEnd() glEndList() drawing_globals.solidCubeList = solidCubeList = glGenLists(1) glNewList(solidCubeList, GL_COMPILE) glBegin(GL_QUADS) for i in xrange(len(drawing_globals.cubeIndices)): avenormals = V(0, 0, 0) #bruce 060302 fixed normals for flat shading for j in xrange(4): nTuple = tuple( drawing_globals.cubeNormals[drawing_globals.cubeIndices[i][j]]) avenormals += A(nTuple) avenormals = norm(avenormals) for j in xrange(4): vTuple = tuple(drawing_globals.cubeVertices[ drawing_globals.cubeIndices[i][j]]) #bruce 060302 made size compatible with glut.glutSolidCube(1.0) vTuple = A(vTuple) * 0.5 glNormal3fv(avenormals) glVertex3fv(vTuple) glEnd() glEndList() drawing_globals.rotSignList = rotSignList = glGenLists(1) glNewList(rotSignList, GL_COMPILE) glBegin(GL_LINE_STRIP) for ii in xrange(len(drawing_globals.rotS0n)): glVertex3fv(tuple(drawing_globals.rotS0n[ii])) glEnd() glBegin(GL_LINE_STRIP) for ii in xrange(len(drawing_globals.rotS1n)): glVertex3fv(tuple(drawing_globals.rotS1n[ii])) glEnd() glBegin(GL_TRIANGLES) for v in drawing_globals.arrow0Vertices + drawing_globals.arrow1Vertices: glVertex3f(v[0], v[1], v[2]) glEnd() glEndList() drawing_globals.linearArrowList = linearArrowList = glGenLists(1) glNewList(linearArrowList, GL_COMPILE) glBegin(GL_TRIANGLES) for v in drawing_globals.linearArrowVertices: glVertex3f(v[0], v[1], v[2]) glEnd() glEndList() drawing_globals.linearLineList = linearLineList = glGenLists(1) glNewList(linearLineList, GL_COMPILE) glEnable(GL_LINE_SMOOTH) glBegin(GL_LINES) glVertex3f(0.0, 0.0, -drawing_globals.halfHeight) glVertex3f(0.0, 0.0, drawing_globals.halfHeight) glEnd() glDisable(GL_LINE_SMOOTH) glEndList() drawing_globals.circleList = circleList = glGenLists(1) glNewList(circleList, GL_COMPILE) glBegin(GL_LINE_LOOP) for ii in range(60): x = cos(ii * 2.0 * pi / 60) y = sin(ii * 2.0 * pi / 60) glVertex3f(x, y, 0.0) glEnd() glEndList() # piotr 080405 drawing_globals.filledCircleList = filledCircleList = glGenLists(1) glNewList(filledCircleList, GL_COMPILE) glBegin(GL_POLYGON) for ii in range(60): x = cos(ii * 2.0 * pi / 60) y = sin(ii * 2.0 * pi / 60) glVertex3f(x, y, 0.0) glEnd() glEndList() drawing_globals.lineCubeList = lineCubeList = glGenLists(1) glNewList(lineCubeList, GL_COMPILE) glBegin(GL_LINES) cvIndices = [ 0, 1, 2, 3, 4, 5, 6, 7, 0, 3, 1, 2, 5, 6, 4, 7, 0, 4, 1, 5, 2, 6, 3, 7 ] for i in cvIndices: glVertex3fv(tuple(drawing_globals.cubeVertices[i])) glEnd() glEndList() # Debug Preferences from utilities.debug_prefs import debug_pref, Choice_boolean_True from utilities.debug_prefs import Choice_boolean_False choices = [Choice_boolean_False, Choice_boolean_True] # 20060314 grantham initial_choice = choices[drawing_globals.allow_color_sorting_default] drawing_globals.allow_color_sorting_pref = debug_pref( "Use Color Sorting?", initial_choice, prefs_key=drawing_globals.allow_color_sorting_prefs_key) #bruce 060323 removed non_debug = True for A7 release, changed default #value to False (far above), and changed its prefs_key so developers #start with the new default value. #russ 080225: Added. initial_choice = choices[drawing_globals.use_color_sorted_dls_default] drawing_globals.use_color_sorted_dls_pref = debug_pref( "Use Color-sorted Display Lists?", initial_choice, prefs_key=drawing_globals.use_color_sorted_dls_prefs_key) #russ 080225: Added. initial_choice = choices[drawing_globals.use_color_sorted_vbos_default] drawing_globals.use_color_sorted_vbos_pref = debug_pref( "Use Color-sorted Vertex Buffer Objects?", initial_choice, prefs_key=drawing_globals.use_color_sorted_vbos_prefs_key) #russ 080403: Added drawing variant selection variants = [ "0. OpenGL 1.0 - glBegin/glEnd tri-strips vertex-by-vertex.", "1. OpenGL 1.1 - glDrawArrays from CPU RAM.", "2. OpenGL 1.1 - glDrawElements indexed arrays from CPU RAM.", "3. OpenGL 1.5 - glDrawArrays from graphics RAM VBO.", "4. OpenGL 1.5 - glDrawElements, verts in VBO, index in CPU.", "5. OpenGL 1.5 - VBO/IBO buffered glDrawElements." ] drawing_globals.use_drawing_variant = debug_pref( "GLPane: drawing method", Choice(names=variants, values=range(len(variants)), defaultValue=drawing_globals.use_drawing_variant_default), prefs_key=drawing_globals.use_drawing_variant_prefs_key) # temporarily always print this, while default setting might be in flux, # and to avoid confusion if the two necessary prefs are set differently # [bruce 080305] if (drawing_globals.allow_color_sorting_pref and drawing_globals.use_color_sorted_dls_pref): print "\nnote: this session WILL use color sorted display lists" else: print "\nnote: this session will NOT use color sorted display lists" if (drawing_globals.allow_color_sorting_pref and drawing_globals.use_color_sorted_vbos_pref): print "note: this session WILL use", \ "color sorted Vertex Buffer Objects\n" else: print "note: this session will NOT use", \ "color sorted Vertex Buffer Objects\n" # 20060313 grantham Added use_c_renderer debug pref, can # take out when C renderer used by default. if drawing_globals.quux_module_import_succeeded: initial_choice = choices[drawing_globals.use_c_renderer_default] drawing_globals.use_c_renderer = (debug_pref( "Use native C renderer?", initial_choice, prefs_key=drawing_globals.use_c_renderer_prefs_key)) #bruce 060323 removed non_debug = True for A7 release, and changed # its prefs_key so developers start over with the default value. #initTexture('C:\\Huaicai\\atom\\temp\\newSample.png', 128,128) return # from setup_drawer
def addInternal(self, i, na, nb, nc, r, theta, phi): """ Add another point, given its internal coordinates. Once added via this routine, the cartesian coordinates for the point can be retrieved with getCartesian(). @param i: Index of the point being added. After this call, a call to getCartesian with this index value will succeed. Index values less than 4 are ignored. Index values should be presented here in sequence beginning with 4. @param na: Index value for point A. Point 'i' will be 'r' distance units from point A. @param nb: Index value for point B. Point 'i' will be located such that the angle i-A-B is 'theta' degrees. @param nc: Index value for point C. Point 'i' will be located such that the torsion angle i-A-B-C is 'torsion' degrees. @param r: Radial distance (in same units as resulting cartesian coordinates) between A and i. @param theta: Angle in degrees of i-A-B. @param phi: Torsion angle in degrees of i-A-B-C """ if (i < 4): return if (i != self._nextIndex): raise IndexError, "next index is %d not %r" % (self._nextIndex, i) cos_theta = cos(DEG2RAD * theta) xb = self._coords[nb][0] - self._coords[na][0] yb = self._coords[nb][1] - self._coords[na][1] zb = self._coords[nb][2] - self._coords[na][2] rba = 1.0 / sqrt(xb*xb + yb*yb + zb*zb) if abs(cos_theta) >= 0.999: # Linear case # Skip angles, just extend along A-B. rba = r * rba * cos_theta xqd = xb * rba yqd = yb * rba zqd = zb * rba else: xc = self._coords[nc][0] - self._coords[na][0] yc = self._coords[nc][1] - self._coords[na][1] zc = self._coords[nc][2] - self._coords[na][2] xyb = sqrt(xb*xb + yb*yb) inv = False if xyb < 0.001: # A-B points along the z axis. tmp = zc zc = -xc xc = tmp tmp = zb zb = -xb xb = tmp xyb = sqrt(xb*xb + yb*yb) inv = True costh = xb / xyb sinth = yb / xyb xpc = xc * costh + yc * sinth ypc = yc * costh - xc * sinth sinph = zb * rba cosph = sqrt(abs(1.0- sinph * sinph)) xqa = xpc * cosph + zc * sinph zqa = zc * cosph - xpc * sinph yzc = sqrt(ypc * ypc + zqa * zqa) if yzc < 1e-8: coskh = 1.0 sinkh = 0.0 else: coskh = ypc / yzc sinkh = zqa / yzc sin_theta = sin(DEG2RAD * theta) sin_phi = -sin(DEG2RAD * phi) cos_phi = cos(DEG2RAD * phi) # Apply the bond length. xd = r * cos_theta yd = r * sin_theta * cos_phi zd = r * sin_theta * sin_phi # Compute the atom position using bond and torsional angles. ypd = yd * coskh - zd * sinkh zpd = zd * coskh + yd * sinkh xpd = xd * cosph - zpd * sinph zqd = zpd * cosph + xd * sinph xqd = xpd * costh - ypd * sinth yqd = ypd * costh + xpd * sinth if inv: tmp = -zqd zqd = xqd xqd = tmp self._coords[i][0] = xqd + self._coords[na][0] self._coords[i][1] = yqd + self._coords[na][1] self._coords[i][2] = zqd + self._coords[na][2] self._nextIndex = self._nextIndex + 1