Package Pmv :: Module extruder
[hide private]
[frames] | no frames]

Source Code for Module Pmv.extruder

  1  ############################################################################# 
  2  # 
  3  # Author: Sophie COON, Kevin CHAN, Michel F. SANNER 
  4  # 
  5  # Copyright: M. Sanner TSRI 2000 
  6  # 
  7  ############################################################################# 
  8   
  9  # $Header: /opt/cvs/python/packages/share1.5/Pmv/extruder.py,v 1.27.2.2 2007/09/08 00:05:55 mgltools Exp $ 
 10  # 
 11  # $Id: extruder.py,v 1.27.2.2 2007/09/08 00:05:55 mgltools Exp $ 
 12  # 
 13   
 14  import Numeric, math 
 15  from Pmv import Ribbon 
 16  from DejaVu.Shapes import Rectangle2D 
 17   
 18  from opengltk.OpenGL import GL 
 19  #from opengltk.extent.utillib import glTriangleNormals 
 20  from geomutils.geomalgorithms import TriangleNormals 
 21  # Gotta move this class in DejaVu not dependent on MolKit any longer 
22 -class Sheet2D:
23 """ Class implementing a set of method to compute a path3D, normals, 24 binormals and transformation matrices given a 2 sets of control points 25 coordinates. (ctrl points and torsion ctrl points) 26 """
27 - def compute(self, coords , isHelix, nbrib = 2, 28 nbchords = 10, width = 1.5, offset = 1.2, off_c = 0.5):
29 """ """ 30 self.nrib = nbrib 31 self.coords = coords 32 natoms = len(self.coords) 33 self.width = width 34 self.chords = nbchords 35 self.offset = offset 36 self.isHelix = isHelix 37 # Create a ribbon2D object 38 self.smooth = Ribbon.ribbon2D(nbrib, width, nbchords, 39 offset, natoms, coords, 40 isHelix, off_c) 41 self.oldsmooth = self.smooth 42 self.addFirstLastPoints() 43 self.verts2D_flat = Numeric.array(Numeric.reshape(self.smooth, 44 (-1,4))[:,:3]) 45 46 path = (self.smooth[0,:,:3] + self.smooth[1,:,:3])*0.5 47 self.path = path.astype('f') 48 self.faces2D = self.computeFaces2D() 49 binormals = self.computeBinormals() 50 normals = self.computeNormals() 51 self.matrixTransfo= self.buildTransformationMatrix(binormals, normals)
52
53 - def interpolateSmoothArray(self, first, last, nPts):
54 """Insert self.chord-1 points into self.smooth such that each residue 55 is represented by exactly self.nchords points""" 56 57 # create array to hold new points 58 beg = Numeric.ones( (self.nrib, nPts, 4) ).astype('f') 59 60 # set all points to the coordinates of first point in each rib 61 beg = beg * Numeric.reshape( self.smooth[:,first], (self.nrib,1,4) ) 62 # compute vectors from first to second point for each rib 63 # and divide by number of intervals 64 vec = (self.smooth[:,last] - self.smooth[:,first]) / nPts 65 66 # resize vector 67 vec1 = Numeric.resize( vec[0], (nPts, 4) ) 68 vec2 = Numeric.resize( vec[1], (nPts, 4) ) 69 vec = Numeric.concatenate( (vec1, vec2) ) 70 vec.shape = (self.nrib, nPts, 4) 71 72 scale = Numeric.arrayrange(nPts) 73 scale.shape = (1,nPts,1) 74 75 # add it 0,1,2,3 ... nchord-1 times to the new points 76 return beg + vec*scale
77
78 - def addFirstLastPoints(self):
79 last = self.smooth.shape[1] 80 81 ar2 = self.interpolateSmoothArray(last-2, last-1, self.chords) 82 self.smooth = Numeric.concatenate((self.smooth[:, :-2, :], 83 ar2, self.smooth[:, -1:, :] ), 84 1)
85
86 - def computeFaces2D(self):
87 f = [] 88 n = self.smooth.shape[1] 89 f = map(lambda x, n1 = n: (x,x+n1,x+n1+1,x+1), 90 range(self.smooth.shape[1]-1)) 91 faces2D = Numeric.array(f).astype('i') 92 return faces2D
93
94 - def computeBinormals(self):
95 f = Numeric.array(self.faces2D[:,:3]) 96 binorm = TriangleNormals(self.verts2D_flat, 97 f, 'PER_VERTEX') 98 binorm[self.smooth.shape[1]-1,:] = binorm[self.smooth.shape[1]-2,:] 99 binorm1 = binorm[:self.smooth.shape[1]] 100 return binorm1
101
102 - def computeNormals(self):
103 normals = self.smooth[1,:,:3] - self.smooth[0,:,:3] 104 normals = normals/self.width 105 normals = normals.astype('f') 106 return normals
107
108 - def buildTransformationMatrix(self, binormals, normals):
109 matrixTransfo = Numeric.zeros( (len(self.path), 3, 3) ).astype('f') 110 for i in range(len(self.path)): 111 matrixTransfo[i][0] = normals[i] 112 matrixTransfo[i][1] = binormals[i] 113 matrixTransfo[i][2] = self.path[i] 114 return matrixTransfo
115 116
117 -def getAverage(elements):
118 """Function to get the average of a list of elements""" 119 average = Numeric.array([0,0,0]) 120 for el in elements: 121 average = average + Numeric.array(el) 122 average = average/len(elements) 123 average = list(average) 124 return average
125 126 127 128 ###################################################################### 129 ### ### 130 ### CLASSES TO DEFINE EXTRUSION ### 131 ### ### 132 ###################################################################### 133
134 -class ExtrudeObject:
135 """ 136 Base class to take a shape and extrude it along a 3D path. 137 """ 138
139 - def __init__(self, path3D, matrix, shape, cap1 = 0, cap2 = 0, arrow = 0, 140 larrow = 3, warrow = 2):
141 """ 142 Constructor: Takes as arguments a path3D, matrix, 2D shape, and 143 optional cap1, cap2, and arrow. Calls getextrudeVertices() and 144 getFaces() and stores the return values in self.vertices, self.vnormals 145 , and self.faces. 146 """ 147 self.path3D = path3D 148 self.matrix = matrix 149 self.shape = shape 150 self.arrow = arrow 151 if not isinstance(self.shape, Rectangle2D): self.arrow = 0 152 self.larrow = larrow 153 self.warrow = warrow 154 self.cap1 = cap1 155 self.cap2 = cap2 156 if self.arrow: self.cap2 = 0 # no end cap if arrow 157 self.norms = matrix[:,0] 158 self.vertices, self.vnormals = self.getextrudeVertices() 159 self.faces = self.getFaces() 160 161 # Here need to create a numeric array for each properties: 162 # colors 163 self.colors = Numeric.ones((len(self.faces), 3),'f') 164 # opacities 165 self.opacities = Numeric.ones((len(self.faces),),'f')
166
167 - def getextrudeVertices(self):
168 """ get the extruded vertices and normals. If an arrow is specified, 169 extra vertices are added. If caps are specified, 170 the end vertices must be duplicated and used as extra vertices.""" 171 ls = self.shape.lenShape 172 length = len(self.path3D) 173 174 f = g = 0 175 # f adds another section, a section is ls vertices. 176 # g adds the center pt of cap 177 if self.cap1: f, g = f+1, g+1 # add a section and a middle point. 178 if self.cap2: f, g = f+1, g+1 179 if self.arrow:f = f+3 # add 3 sections: 180 # - 1 junction between the arrow and 181 # the rest of the geom. 182 # - 2 for the caps of the arrow. 183 184 # get the right size pts and normals arrays for caps and arrows 185 pts = Numeric.zeros( ((length+f)*ls+g,3),'f') 186 ptsNorm = Numeric.zeros( ((length+f)*ls+g,3),'f') 187 188 # extrude 2D shape along 3D path 189 for i in range(length): 190 pts[i*ls:i*ls+ls] = Numeric.matrixmultiply(self.shape.contpts, 191 self.matrix[i]).astype('f') 192 newNorm = Numeric.matrixmultiply(self.shape.contnorm, 193 self.matrix[i]).astype('f') 194 ptsNorm[i*ls:i*ls+ls] = newNorm 195 196 # add 3*ls vertices for the arrow 197 if self.arrow: 198 pts= self.addArrow(pts) 199 200 # add duplicate vertices and centers for cap1 and/or cap2 at the end 201 # of the array of pts 202 if self.cap1 and not self.cap2: 203 pts[-ls-1:-1] = pts[0:ls] 204 pts[-1] = self.path3D[0] # center of cap1 205 # normals 206 n = TriangleNormals(pts[-4:], [(3, 1, 0)]) 207 for k in range(ls+1): 208 ptsNorm[-ls-1+k] = n[0] 209 210 elif self.cap2 and not self.cap1: 211 pts[-ls-1:-1] = pts[(length-1)*ls:length*ls] 212 pts[-1] = self.path3D[-1] # center of cap2 213 # normals 214 n = TriangleNormals(pts[-4:], [(0, 1, 3)]) 215 for k in range(ls+1): 216 ptsNorm[-ls-1+k] = n[0] 217 218 elif self.cap1 and self.cap2: 219 pts[-2*ls-2:-ls-2] = pts[0:ls] # vertices for cap1 220 pts[-ls-2] = self.path3D[0] # center of cap1 221 # normals 222 n = TriangleNormals(pts[-5-ls:-ls-1], [(3, 1, 0)]) 223 for k in range(ls+1): 224 ptsNorm[-2*ls-2+k] = n[0] 225 226 pts[-ls-1:-1] =pts[(length-1)*ls:length*ls] # vertices for cap2 227 pts[-1] = self.path3D[-1] # center of cap2 228 # normals 229 n = TriangleNormals(pts[-4:], [(0, 1, 3)]) 230 for k in range(ls+1): 231 ptsNorm[-ls-1+k] = n[0] 232 233 return pts, ptsNorm
234
235 - def addArrow(self, pts):
236 """ Compute the vertices for an arrowhead. 237 self.larrow specifies how far back the arrow goes along the path3D. 238 self.warrow is the width in real units. 239 """ 240 # @ @ 241 # /| /| 242 # / | / | 243 # *-----*-----*-----*-----* * | / | 244 # /| /| /| /| /| | | / | 245 # / | / | / | / | / | | @/ @ 246 # *-----*-----*-----*-----* | * | // / 247 # | | | | | | | | | | /| |// / 248 # | * | * | * | * | * / | */ / 249 # | / | / | / | / | / @ | @ / 250 # |/ |/ |/ |/ |/ | | | / 251 # *-----*-----*-----*-----* | * | / 252 # | / | / 253 # |/ |/ 254 # | @ @ 255 # < BLOC1-> lp-lenarrow> | 256 # <lp-lenarrow> 257 # BLOC2 | 258 # <v[lp-lenarrow:] translated > 259 # BLOC3 260 # lp = len(self.path3D) 261 # *: vertices results of the extrusion of the shape2D along the path3D 262 # @: those vertices translated . 263 264 265 lenarrow = self.larrow 266 widtharrow = self.warrow 267 268 ls = self.shape.lenShape 269 lv = len(pts) 270 path = self.path3D 271 lp = len(path) 272 lnew = lp-lenarrow 273 if lnew<0: 274 self.arrow = 0 275 # the arrow is too long: no arrow added 276 return pts 277 278 # Compute the translation vector that will be used to translate the 279 # vertices used to build the arrowhead. 280 281 d = Numeric.zeros( lenarrow+1, 'f') # the firs section will be 282 # duplicate to build the caps. 283 for n in xrange(1, lenarrow+1): 284 d[n] = d[n-1] + self.dist(path[-n], path[-n-1]) 285 d = d*widtharrow/d[lenarrow] - abs(self.shape.contpts[0][0]) 286 287 # We apply the translation to the vertices that belongs to the arrow 288 # and reorganize them in the array of points so the array contains 289 # three blocs of vertices see the drawing above: 290 # A total of 3*ls vertices have been added 291 # Build bloc3 292 for s in xrange(lenarrow+1): 293 #v = [0, 0, 0] 294 uvector = self.norms[-s-1] 295 v = (uvector*d[s]).astype('f') 296 297 for j in range(ls): 298 if j < (ls)/2 or j >= ls: 299 pts[(lp-s+2)*ls+j] = pts[(lp-s-1)*ls+j]-v 300 elif j >= (ls)/2 and j < ls: 301 pts[(lp-s+2)*ls+j] = pts[(lp-s-1)*ls+j]+v 302 303 # build bloc2 304 # duplicate vertices for corner of arrow 305 pts[lnew*ls:(lnew+1)*ls] = pts[(lnew-1)*ls:lnew*ls] 306 pts[(lnew+1)*ls:(lnew+2)*ls] = pts[(lnew+2)*ls:(lnew+3)*ls] 307 return pts
308 309
310 - def dist(self, p1, p2):
311 """ Calculate distance between two pts.""" 312 dx = p2[0]-p1[0] 313 dy = p2[1]-p1[1] 314 dz = p2[2]-p1[2] 315 316 distance = math.sqrt(pow(dx, 2)+pow(dy, 2)+pow(dz, 2)) 317 return distance
318
319 - def getFaces(self):
320 """ get the list of faces for the extrusion, 321 and add faces for caps.""" 322 faces = [] 323 ls = self.shape.lenShape 324 lv = len(self.vertices) 325 326 # build faces with 2Dshape that has 2 normals per vertex 327 if self.shape.vertDup == 1: 328 # You build the faces between two points of the path3D 329 # The number of faces == number of non duplicated points of the 330 # shape2D. 331 if not self.arrow: 332 faces = self.buildFaces(faces=faces,start=0, 333 end=len(self.path3D)-1, 334 ls=ls, dup=1) 335 else: 336 #ARROWS: 3*ls vertices have been added but only 2 faces. 337 lp = len(self.path3D) 338 # 1- BLOC1: cf drawing above. 339 faces = self.buildFaces(faces = faces, start = 0, 340 end = lp-(self.larrow+1), 341 ls = ls, dup=1) 342 343 #2- BLOC2 : Only two faces to close the back of the arrow. 344 i = lp - self.larrow 345 faces.append((i*ls, i*ls+2, i*ls+ls+2, i*ls+ls)) 346 faces.append((i*ls+ls/2, i*ls+ls/2+2, 347 i*ls+ls/2+ls+2, i*ls+ls+ls/2)) 348 349 #3- BLOC3: cf drawing above. 350 faces = self.buildFaces(faces=faces, 351 start=(lp-(self.larrow+1))+3, 352 end=lp+3-1, ls=ls, dup=1) 353 self.fixNormals(faces) # get correct normals for arrow 354 355 356 # CAPS: get faces for the caps: 357 # ls+1 vertices ( a section and a middle face point), 358 # have been added to the regular vertices for the 359 # caps and normals have been computed for those vertices. 360 # The vertices are duplicated except for the middle face point, 361 # but the normals are the same That is why below we are only using 362 # every other vertices to get the faces. 363 364 if (self.cap1 and not self.cap2) : 365 # Only the beginning cap 366 # the index of the first caps vertices is: 367 # the last vertex - (ls + 1) 368 fc1 = lv - (ls + 1) 369 for j in xrange(0,ls-2,2): 370 faces.append( (fc1+j+2, fc1+j, fc1+ls, fc1+ls)) 371 faces.append( (fc1, fc1+ls-2, fc1+ls, fc1+ls)) 372 373 elif (self.cap2 and not self.cap1): 374 # Only one cap the end cap: 375 # the index of the first caps vertices is: 376 # the last vertex - (ls + 1) 377 fc2 = lv - (ls + 1) 378 for j in xrange(0,ls-2,2): 379 faces.append((fc2+j, fc2+j+2, fc2+ls, fc2+ls)) 380 faces.append( (fc2+ls-2, fc2, fc2+ls, fc2+ls)) 381 382 elif self.cap1 and self.cap2: # both caps 383 # the index of the first cap vertex is : 384 # last vertex (lv) - (2*(ls+1)) because 1st caps: 385 fc1 = lv - (2*(ls+1)) 386 for j in xrange(0,ls-2,2): 387 faces.append((fc1+j+2, fc1+j, fc1+ls, fc1+ls)) 388 faces.append( (fc1, fc1+ls-2, fc1+ls, fc1+ls)) 389 390 #cap2: 391 # the index of the second cap vertex is : 392 # last vertex (lv) - ((ls+1)) 393 fc2 = lv - (ls+1) 394 for j in xrange(0,ls-2,2): 395 faces.append((fc2+j, fc2+j+2, fc2+ls, fc2+ls)) 396 faces.append( (fc2+ls-2,fc2, fc2+ls, fc2+ls)) 397 398 # not duplicate vertices; 1 normal per vertex 399 else: 400 if not self.arrow: 401 faces = self.buildFaces(faces=faces, start=0, 402 end=len(self.path3D)-1, 403 ls=ls, dup=0) 404 else: 405 #ARROWS: 3*ls vertices have been added but only 2 faces. 406 lp = len(self.path3D) 407 # 1- BLOC1: cf drawing above. 408 faces = self.buildFaces(faces = faces, start = 0, 409 end = lp-(self.larrow+1), 410 ls = ls, dup=0) 411 412 #2- BLOC2 : Only two faces to close the back of the arrow. 413 #VERIFY!!!! 414 i = lp - self.larrow 415 faces.append((i*ls, i*ls+1, i*ls+ls+1, i*ls+ls)) 416 faces.append((i*ls+ls/2, i*ls+ls/2+1, 417 i*ls+ls/2+ls+1, i*ls+ls+ls/2)) 418 419 #3- BLOC3: cf drawing above. 420 faces = self.buildFaces(faces=faces, 421 start=(lp-(self.larrow+1))+3, 422 end=lp+3-1, ls=ls, dup=0) 423 #self.fixNormals(faces) # get correct normals for arrow 424 425 # add caps 426 if self.cap1 and not self.cap2: 427 # first cap only 428 fc1 = lv - (ls+1) 429 for i in range(ls-1): 430 faces.append((fc1+i+1, fc1+i, fc1+ls, fc1+ls)) 431 faces.append( (fc1, fc1+ls-1, fc1+ls, fc1+ls)) 432 433 elif self.cap2 and not self.cap1: # second cap only 434 fc2 = lv - (ls+1) 435 for i in range(ls-1): 436 faces.append((fc2+i+1, fc2+i, fc2+ls, fc2+ls)) 437 faces.append( (fc2, fc2+ls-1, fc2+ls, fc2+ls)) 438 439 elif self.cap1 and self.cap2: # both caps 440 # the index of the first cap vertex is : 441 # last vertex (lv) - (2*(ls+1)) because 1st caps: 442 fc1 = lv - (2*(ls+1)) 443 for j in xrange(ls-1): 444 faces.append((fc1+j+1, fc1+j, fc1+ls, fc1+ls)) 445 faces.append( (fc1, fc1+ls-1, fc1+ls, fc1+ls)) 446 447 #cap2: 448 # the index of the second cap vertex is : 449 # last vertex (lv) - ((ls+1)) 450 fc2 = lv - (ls+1) 451 for j in xrange(ls-1): 452 faces.append((fc2+j, fc2+j+1, fc2+ls, fc2+ls)) 453 faces.append( (fc2+ls-1,fc2, fc2+ls, fc2+ls)) 454 return faces
455
456 - def buildFaces(self, faces, start, end, ls, dup):
457 """ Method that returns the faces for the points in the path3D 458 between start and end. Ls is the length of the shape and dup 459 indicates if the vertices are duplicated.""" 460 if dup: 461 jrange = range(1,ls-2,2) 462 # b+6 463 # b+ls+6 | /b+ls+7 | /b+7 464 # |/ |/ 465 # *-----------* 466 # b+ls+5 /| b+5 /| 467 # | / | | / | 468 # |/ | b+ls |/ | b+0 where b=i*ls 469 # *-----/-----* | / and i is the section number. 470 # /| |/ /| |/ When you build a facet he 471 # b+ls+4 / | *-----/-|---* normals must go out. 472 # | /| b+4| /| 473 # | / | | / | 474 # |/ b+ls+1 |/ b+1 475 # *-----------* 476 # /| /| 477 # b+ls+3 / | / | 478 # | b+3 b+2 479 # b+ls+2 480 481 else: 482 jrange = range(ls-1) 483 # The vertices are not duplicated. 484 # 485 # 486 # b+ls+3 *-----------*b+3 487 # /| /| 488 # / | / | 489 # / | / | where b=i*ls 490 # b+ls+2*-----------*b+2| and i is the section number. 491 # | | | | 492 # | *-------|---*b 493 # | /b+ls | / 494 # | / | / 495 # |/ |/ 496 # *-----------* 497 # b+ls+1 b+1 498 499 500 for i in xrange(start, end): 501 # i represent the section number you are connecting. 502 for j in jrange: 503 # j represents the vertex number. 504 # Build the (ls/2)-1 faces 505 faces.append(((i*ls)+j, (i*ls)+(j+1), 506 ((i+1)*ls)+(j+1),((i+1)*ls)+j)) 507 # Build the last face. 508 faces.append((i*ls, (i+1)*ls, 509 (i+1)*ls+(ls-1), (i*ls)+(ls-1))) 510 return faces
511 512
513 - def fixNormals(self, faces):
514 """ fixes normals on arrow by using glQuadNormals, which calculates 515 normals.""" 516 ls = self.shape.lenShape 517 path = self.path3D 518 lp = len(path) 519 la = self.larrow 520 lnew = lp-la 521 if self.shape.vertDup==1: numf = (ls-1)/2 522 else: numf = ls-1 523 arrfaces = faces[-(la+3)*numf:] 524 # glQuadNormals need all the vertices of the secondarystructure but 525 # only the faces belonging to the arrow. 526 n = self.glQuadNormals(self.vertices, arrfaces) 527 # Replacing the normals in the array by the new one. 528 self.vnormals[lnew*ls:(lp+3)*ls] = n[lnew*ls:(lp+3)*ls]
529
530 - def glQuadNormals(self, vertices, faces):
531 """ gets normals for quads by converting a quad face into two triangle 532 faces and calling TriangleNormals. """ 533 faces = Numeric.array(faces) 534 f = Numeric.concatenate((faces[:,-2:], faces[:,:1]), 1) 535 F = Numeric.concatenate((faces[:,:3], f), 0) 536 n = TriangleNormals(vertices, F, 'PER_VERTEX') 537 return n
538
539 - def setResidueProperties(self, properties, propName, resIndices):
540 """ with the given list of pairs of residue indices and corresponding 541 colors, the method sets the color per residue in the self.colors array. 542 """ 543 544 nfaces = self.shape.lenShape 545 if self.shape.vertDup==1: nfaces = nfaces/2 546 properties = Numeric.array(properties).astype('f') 547 self.properties = getattr(self, propName) 548 for r in range(len(resIndices)): 549 st = int(resIndices[r][0]*nfaces) 550 en = int(resIndices[r][1]*nfaces) 551 for f in range(st, en): 552 self.properties[f] = properties[r][:3]
553
554 - def setStripProperty(self, properties, propName):
555 """ set the color array so that each side strip of the structure has 556 one color. """ 557 558 nfaces = self.shape.lenShape 559 if self.shape.vertDup==1: nfaces = nfaces/2 560 561 assert len(properties)==nfaces 562 c = 0 563 if self.cap1: c = c+nfaces 564 if self.cap2: c = c+nfaces 565 for i in range(-c, 0): 566 self.colors[i] = (1., 1., 1.) # color caps white 567 self.opacities[i] = 1. # color caps white 568 self.properties = getattr(self, propName) 569 if self.arrow: 570 for i in range(len(self.properties)-c): 571 s = i%nfaces 572 if i >= len(self.properties)-(self.larrow+2)*nfaces: 573 self.properties[i] = properties[s-2][:3] 574 elif i == len(self.properties)-(self.larrow+2)*nfaces-1: 575 self.properties[i] = properties[s+1][:3] 576 else: 577 self.properties[i] = properties[s][:3] 578 else: 579 for i in range(len(self.properties)-c): 580 s = i%nfaces 581 self.properties[i] = properties[s][:3]
582 583 584
585 -class ExtrudeSSElt(ExtrudeObject):
586 """ Class to take a shape and extrude it along the 3D path defined by 587 a control coordinate and torsion coordinate 588 """ 589
590 - def __init__(self, ssElt, shape, gapEnd = 0, gapBeg = 0, cap1=0, 591 cap2=0, arrow = 0,larrow = 3, warrow = 2):
592 """Constructor's arguments: 593 - secondary structure Elt. 594 - shape. 595 - etc...""" 596 self.ssElt = ssElt 597 self.gapBeg = gapBeg 598 self.gapEnd = gapEnd 599 self.lengthPath = len(self.ssElt.sheet2D.path) 600 self.residuesInChain = self.ssElt.sheet2D.resInSheet 601 self.residuesInChain.nbSS = range(len(self.residuesInChain)) 602 self.chords = self.ssElt.sheet2D.chords 603 # last residue index in chain. 604 self.lastResIndex = self.residuesInChain[-1].nbSS 605 self.indexStart = self.ssElt.start.nbSS 606 607 # first point and last point index in the path3D of the first residue 608 #of the secondarystructure. 609 self.fromForStart, self.toForStart = self.getResPts(self.indexStart) 610 611 ## self.indexEnd = self.residuesInChain.index(self.ssElt.end) 612 self.indexEnd = self.ssElt.end.nbSS 613 # first point and last point index in the path3D of the last residue 614 #of the secondarystructure. 615 self.fromForEnd, self.toForEnd = self.getResPts(self.indexEnd) 616 path3D = self.ssElt.sheet2D.path[self.fromForStart:self.toForEnd] 617 matrix = self.ssElt.sheet2D.matrixTransfo[self.fromForStart: 618 self.toForEnd] 619 620 621 ExtrudeObject.__init__(self, path3D, matrix, shape, cap1=cap1, 622 cap2=cap2, arrow=arrow, larrow=larrow, 623 warrow=warrow)
624 625 626
627 - def getResIndexFromPts(self, respts):
628 """ return the index of the residue to which a point in the path 629 belongs.""" 630 631 if respts < (self.chords/2 + 1 ): 632 # first residue 633 resIndex = 0 634 elif respts > ((self.lengthPath-1)-\ 635 (self.chords + self.chords/2)): 636 # last residue 637 resIndex = self.lastResIndex 638 else: 639 # all the other nbchords 640 resIndex = (respts-(2+ self.chords/2))/self.chords + 1 641 642 643 return resIndex
644
645 - def getResPts(self, residueindex):
646 """ return the index of the first and the last point in the 647 Sheet2D.path for the residue whose index is specified""" 648 # a residue is represented in the path3D by chords points. 649 # first residue represented by nbchords/2 + 1 650 # last residue represented by nbchords+nbchords/2 651 # all other by nbchords. 652 if residueindex == 0: 653 fromPts = 0 654 toPts = self.chords/2 + 2 655 656 elif residueindex == self.lastResIndex: 657 fromPts = (residueindex-1) * self.chords + self.chords/2+1 658 toPts = self.lengthPath-1 659 660 else: 661 fromPts = (residueindex-1) * self.chords + self.chords/2+1 662 toPts = fromPts + self.chords +1 663 664 toPts = toPts-self.gapEnd 665 fromPts = fromPts + self.gapBeg 666 return fromPts,toPts
667
668 - def getExtrudeResidues(self, resSet):
669 """ Get faces for the specified residues in ResSet """ 670 671 ls = self.shape.lenShape 672 nfaces = ls 673 if self.shape.vertDup==1: nfaces = (ls)/2 674 residueFaces = [] 675 resSet.sort() 676 677 for r in resSet: 678 rindex = r.nbSS 679 start, end = self.getResPts(rindex) 680 # 1st and last points in the path3D corresponding to r 681 682 first = (start-self.fromForStart)*nfaces 683 last = (end-self.fromForStart-1)*nfaces 684 # relative to the secondarystructure. 685 686 # faces for arrow (Note: assumes arrow shorter than last residue) 687 if r==self.ssElt.end and self.arrow: 688 #Only two faces are added when an arrow is added. 689 last = last+2 690 residueFaces.extend(self.faces[first:last]) 691 692 # faces for cap1 or cap2, if residue is beginning or end 693 if r==self.ssElt.start: 694 if self.cap1 and not self.cap2: 695 residueFaces.extend(self.faces[-nfaces:]) 696 697 elif self.cap1 and self.cap2: 698 residueFaces.extend( 699 self.faces[-2*nfaces:-nfaces]) 700 if r==self.ssElt.end: 701 if self.cap2: 702 residueFaces.extend(self.faces[-nfaces:]) 703 704 return residueFaces
705
706 - def getExtrudeProperties(self, ResSet, propName):
707 """ Get the colors for the specified residues in ResSet """ 708 709 ls = self.shape.lenShape 710 nfaces = ls 711 if self.shape.vertDup==1: nfaces = (ls)/2 712 # res are the residues used to build the sheet 2D. 713 prop = [] 714 resProperty = getattr(self, propName).tolist() 715 716 # sort residues in secondarystructure according to nbSS 717 ResSet.sort() 718 for r in ResSet: 719 rindex = r.nbSS 720 start, end = self.getResPts(rindex) 721 # 1st and last points in the whole path3D corresponding to r 722 723 first = (start-self.fromForStart)*nfaces 724 last = (end-self.fromForStart-1)*nfaces 725 # 1st and last points index relative to the secondarystructure. 726 727 # colors for arrow (Note: assumes arrow shorter than last residue) 728 if r==self.ssElt.end and self.arrow: 729 # 3 corresponds to the sections added for the arrow. 730 last = last+2 731 prop.extend(resProperty[first:last]) 732 733 # colors for cap1 or cap2, if residue is beginning or end 734 if r==self.ssElt.start: 735 if self.cap1 and not self.cap2: 736 prop.extend(resProperty[-nfaces:]) 737 elif self.cap1 and self.cap2: 738 prop.extend(resProperty[-2*nfaces:-nfaces]) 739 if r==self.ssElt.end: 740 if self.cap2: 741 prop.extend(resProperty[-nfaces:]) 742 743 return prop
744
745 - def setResProperties(self, propVect, propName, ResSet):
746 """ sets each residue in 'ResSet' to the color in 'colors' by calling 747 the setResidueColors method of extrusion, which is an instance of the 748 Extrude class. """ 749 750 assert len(propVect)==len(ResSet) 751 ls = self.shape.lenShape 752 nfaces = ls 753 if self.shape.vertDup==1: nfaces = (ls)/2 754 firstLastIndices = [] 755 properties = [] 756 i=0 757 for r in ResSet: 758 assert r in self.ssElt.residues 759 rindex = r.nbSS 760 start, end = self.getResPts(rindex) 761 first = start-self.fromForStart 762 last = end-self.fromForStart-1 763 # relative to the secondarystructure. 764 765 # color arrow same color as residue 766 if r==self.ssElt.end and self.arrow: 767 # When an arrow is added the nbSS of faces is increased by 768 # 2. If we add 1 to End this will mean that 4 faces have been 769 # added . 770 last = last + 0.5 771 772 firstLastIndices.append((first, last)) 773 propTmp = propVect[i] 774 properties.append(propTmp) 775 # color the caps same color as residue 776 if r==self.ssElt.start: 777 if self.cap1 and not self.cap2: 778 firstLastIndices.append((-1, 0)) 779 properties.append(propTmp) 780 elif self.cap1 and self.cap2: 781 firstLastIndices.append((-2, -1)) 782 properties.append(propTmp) 783 if r==self.ssElt.end: 784 if self.cap2: 785 firstLastIndices.append((-1, 0)) 786 properties.append(propTmp) 787 i = i+1 788 789 ExtrudeObject.setResidueProperties(self,properties, 790 propName,firstLastIndices )
791
792 - def getResIndexFromExtrudeVertex(self, vertex):
793 """ takes a vertex from the extrusion and returns the index of the 794 residue the vertex belongs to """ 795 assert vertex < len(self.vertices) 796 ls = self.shape.lenShape 797 # find the section number of the path3D to which the picked 798 # vertex belongs to 799 pickedEstimate = vertex/ls 800 # number of section that have been added to the path3D. 801 extraSection = 0 802 # len(self.paths3D)-1 because there is a section shared by 803 # two residues. 804 if pickedEstimate>=len(self.path3D)-1: 805 if self.arrow: 806 extraSection = 3 807 if pickedEstimate <= (len(self.path3D)-1)+extraSection: 808 # What comes after normal points are the arrow sections 809 # then the cap1 there are no cap2. 810 # vertex is in arrow, p is the point index if no 811 # Arrow added 812 pickedSection = len(self.path3D) - 2 813 814 else: 815 pointsLeft = vertex-(len(self.path3D)+extraSection)*ls 816 # remove from the vertex index the whole path3D and the 817 # extraSection added for the arrow to see if the vertex 818 # is in caps. The cap extraSection have been added at the 819 # end. 820 pickedEstimate = pointsLeft/(ls+1) 821 pickedSection = pickedEstimate 822 else: 823 pointsLeft = vertex-(len(self.path3D)+extraSection)*ls 824 pickedEstimate = pointsLeft/(ls+1) 825 pickedSection = pickedEstimate 826 827 if pickedEstimate==1: 828 pickedSection = len(self.path3D)-2 829 # vertex is in cap2 830 831 if pickedEstimate<=0: 832 if self.cap1: 833 pickedSection = 1 # vertex is in cap1 834 elif self.cap2: 835 pickedSection = len(self.path3D)-2 # vertex is in cap2 836 else: 837 pickedSection = pickedEstimate 838 839 else: pickedSection = pickedEstimate 840 index = self.getResIndexFromPts(pickedSection+self.fromForStart) 841 842 resIndex = index - self.indexStart 843 844 # remove first section because only represented by self.chords/2 + 1 845 p = ((self.lengthPath-1)-(self.chords + self.chords/2)) 846 if pickedSection < self.chords/2+2: 847 resIndex = 0 848 849 elif pickedSection >((self.lengthPath-1)-\ 850 (self.chords + self.chords/2)): 851 resIndex = self.lastResIndex 852 853 if resIndex==-1: resIndex=0 854 return resIndex
855 856 857 858 from mglutil.math import crossProduct,norm 859
860 -def ExtrudeNA(chain):
861 """Computes ribbons for DNA/RNA""" 862 coord = [] 863 coord.append(chain.residues[0].atoms[0].coords) 864 NA_type = chain.residues[0].type.strip() 865 atoms = chain.residues[0].atoms 866 if NA_type in ['A', 'G']: 867 N9 = Numeric.array(atoms.objectsFromString('N9')[0].coords) 868 C8 = Numeric.array(atoms.objectsFromString('C8')[0].coords) 869 C4 = Numeric.array(atoms.objectsFromString('C4')[0].coords) 870 N9_C8 = C8-N9 871 N9_C4 = C4-N9 872 normal = Numeric.array(crossProduct(N9_C8, N9_C4, normal=True)) 873 else: 874 N1 = Numeric.array(atoms.objectsFromString('N1')[0].coords) 875 C2 = Numeric.array(atoms.objectsFromString('C2')[0].coords) 876 C6 = Numeric.array(atoms.objectsFromString('C6')[0].coords) 877 N1_C2 = C2-N1 878 N1_C6 = C6-N1 879 normal = Numeric.array(crossProduct(N1_C2, N1_C6, normal=True)) 880 base_normal = Numeric.array(chain.residues[0].atoms[0].coords) 881 coord.append((base_normal + normal).tolist()) 882 for res in chain.residues[1:]: 883 884 if res.atoms.objectsFromString('P'): 885 P_coord = res.atoms.objectsFromString('P')[0].coords 886 coord.append(P_coord) 887 else: # this in case last residue does not have P 888 P_coord = res.atoms.objectsFromString('C5\*')[0].coords 889 NA_type = res.type.strip() 890 atoms = res.atoms 891 if NA_type in ['A', 'G']: 892 N9 = Numeric.array(atoms.objectsFromString('N9')[0].coords) 893 C8 = Numeric.array(atoms.objectsFromString('C8')[0].coords) 894 C4 = Numeric.array(atoms.objectsFromString('C4')[0].coords) 895 N9_C8 = C8-N9 896 N9_C4 = C4-N9 897 normal = Numeric.array(crossProduct(N9_C8, N9_C4, normal=True)) 898 else: 899 N1 = Numeric.array(atoms.objectsFromString('N1')[0].coords) 900 C2 = Numeric.array(atoms.objectsFromString('C2')[0].coords) 901 C6 = Numeric.array(atoms.objectsFromString('C6')[0].coords) 902 N1_C2 = C2-N1 903 N1_C6 = C6-N1 904 normal = Numeric.array(crossProduct(N1_C2, N1_C6, normal=True)) 905 906 base_normal = Numeric.array(P_coord) 907 coord.append((base_normal + normal).tolist()) 908 909 chain.sheet2D['ssSheet2D'] = Sheet2D() 910 chain.sheet2D['ssSheet2D'].compute(coord, len(chain.residues)*(False,), 911 width = 2.0,off_c = 0.9,offset=0.0, nbchords=4) 912 chain.sheet2D['ssSheet2D'].resInSheet = chain.residues
913