Package DejaVu :: Module DataOutput
[hide private]
[frames] | no frames]

Source Code for Module DejaVu.DataOutput

   1  ############################################################################# 
   2  # 
   3  # Date: Jun 2002   Author: Daniel Stoffler 
   4  # 
   5  # stoffler@scripps.edu 
   6  # 
   7  #       The Scripps Research Institute (TSRI) 
   8  #       Molecular Graphics Lab 
   9  #       La Jolla, CA 92037, USA 
  10  # 
  11  # Copyright: Daniel Stoffler and TSRI 
  12  # 
  13  # Revision: Guillaume Vareille, Alex Gillet 
  14  # 
  15  ############################################################################# 
  16   
  17   
  18  from opengltk.OpenGL import GL 
  19  #from opengltk.extent.utillib import glTriangleNormals 
  20  from geomutils.geomalgorithms import  TriangleNormals 
  21   
  22  import Numeric, math, string, warnings 
  23  from mglutil.math import rotax 
  24  from DejaVu.Geom import Geom 
  25  from DejaVu.IndexedGeom import IndexedGeom 
  26  from DejaVu.Transformable import Transformable 
  27  from DejaVu.IndexedPolylines import IndexedPolylines 
  28  from DejaVu.IndexedPolygons import IndexedPolygons 
  29  from DejaVu.Spheres import Spheres 
  30  from DejaVu.Cylinders import Cylinders 
  31  from DejaVu import viewerConst 
  32  from DejaVu.colorTool import glMaterialWithCheck 
  33  from DejaVu.GleObjects import GleExtrude 
  34  from DejaVu.glfLabels import GlfLabels 
  35   
  36  import Tkinter, Pmw 
  37  from mglutil.gui.InputForm.Tk.gui import InputFormDescr, InputForm 
  38   
  39   
  40  ########################################################################## 
  41  # 
  42  #  functions for generating and parsing SMF format: 
  43  # 
  44  #  http://www.csit.fsu.edu/~burkardt/data/smf/smf.txt 
  45  #  (also DejaVu/FileFormats/smf.txt) 
  46  # 
  47  #  use my Michael Garland's Qslim program  
  48  # 
  49  ########################################################################## 
  50   
  51   
52 -def IndexedPolgonsAsSMFString(geometry):
53 """listOfStrings <-- IndexedPolgonsAsSMFString(geometry) 54 For a given IndexedPolygons geoemtry this function generates the textual SMF 55 description. Currently supports vertices (v), faces (f), normals(n) and 56 colors (c). Normals and color binding mstring are generated automatically. 57 Texture indices (r) are not used yet but could be used to store any integer 58 property. 59 """ 60 assert isinstance(geometry, IndexedPolygons) 61 # we can only handle triangles or quads 62 assert geometry.faceSet.faces.array.shape[1] in [3,4] 63 64 lines = [] 65 lines.append('begin\n') 66 # vertices 67 verts = geometry.vertexSet.vertices.array 68 lines.extend( map(lambda x: ('v %f %f %f\n'%tuple(x)), verts) ) 69 70 # faces 71 tri = geometry.faceSet.faces.array 72 lines.extend( map(lambda x: 73 ('f %d %d %d\n'%(x[0]+1,x[1]+1,x[2]+1)), tri) ) 74 75 # normals 76 normals = geometry.normals 77 if len(normals)==len(verts): 78 lines.append('bind n vertex\n') 79 elif len(normals)==len(tri): 80 lines.append('bind n face\n') 81 else: 82 normals = None 83 if normals: 84 lines.extend( map(lambda x: 85 ('n %f %f %f\n'%tuple(x)), normals) ) 86 87 # colors 88 if geometry.materials[1028].binding[1]==11: #per vertex color 89 lines.append('bind c vertex\n') 90 cols = geometry.materials[1028].prop[1] 91 lines.extend( map(lambda x: 92 ('c %f %f %f\n'%tuple(x[:3])), cols) ) 93 lines.append('end\n') 94 return lines
95 96
97 -def writePolygonsAsSMF(geometry, filename):
98 """Write a IndexedPolygons geometry to a file""" 99 100 f = open(filename, 'w') 101 map( lambda x, f=f: f.write(x), IndexedPolgonsAsSMFString(geometry) ) 102 f.close()
103 104
105 -def ParseSMFString(stringList):
106 """v,f,n,c,r <-- ParseSMFString(stringList) 107 Parse an ascii SMF file and returnes a list of 3D vertices, triangular faces 108 (0-based indices, faces with more edges generate warnings), normals, colors 109 and 2D texture coordinates. 110 """ 111 112 vertices = [] 113 faces = [] 114 normals = [] 115 colors = [] 116 textures = [] 117 fi = 0 118 for l in stringList: 119 w = l.split() 120 if w[0]=='v': # vertices 121 vertices.append( [float(w[1]),float(w[2]),float(w[3])] ) 122 elif w[0]=='f': # faces 123 if len(w) > 4: 124 warnings.warn("face %d has more than 3 edges"%fi); 125 faces.append( [int(w[1])-1,int(w[2])-1,int(w[3])-1] ) 126 fi += 1 127 if w[0]=='n': # normal vectors 128 normals.append( [float(w[1]),float(w[2]),float(w[3])] ) 129 if w[0]=='c': # colors 130 colors.append( [float(w[1]),float(w[2]),float(w[3])] ) 131 if w[0]=='r': # 2D texture indices 132 textures.append( [float(w[1]),float(w[2])] ) 133 return vertices, faces, normals, colors, textures
134 135
136 -def readSMF(filename):
137 """Read an SMF ascii file and return an IndexedPolygons geometry""" 138 139 f = open(filename) 140 data = f.readlines() 141 f.close() 142 v, f, n, c, t = ParseSMFString(data) 143 return v, f, n, c, t
144 145
146 -class OutputNode:
147 148 """This base class recursively loops over a given DejaVu geom tree and 149 computes the transformation matrices at each level.""" 150
151 - def __init__(self):
152 self.output = [] # list describing the formated data 153 self.lenGeoms = 0 # used for the progress bar to determine how many
154 # visible geoms are in the viewer 155
156 - def configureProgressBar(self, **kw):
157 # this method is to be implemented by the user from outside 158 pass
159 160
161 - def updateProgressBar(self, progress=None):
162 # this method is to be implemented by the user from outside 163 pass
164 165
166 - def countGeoms(self, obj):
167 for child in obj.children: 168 if child.visible: 169 check = self.checkGeom(child) 170 if check: 171 self.lenGeoms = self.lenGeoms + 1 172 self.countGeoms(child)
173 174
175 - def loopGeoms(self, obj):
176 """ this calls the recursive method """ 177 178 ## #commented out 2.7.02 DS, we discard now root transformation 179 ## # we reset the scale of rootObject to 1,1,1 180 ## if obj == obj.viewer.rootObject: 181 ## scaleFactor = obj.scale 182 ## obj.SetScale([1.,1.,1.]) 183 184 # initialize the progress bar to be ratio 185 self.lenGeoms = 0 # initialize this to 0 186 self.countGeoms(obj) # determine lenght of visible geoms 187 self.lenGeoms = self.lenGeoms + 1 # FIXME: dont know why whe 188 # always have 1 too few 189 self.configureProgressBar(init=1, mode='increment', 190 granularity=1, 191 progressformat='ratio', 192 labeltext='parse geoms to vrml2', 193 max=self.lenGeoms) 194 GL.glPushMatrix() 195 GL.glLoadIdentity() 196 self._loopGeomsRec(obj) # call recursive method 197 GL.glPopMatrix()
198 199 ## #commented out 2.7.02 DS, we discard now root transformation 200 ## # now we set the scale factor back to what it was 201 ## if obj == obj.viewer.rootObject: 202 ## obj.SetScale(scaleFactor) 203 204
205 - def _loopGeomsRec(self, obj):
206 """ recursive method """ 207 208 GL.glPushMatrix() 209 210 # we discard root object transformation: 211 if obj is not obj.viewer.rootObject: 212 obj.MakeMat() 213 214 obj.VRML2CreatedPROTOForThisGeom = 0 # flag used in vrml2 doit() 215 216 for i in range(len(obj.instanceMatrices)): 217 GL.glPushMatrix() 218 GL.glMultMatrixf(obj.instanceMatrices[i]) 219 obj.instanceMatricesIndex = i # flag used in stl and vrml2 doit() 220 221 matrix = GL.glGetDoublev(GL.GL_MODELVIEW_MATRIX) 222 self.NodeRepr(obj, matrix) 223 224 for child in obj.children: 225 226 if child.visible: 227 self._loopGeomsRec(child) 228 229 GL.glPopMatrix() 230 231 GL.glPopMatrix() # Restore the matrix 232 del obj.instanceMatricesIndex # clean up object 233 del obj.VRML2CreatedPROTOForThisGeom
234 235
236 - def NodeRepr(self, obj, matrix):
237 """ This method, to be implemented by sublcass, should generate 238 stl, vrml2 etc descriptions of DejaVu geoms""" 239 pass
240 241
242 - def checkGeom(self, geom):
243 # decides which geoms will be output. return 0 means don't save this 244 if geom is None: 245 return 0 246 elif not isinstance(geom, Geom): 247 return 0 248 elif not geom.visible: 249 return 0 250 elif len(geom.vertexSet)==0: 251 return 0 252 elif isinstance(geom, IndexedGeom) and len(geom.faceSet) == 0: 253 return 0 254 else: return 1
255 256
257 -class OutputSTL(OutputNode):
258 """ generates a list of strings describing DejaVu geoms in STL 259 (stereolithography) format (don't mix this with standard template 260 library). 261 """ 262 # THIS STUFF HERE WAS USED IN GLEObject 263 ## def getSTL(self, reverse=0, **kw): 264 ## """ returns a string describing vertices and normals in the STL format. 265 ## """ 266 ## from OpenGL import GL 267 268 ## # force per face normal calculation 269 ## if self.shading != GL.GL_FLAT: 270 ## oldmode = self.shading 271 ## oldnorm = self.normals 272 ## self.shading = GL.GL_FLAT 273 ## self.GetNormals() 274 ## norms = self.normals 275 ## self.shading = oldmode 276 ## self.normals = oldnorm 277 278 ## faces = self.getFaces() 279 ## if len(faces) < 1: 280 ## raise RuntimeError("No faces found in geometry ",self.name) 281 282 ## if faces.shape[1] > 3: 283 ## raise RuntimeError("More than 3 indices per face in ",self.name) 284 285 ## vert = self.getVertices() 286 ## if len(vert)<3: 287 ## raise RuntimeError("Less that 3 vertices found in geometry ", 288 ## self.name) 289 290 ## fn = norms 291 ## if len(fn)!=len(faces): 292 ## raise RuntimeError("Number of face normals does not match \ 293 ## number of faces in geoemtry ",self.name) 294 295 ## if reverse: 296 ## fn = -1.0*fn 297 ## l=[] 298 ## for face in faces: 299 ## l.append([face[0],face[2],face[1]]) 300 ## faces = Numeric.array(l) 301 302 ## stl = [] 303 ## for i in xrange(len(faces)): 304 ## stl.append(" facet normal %f %f %f\n"%tuple(fn[i])) 305 ## stl.append(" outer loop\n") 306 ## fa = faces[i] 307 ## stl.append(" vertex %f %f %f\n"%tuple(vert[fa[0]])) 308 ## stl.append(" vertex %f %f %f\n"%tuple(vert[fa[1]])) 309 ## stl.append(" vertex %f %f %f\n"%tuple(vert[fa[2]])) 310 ## stl.append(" endloop\n") 311 ## stl.append(" endfacet\n") 312 313 ## return stl 314
315 - def __init__(self):
316 OutputNode.__init__(self) 317 self.Transformable = Transformable() 318 self.sphereQuality = 2 # set in getSTL() 319 self.cylinderQuality = 10 # set in getSTL()
320 321
322 - def getSTL(self, root, filename, sphereQuality=2, 323 cylinderQuality=10):
324 325 self.sphereQuality = sphereQuality 326 self.cylinderQuality = cylinderQuality 327 self.output = [] 328 self.output.append("solid %s\n"%filename) 329 self.loopGeoms(root) 330 self.output.append("endsolid %s\n"%filename) 331 return self.output
332 333
334 - def NodeRepr(self, geom, matrix):
335 # called recursively from loopGeom() 336 if not self.checkGeom(geom): return 337 338 # different geoms have to be treated different 339 340 # IndexedGeoms are saved 341 if isinstance(geom, IndexedPolygons): 342 self.doitIndexedGeoms(geom, matrix) 343 344 elif isinstance(geom, Spheres): 345 self.doitSpheres(geom, matrix) 346 347 elif isinstance(geom, Cylinders): 348 self.doitCylinders(geom, matrix) 349 350 # Lines are obviously not supported (no volume) 351 elif isinstance(geom, IndexedPolylines): 352 return
353 354
355 - def doitIndexedGeoms(self, geom, matrix):
356 # gets called from NodeRepr() 357 358 vert = geom.getVertices() 359 faces = geom.getFaces() 360 361 if faces.shape[1]==3: 362 fn = TriangleNormals( vert, faces, 'PER_FACE') 363 else: 364 fn = TriangleNormals( vert, faces[:,:3], 'PER_FACE') 365 366 #if geom is quads, or higher, make triangles 367 if faces.shape[1] > 3: 368 newfaces=[] 369 newfn = [] 370 n=0 # counter for normals 371 for face in faces: 372 373 for i in range(len(face)): 374 # stop, if face contains -1 (for example, BSP Tree objects 375 # might 'fill up' faces with -1 to make uniform arrays 376 if face[i] == -1: 377 break 378 newfaces.append( [face[0],face[i-1],face[i]]) 379 newfn.append(fn[n]) 380 381 # increment normal counter 382 n = n + 1 383 384 # finally, set new faces 385 faces = newfaces 386 fn = Numeric.array(newfn).astype('f') 387 388 self.doit(vert, faces, fn, matrix, invertNormals=geom.invertNormals)
389 390
391 - def doitSpheres(self, geom, matrix):
392 geom = geom.asIndexedPolygons(quality=self.sphereQuality) 393 vert = geom.getVertices() 394 faces = geom.getFaces() 395 fn = TriangleNormals( vert, faces, 'PER_FACE') 396 self.doit(vert, faces, fn, matrix, invertNormals=geom.invertNormals)
397 398
399 - def doitCylinders(self, geom, matrix):
400 geom = geom.asIndexedPolygons(quality=self.cylinderQuality) 401 vert = geom.getVertices() 402 faces = geom.getFaces() 403 fn = TriangleNormals( vert, faces, 'PER_FACE') 404 self.doit(vert, faces, fn, matrix, invertNormals=geom.invertNormals)
405 406
407 - def doit(self, vert, faces, fn, matrix, invertNormals=False):
408 if invertNormals: 409 fn = -1.0*fn 410 l=[] 411 for face in faces: 412 l.append([face[0],face[2],face[1]]) 413 faces = Numeric.array(l) 414 415 coords = Numeric.array(vert).astype('f') 416 matrix = Numeric.array(matrix).astype('f') 417 matrix.shape = (4,4) # this changed after python2.3!! 418 one = Numeric.ones( (coords.shape[0], 1), \ 419 coords.typecode() ) 420 c = Numeric.concatenate( (coords, one), 1 ) 421 422 # apply the matrix to the vertices 423 newCoords = Numeric.matrixmultiply(c, \ 424 Numeric.transpose(matrix))[:, :3] 425 426 self.output.extend(self.makestl(newCoords, faces, fn))
427 428
429 - def makestl(self, vert, faces, fn):
430 stl = [] 431 432 for i in xrange(len(faces)): 433 stl.append(" facet normal %f %f %f\n"%tuple(fn[i])) 434 stl.append(" outer loop\n") 435 fa = faces[i] 436 stl.append(" vertex %f %f %f\n"%tuple(vert[fa[0]])) 437 stl.append(" vertex %f %f %f\n"%tuple(vert[fa[1]])) 438 stl.append(" vertex %f %f %f\n"%tuple(vert[fa[2]])) 439 stl.append(" endloop\n") 440 stl.append(" endfacet\n") 441 442 return stl
443 444
445 -class OutputVRML2(OutputNode):
446 """ generates a list of strings describing DejaVu geoms in VRML 2.0 447 format. Usage: OutputVRML2.getVRML2(geom, complete=0/1, normals=0/1) 448 geom represents the geoms to be converted 449 complete=1 will add vrml2 header and footer 450 normals=1 will add normals 451 """ 452
453 - def __init__(self):
454 OutputNode.__init__(self) 455 self.geomName = None 456 self.Transformable = Transformable() 457 self.completeFlag = 1 # is set in getVRML2() 458 self.saveNormalsFlag = 0 # is set in getVRML2() 459 self.colorPerVertexFlag = True # set in getVRML2() 460 self.usePROTOFlag = 0 # if set, instanceMatrice geoms are not 461 # saved as geoms, but re-used with PROTO 462 self.sphereQuality = 2 # default quality for sphere subsampling 463 self.cylinderQuality = 10 # default quality for cyl. subsampling
464 465
466 - def getVRML2(self, root, complete=1, normals=0, 467 colorPerVertex=True, 468 usePROTO=0, sphereQuality=2, cylinderQuality=10):
469 """ this method returns a list of strings describing DejaVu Geoms in 470 VRML2 format """ 471 472 # this is the method the user should call 473 474 self.completeFlag = complete # if 1, header and footer will be added 475 self.saveNormalsFlag = normals # if 1, normals are added 476 self.colorPerVertexFlag = colorPerVertex # if False, color per face 477 self.usePROTOFlag = usePROTO # if set to 1, instance geoms are saved 478 # with one PROTO. Else: data for these 479 # geoms will be prepared which blows up 480 # the file size 481 482 self.sphereQuality = sphereQuality # default is 2 483 self.cylinderQuality = cylinderQuality # default is 10 484 485 self.output = [] 486 487 if self.completeFlag: 488 self.output.extend(self.getFileHeader1()) 489 self.output.extend(self.getCopyright()) 490 self.output.extend(self.getFileHeader2()) 491 492 self.loopGeoms(root) 493 494 if self.completeFlag: 495 self.output.extend(self.getFileTrailer()) 496 497 return self.output
498 499
500 - def NodeRepr(self, geom, matrix):
501 # called recursively from loopGeom() 502 if not self.checkGeom(geom): return 503 504 # call the progress bar update 505 self.configureProgressBar(labeltext='parse '+geom.name) 506 self.updateProgressBar() 507 508 # IndexedGeoms, Spheres and Cylinders have to be treated differently 509 if isinstance(geom, IndexedPolygons) or \ 510 isinstance(geom, IndexedPolylines): 511 self.output.extend( self.doit(geom, matrix) ) 512 513 elif isinstance(geom, Spheres): 514 # convert Spheres geom into IndexedPolygons 515 sphGeom = geom.asIndexedPolygons(quality=self.sphereQuality) 516 sphGeom.viewer = geom.viewer 517 sphGeom.parent = geom.parent 518 sphGeom.name = geom.name 519 sphGeom.fullName = geom.fullName 520 sphGeom.instanceMatrices = geom.instanceMatrices 521 sphGeom.instanceMatricesIndex = geom.instanceMatricesIndex 522 sphGeom.VRML2CreatedPROTOForThisGeom = 0 523 self.output.extend( self.doit(sphGeom, matrix) ) 524 525 elif isinstance(geom, Cylinders): 526 # convert Cylinders geom into IndexedPolygons 527 cylGeom = geom.asIndexedPolygons(quality=self.cylinderQuality) 528 cylGeom.viewer = geom.viewer 529 cylGeom.parent = geom.parent 530 cylGeom.name = geom.name 531 cylGeom.fullName = geom.fullName 532 cylGeom.instanceMatrices = geom.instanceMatrices 533 cylGeom.instanceMatricesIndex = geom.instanceMatricesIndex 534 cylGeom.VRML2CreatedPROTOForThisGeom = 0 535 self.output.extend( self.doit(cylGeom, matrix) ) 536 537 elif isinstance(geom, GlfLabels): 538 # convert Cylinders geom into IndexedPolygons 539 glfGeom = geom.asIndexedPolygons() 540 glfGeom.viewer = geom.viewer 541 glfGeom.parent = geom.parent 542 glfGeom.name = geom.name 543 glfGeom.fullName = geom.fullName 544 glfGeom.instanceMatrices = geom.instanceMatrices 545 glfGeom.instanceMatricesIndex = geom.instanceMatricesIndex 546 glfGeom.VRML2CreatedPROTOForThisGeom = 0 547 self.output.extend( self.doit(glfGeom, matrix) )
548 549
550 - def doit(self, geom, matrix):
551 # gets called from NodeRepr() 552 vrml2 = [] 553 554 # if self.usePROTO is set to 1: don't convert instance matrices 555 # geoms into geoms, but use the vrml2 USE 556 if self.usePROTOFlag: 557 # create all the necessary data to be put in the PROTO which goes 558 # in the header of the vrml2 file 559 if geom.VRML2CreatedPROTOForThisGeom == 0: 560 name = self.getGeomName(geom) 561 vrml2.append("PROTO "+name+" [ ] {\n") 562 identityMatrix = Numeric.identity(4).astype('f') 563 vrml2.extend( self.doitReally(geom, identityMatrix) ) 564 vrml2.append("}\n") 565 566 # now insert this into the header of self.output 567 for i in range(len(vrml2)): 568 self.output.insert(i+1,vrml2[i]) 569 geom.VRML2CreatedPROTOForThisGeom = 1 # don't add this geom 570 # to the header next time 571 # this PROTO flag will be deleted when we leave the recursive 572 573 # and add it as USE to the body 574 vrml2 = [] # clear the list because this data has been added 575 vrml2.extend( self.doitUsePROTO(geom, matrix) ) 576 return vrml2 577 578 else: 579 # here we save all the data for all geoms 580 return self.doitReally(geom, matrix)
581 582
583 - def doitReally(self, geom, matrix):
584 # add header for geom 585 vrml2 = [] 586 587 vrml2.extend(self.getGeomHeader(geom)) 588 vrml2.extend(self.getShape()) 589 vrml2.extend(self.getAppearance()) 590 mat, colors = self.getMaterial(geom) 591 vrml2.extend(mat) 592 593 # add texture if applicable: 594 if geom.texture: 595 vrml2.extend( self.getTexture(geom) ) 596 597 vrml2.append(" }\n") 598 vrml2.append("\n") 599 600 # add coords, faces, etc 601 vrml2.extend( self.getGeomDescr(geom) ) 602 603 # add texCoord Coordinates is applicable 604 if geom.texture: 605 vrml2.extend( self.getTexCoords(geom) ) 606 607 # add texCoordsIndex if applicable 608 if hasattr(geom.vertexSet,'texCoordsIndex'): 609 vrml2.extend( self.getTexCoordsIndex(geom)) 610 611 # add normals if applicable 612 if self.saveNormalsFlag and isinstance(geom, IndexedPolygons): 613 vrml2.extend( self.getNormals(geom) ) 614 615 # add colors per vertex if applicable 616 if colors: 617 vrml2.extend( self.getColors(geom, colors) ) 618 619 # add closing brackets for geom 620 vrml2.append(" }\n") 621 vrml2.append(" }\n") 622 623 # add transformations for geom 624 vrml2.extend( self.getTransforms(matrix) ) 625 626 # add closing bracket for Transform{} 627 vrml2.append(" }\n") 628 return vrml2
629 630
631 - def doitUsePROTO(self, geom, matrix):
632 # FIXME: this works currently only with geoms that are not grouped 633 # i.e. it doesnt work with secondary structures, they will be saved 634 # as PROTO too, but also for each instanceMatrix (->redundant) 635 636 vrml2 = [] 637 638 geom.instanceMatricesIndex = 0 639 name = string.split(self.getGeomHeader(geom)[0])[1] 640 vrml2.append(" Transform {\n") 641 vrml2.append(" children "+name+" { }\n") 642 643 # add transformations for geom 644 vrml2.extend( self.getTransforms(matrix) ) 645 646 # add closing bracket for Transform{} 647 vrml2.append(" }\n") 648 return vrml2
649 650 651
652 - def getFileHeader1(self):
653 vrml2=[] 654 vrml2.append("#VRML V2.0 utf8 Python Molecular Viewer Geom\n") 655 vrml2.append("\n") 656 return vrml2
657 658
659 - def getCopyright(self):
660 vrml2=[] 661 vrml2.append("WorldInfo {\n") 662 663 vrml2.append(' title ""\n') 664 vrml2.append(" info [\n") 665 vrml2.append(' "Copyright (c) 2002 D. Stoffler, M.F. Sanner and A.J. Olson"\n') 666 vrml2.append(' "Molecular Graphics Lab"\n') 667 vrml2.append(' "The Scripps Research Institute, La Jolla, CA"\n') 668 vrml2.append(' "VRML2 file generated with the Python Molecular Viewer:"\n') 669 vrml2.append(' "http://www.scripps.edu/~sanner/python/pmv/"\n') 670 vrml2.append(" ]\n") 671 vrml2.append("}\n") 672 return vrml2
673 674
675 - def getFileHeader2(self):
676 vrml2=[] 677 vrml2.append("Group {\n") 678 vrml2.append(" children [\n") 679 return vrml2
680 681
682 - def getFileTrailer(self):
683 vrml2=[] 684 vrml2.append(" ]\n") 685 vrml2.append("}\n") 686 return vrml2
687 688
689 - def getGeomName(self, geom):
690 g = geom 691 name = "Pmv_" 692 while g != geom.viewer.rootObject: 693 # g.name can contain whitespaces which we have to get rid of 694 gname = string.split(g.name) 695 ggname = "" 696 for i in gname: 697 ggname = ggname + i 698 name = name + string.strip(ggname)+"AT"+\ 699 string.strip(str(g.instanceMatricesIndex))+ '_' 700 g = g.parent 701 return name
702 703
704 - def getGeomHeader(self, geom):
705 # generates geom name 706 vrml2=[] 707 g = geom 708 name = self.getGeomName(geom) 709 vrml2.append(" DEF "+name+" Transform {\n") 710 return vrml2
711 712
713 - def getShape(self):
714 vrml2=[] 715 vrml2.append(" children Shape {\n") 716 return vrml2
717 718
719 - def getAppearance(self):
720 vrml2=[] 721 vrml2.append(" appearance Appearance {\n") 722 return vrml2
723 724
725 - def getMaterial(self, geom):
726 vrml2=[] 727 728 mat = geom.materials[GL.GL_FRONT].prop[:] 729 geom.materials[GL.GL_FRONT].colorIndex = None # will be used later on 730 colors = None 731 732 # if only 1 color present, skip this all and use the ambient definition 733 # below 734 if len(mat[1])> 1: 735 colors = mat[1] 736 737 # The ZCorp printer software doesn't support color_per_face, 738 # but Pmv does. So, we create a colorIndex list for special cases 739 # However, the user can still choose between coloring 740 # per face and per vertex 741 742 # FIXME: test for primitive type, i.e. tri_strip or quad_strip 743 # currently this works only for tri_strips 744 if isinstance(geom, GleExtrude): # special case! 745 faces = geom.faceSet.faces.array # triangle_strips 746 ifaces = geom.getFaces() # indexed geom 747 748 # if the user forces to save color per vertex: 749 if self.colorPerVertexFlag is True: 750 colorIndex = Numeric.zeros( (ifaces.shape[0], \ 751 ifaces.shape[1]) ) 752 c = 0 753 cc = 0 754 for face in faces: 755 for j in range(len(face)-2): # -2 because of tri_strip 756 colorIndex[cc] = c 757 cc = cc + 1 758 c = c + 1 759 geom.materials[GL.GL_FRONT].colorIndex = colorIndex 760 761 elif isinstance(geom, IndexedPolygons): 762 mat[1]=[mat[1][0]] 763 vertices = geom.getVertices() 764 faces = geom.getFaces() 765 766 # if current colors are per face: 767 if len(colors) != len(vertices) and len(colors) == len(faces): 768 # if the user forces colors per vertices: 769 if self.colorPerVertexFlag is True: 770 colorIndex = Numeric.zeros( (faces.shape[0], \ 771 faces.shape[1]) ) 772 c = 0 773 for face in faces: 774 for f in face: 775 colorIndex[c] = c 776 c = c + 1 777 geom.materials[GL.GL_FRONT].colorIndex = colorIndex 778 779 # if current colors are per vertex 780 else: 781 # if the user forces colors per face: 782 if self.colorPerVertexFlag is False: 783 # code from Michel Sanner follows (thanks Michel!): 784 vcol = geom.materials[1028].prop[1] 785 tri = geom.faceSet.faces.array 786 verts= geom.vertexSet.vertices.array 787 colors = [] 788 for t in tri: 789 s1,s2,s3 = t 790 col = ( (vcol[s1][0]+vcol[s2][0]+vcol[s3][0])/3., 791 (vcol[s1][1]+vcol[s2][1]+vcol[s3][1])/3., 792 (vcol[s1][2]+vcol[s2][2]+vcol[s3][2])/3. ) 793 colors.append( col) 794 795 796 797 ambInt = '%.5f'%mat[0][0][0] 798 difCol = '%.5f'%mat[1][0][0]+" "+'%.5f'%mat[1][0][1]+" "+\ 799 '%.5f'%mat[1][0][2] 800 emCol = '%.5f'%mat[2][0][0]+" "+'%.5f'%mat[2][0][1]+" "+\ 801 '%.5f'%mat[2][0][2] 802 specCol = '%.5f'%mat[3][0][0]+" "+'%.5f'%mat[3][0][1]+" "+\ 803 '%.5f'%mat[3][0][2] 804 shin = '%.5f'%mat[4][0] 805 trans = `1-mat[5][0]` 806 807 vrml2.append(" material Material {\n") 808 vrml2.append(" ambientIntensity "+ambInt+"\n") 809 vrml2.append(" diffuseColor "+difCol+"\n") 810 vrml2.append(" emissiveColor "+emCol+"\n") 811 vrml2.append(" specularColor "+specCol+"\n") 812 vrml2.append(" shininess "+shin+"\n") 813 vrml2.append(" transparency "+trans+"\n") 814 vrml2.append(" }\n") 815 return vrml2, colors
816 817
818 - def getGeomDescr(self, geom):
819 vrml2 = [] 820 821 if isinstance(geom, IndexedPolygons): 822 vrml2.append(" geometry IndexedFaceSet {\n") 823 # add vertices 824 vrml2.extend( self.getCoords(geom) ) 825 # add face indices 826 vrml2.extend( self.getFaces(geom) ) 827 # add color indices if applicable 828 if geom.materials[GL.GL_FRONT].colorIndex: 829 vrml2.extend( self.getColorIndex(geom) ) 830 831 elif isinstance(geom, IndexedPolylines): 832 vrml2.append(" geometry IndexedLineSet {\n") 833 # add vertices 834 vrml2.extend( self.getCoords(geom) ) 835 # add face indices 836 vrml2.extend( self.getFaces(geom) ) 837 838 return vrml2
839 840 841 ## added by A Gillet 04/13/2006
842 - def getTexture(self,geom):
843 """ return PixelTexture Node 844 PixelTexture { 845 image 0 0 0 # exposedField SFImage 846 repeatS True # field SFBool 847 repeatT True # field SFBool 848 } 849 850 the value of the image field specifies image size and pixel values 851 for a texture image 852 width (in pixel) 853 height (in pixel) 854 number of 8-bit bytes for each pixel 855 recognize values are: 856 0 disable texturing for shape 857 1 Grayscale 858 2 Grayscale with alpha 859 3 RGB 860 4 RGB with alpha 861 (Info taken from Book " VRML 2.0 source book by Andrea L. Ames, 862 David R. Nadeau and John L. Moreland ") 863 864 """ 865 866 867 vrml2=[] 868 tex = geom.texture 869 dims = tex.image.shape 870 871 vrml2.append("\n") 872 vrml2.append(" texture PixelTexture {\n") 873 width = dims[0] 874 if len(dims) == 3: 875 height = dims[1] 876 num_byte = dims[2] 877 elif len(dims)==1: 878 height = 1 879 num_byte = len(tex.image[0]) 880 elif len(dims)==2: 881 height = 1 882 num_byte = dims[1] 883 884 vrml2.append(" image "+`width`+" "+`height`+" "+`num_byte`+"\n") 885 886 if len(dims) == 3: 887 # we have a 2D texture (image) 888 countW =0 889 for r in tex.image: # row 890 for c in r: # column 891 istring = "0x" 892 for i in range(3): 893 hexa = "%X"%c[i] 894 if len(hexa)==1: hexa = "0"+hexa 895 istring = istring+ hexa 896 istring = istring + " " 897 vrml2.append(istring) 898 vrml2.append("\n") 899 vrml2.append(" }\n") 900 901 else: 902 # we have a 1-dimensional array 903 for line in tex.image: 904 istring = "0x" 905 for i in range(len(line)): 906 hexa = "%X"%line[i] 907 if len(hexa)==1: hexa = "0"+hexa 908 istring = istring+ hexa 909 istring = istring + "\n" 910 vrml2.append(istring) 911 vrml2.append(" }\n") 912 return vrml2
913 914 915 916 917 ## Daniel Stoffler code 918 ## def getTexture(self, geom): 919 ## vrml2=[] 920 ## dims = geom.texture.image.shape 921 ## vrml2.append("\n") 922 ## vrml2.append(" texture PixelTexture {\n") 923 ## # FIXME : what are real dimensions of image? 924 ## # I never tested this for images larger than one-dimensional array 925 ## vrml2.append(" image "+`dims[0]`+" "+`1`+" "+\ 926 ## `len(geom.texture.image[0])`+"\n") 927 ## for line in geom.texture.image: 928 ## istring = "0x" 929 ## for i in range(len(line)): 930 ## hexa = "%X"%line[i] 931 ## if len(hexa)==1: hexa = "0"+hexa 932 ## istring = istring+ hexa 933 ## istring = istring + "\n" 934 ## vrml2.append(istring) 935 ## vrml2.append(" }\n") 936 ## return vrml2 937 938
939 - def getCoords(self, geom):
940 vrml2=[] 941 vertices = geom.getVertices() 942 vrml2.append(" coord Coordinate {\n") 943 vrml2.append(" point [\n") 944 for vert in vertices: 945 vstring = " "+'%.5f'%vert[0]+" "+\ 946 '%.5f'%vert[1]+" "+'%.5f'%vert[2]+",\n" 947 vrml2.append(vstring) 948 vrml2.append(" ]\n") 949 vrml2.append(" }\n") 950 return vrml2
951 952
953 - def getFaces(self, geom):
954 #print "getFaces" 955 vrml2=[] 956 faces = geom.getFaces() 957 vrml2.append(" coordIndex [\n") 958 959 for face in faces: 960 facestring = " " 961 if geom.invertNormals: # reverse faces 962 facestring = facestring + `face[0]` + ", " 963 for i in range(len(face)-1,0,-1): 964 facestring = facestring + `face[i]` + ", " 965 else: 966 for f in face: 967 facestring = facestring + `f` + ", " 968 969 facestring = facestring + "-1,\n" 970 vrml2.append(facestring) 971 vrml2.append(" ]\n") 972 return vrml2
973 974
975 - def getColorIndex(self, geom):
976 # only called if len(colors) != len(faces) 977 vrml2 = [] 978 colorIndex = geom.materials[GL.GL_FRONT].colorIndex 979 vrml2.append(" colorIndex [\n") 980 for cI in colorIndex: 981 cIstring = " " 982 for c in cI: 983 cIstring = cIstring + `c` +", " 984 cIstring = cIstring + "-1,\n" 985 vrml2.append(cIstring) 986 vrml2.append(" ]\n") 987 # clean up the geom object 988 del geom.materials[GL.GL_FRONT].colorIndex 989 return vrml2
990 991
992 - def getNormals(self, geom):
993 if geom.invertNormals: 994 fn = -1.0 * geom.normals 995 else: 996 fn = geom.normals 997 998 vrml2=[] 999 vrml2.append(" normal Normal {\n") 1000 vrml2.append(" vector [\n") 1001 for n in fn: 1002 vrml2.append(" %.5f"%n[0]+" %.5f"%n[1]+\ 1003 " %.5f"%n[2]+" \n") 1004 vrml2.append(" ]\n") 1005 vrml2.append(" }\n") 1006 return vrml2
1007 1008
1009 - def getTexCoords(self, geom):
1010 vrml2=[] 1011 vrml2.append("\n") 1012 vrml2.append(" texCoord TextureCoordinate {\n") 1013 vrml2.append(" point [\n") 1014 for p in geom.vertexSet.texCoords.array: 1015 if len(p) == 1: # one dimension array 1016 vrml2.append(" "+`p[0]`+" 0,\n") 1017 else: 1018 vrml2.append(" "+`p[0]`+" "+`p[1]`+",\n") 1019 vrml2.append(" ]\n") 1020 vrml2.append(" }\n") 1021 return vrml2
1022
1023 - def getTexCoordsIndex(self, geom):
1024 vrml2=[] 1025 texCoordsIndex = geom.vertexSet.texCoordsIndex.array 1026 vrml2.append(" texCoordIndex [\n") 1027 1028 for face in texCoordsIndex: 1029 indexstring = " " 1030 for i in face: 1031 indexstring = indexstring + `i` + ", " 1032 1033 indexstring = indexstring + "-1,\n" 1034 vrml2.append(indexstring) 1035 vrml2.append(" ]\n") 1036 return vrml2
1037 1038
1039 - def getColors(self, geom, colors):
1040 vrml2=[] 1041 vrml2.append("\n") 1042 vrml2.append(" colorPerVertex %s\n"%string.upper( 1043 str(self.colorPerVertexFlag))) # TRUE or FALSE ... capital letters 1044 vrml2.append(" color Color {\n") 1045 vrml2.append(" color [\n") 1046 for c in colors: 1047 cstring = ' %.3f'%c[0]+" "+'%.3f'%c[1]+\ 1048 " "+'%.3f'%c[2]+",\n" 1049 vrml2.append(cstring) 1050 vrml2.append(" ]\n") 1051 vrml2.append(" }\n") 1052 return vrml2
1053 1054
1055 - def getTransforms(self, matrix):
1056 vrml2=[] 1057 #mymatrix = matrix.__copy__() 1058 #mymatrix = Numeric.reshape(mymatrix, (16,)) 1059 mymatrix = Numeric.reshape(matrix, (16,)) 1060 rot,trans,scale=self.Transformable.Decompose4x4(mymatrix) 1061 r = rotax.mat_to_quat(rot) 1062 r[3]=r[3]*math.pi/180.0 #convert to rad 1063 r[0] = round(r[0],6) 1064 r[1] = round(r[1],6) 1065 r[2] = round(r[2],6) 1066 r[3] = round(r[3],6) 1067 vrml2.append(" translation "+`trans[0]`+" "+`trans[1]`+" "+\ 1068 `trans[2]`+"\n") 1069 vrml2.append(" rotation "+`r[0]`+" "+`r[1]`+" "+\ 1070 `r[2]`+" "+`r[3]`+"\n") 1071 vrml2.append(" scale "+`scale[0]`+" "+`scale[1]`+" "+\ 1072 `scale[2]`+"\n") 1073 return vrml2
1074 1075
1076 -class DatGUI:
1077 """ basic gui for DataOutput """ 1078
1079 - def __init__(self, master=None, title=None):
1080 self.master = master 1081 self.root = None 1082 self.title = title 1083 if self.title is None: 1084 self.title = 'Options Panel' 1085 1086 if self.master is None: 1087 self.master = Tkinter.Frame() 1088 self.master.pack() 1089 1090 self.sphInput = Tkinter.StringVar() 1091 self.cylInput = Tkinter.StringVar() 1092 1093 self.sphereQuality = 2 # values range from 0 to open end 1094 self.cylinderQuality = 10 # values range from 3 to open end 1095 1096 self.readyToRun = 0 # set to 1 in OK_cb, set to 0 in Cancel_cb 1097 1098 self.idf = InputFormDescr(title=self.title)
1099 1100
1101 - def sphereQuality_cb(self, event=None):
1102 val = self.sphInput.get() 1103 if len(val) == 0 or val is None: 1104 val = self.sphereQuality 1105 try: 1106 val = int(val) 1107 if val < 0: 1108 val = 0 1109 self.sphereQuality = val 1110 self.sphInput.set(str(self.sphereQuality)) 1111 except ValueError: 1112 self.sphInput.set(str(self.sphereQuality))
1113 1114
1115 - def cylinderQuality_cb(self, event=None):
1116 val = self.cylInput.get() 1117 if len(val) == 0 or val is None: 1118 val = self.cylinderQuality 1119 try: 1120 val = int(val) 1121 if val < 3: 1122 val = 3 1123 self.cylinderQuality = val 1124 self.cylInput.set(str(self.cylinderQuality)) 1125 except ValueError: 1126 self.sphInput.set(str(self.cylinderQuality))
1127 1128
1129 - def OK_cb(self):
1130 self.readyToRun = 1 1131 self.sphereQuality_cb() 1132 self.cylinderQuality_cb() 1133 self.master.grab_release() 1134 self.master.quit() 1135 self.optionsForm.withdraw()
1136 1137
1138 - def Cancel_cb(self):
1139 self.readyToRun = 0 1140 self.master.grab_release() 1141 self.master.quit() 1142 self.optionsForm.withdraw()
1143 1144
1145 - def displayPanel(self, create):
1146 self.readyToRun = 0 1147 if create == 0: 1148 self.optionsForm.deiconify() 1149 else: 1150 self.optionsForm = InputForm(self.master, self.root, 1151 descr=self.idf,okcancel=0) 1152 # grab the focus, i.e. the program stops until OK or Cancel is pressed 1153 self.master.grab_set() 1154 self.master.mainloop()
1155 1156
1157 - def getValues(self):
1158 vals = {} 1159 vals['sphereQuality'] = self.sphereQuality 1160 vals['cylinderQuality'] = self.cylinderQuality 1161 return vals
1162 1163
1164 -class STLGUI(DatGUI):
1165 """ this is the gui for OutputSTL 1166 - Save normals adds normals to all geoms to be saved as vrml2 1167 - Invert normals inverts the normals for all geoms to be saved as vrml2 1168 - Sphere quality is the subsampling of the spheres. Default value is 2 1169 lowest allowed value is 0. Higher values increase the file size 1170 significantly. 1171 - Cylinder quality is the subsampling of cylinders. Default value is 10 1172 lowest allowed value is 3.""" 1173
1174 - def __init__(self, master=None, title=None):
1175 DatGUI.__init__(self, master, title) 1176 1177 self.createForm()
1178
1179 - def createForm(self):
1180 self.idf.append({'widgetType':Tkinter.Frame, 1181 'wcfg':{'relief':'sunken','borderwidth':2,'height':2}, 1182 'gridcfg':{'columnspan':2, 'row':1, 'column':0}, 1183 }) 1184 1185 self.idf.append({'widgetType':Tkinter.Frame, 1186 'wcfg':{'relief':'sunken','borderwidth':2,'height':2}, 1187 'gridcfg':{'columnspan':2, 'row':2, 'column':0}, 1188 }) 1189 1190 self.idf.append({'widgetType':Tkinter.Label, 1191 'wcfg':{'text':'Sphere quality'}, 1192 'gridcfg':{'sticky':'w','columnspan':2, 'row':3, 'column':0}, 1193 }) 1194 1195 self.idf.append({'name':'inpSphQual', 1196 'widgetType':Tkinter.Entry, 1197 'defaultValue':'2', 1198 'wcfg':{'font':('Courier',10), 1199 'width':5,'textvariable':self.sphInput, 1200 'command':self.sphereQuality_cb, 1201 }, 1202 'gridcfg':{'sticky':'e', 1203 'columnspan':2, 'row':3, 'column':1 } 1204 }) 1205 1206 self.idf.append({'widgetType':Tkinter.Label, 1207 'wcfg':{'text':'Cylinder quality'}, 1208 'gridcfg':{'sticky':'w','columnspan':2, 'row':4, 'column':0}, 1209 }) 1210 1211 self.idf.append({'name':'inpCylQual', 1212 'widgetType':Tkinter.Entry, 1213 'defaultValue':'10', 1214 'wcfg':{'font':('Courier',10), 1215 'width':5,'textvariable':self.cylInput, 1216 'command':self.cylinderQuality_cb, 1217 }, 1218 'gridcfg':{'sticky':'e', 1219 'columnspan':2, 'row':4, 'column':1 } 1220 }) 1221 1222 self.idf.append({'widgetType':Tkinter.Button, 1223 'text':'OK', 1224 'wcfg':{}, 1225 'gridcfg':{'sticky':'wens', 1226 'columnspan':1, 'row':5, 'column':0}, 1227 'command': self.OK_cb}) 1228 1229 1230 self.idf.append({'widgetType':Tkinter.Button, 1231 'text':'Cancel', 1232 'wcfg':{}, 1233 'gridcfg':{'sticky':'wens', 1234 'columnspan':1, 'row':5, 'column':1}, 1235 'command': self.Cancel_cb})
1236 1237
1238 - def invertNormals_cb(self):
1239 pass
1240 1241
1242 -class VRML2GUI(DatGUI):
1243 """This is the gui for OutputVRML2: 1244 - Save normals adds normals to all geoms to be saved as vrml2 1245 - Invert normals inverts the normals for all geoms to be saved as vrml2 1246 - colorPerVertex: True by default. If set to False, color per face is used 1247 - Using PROTO will define a prototype geom which can be reused. This 1248 is usefull to lower the file size when instanceMatrices are applied. 1249 - Sphere quality is the subsampling of the spheres. Default value is 2 1250 lowest allowed value is 0. Higher values increase the file size 1251 significantly. 1252 - Cylinder quality is the subsampling of cylinders. Default value is 10 1253 lowest allowed value is 3. 1254 """ 1255
1256 - def __init__(self, master=None, title=None):
1257 DatGUI.__init__(self, master, title) 1258 1259 self.saveNormals = Tkinter.IntVar() 1260 self.colorPerVertex = Tkinter.IntVar() 1261 self.colorPerVertex.set(1) # on by default 1262 self.usePROTO = Tkinter.IntVar() 1263 1264 self.createForm()
1265
1266 - def createForm(self):
1267 row = 0 1268 self.idf.append({'name':'savNormals', 1269 'widgetType':Tkinter.Checkbutton, 1270 'wcfg':{'text':'Save Normals ', 1271 'variable':self.saveNormals, 1272 'command':self.saveNormals_cb}, 1273 'gridcfg':{'sticky':'w', 1274 'columnspan':2, 'row':row, 'column':0} 1275 }) 1276 row+= 1 1277 self.idf.append({'widgetType':Tkinter.Frame, 1278 'wcfg':{'relief':'sunken','borderwidth':2,'height':2}, 1279 'gridcfg':{'columnspan':2, 'row':row, 'column':0}, 1280 }) 1281 1282 row += 1 1283 self.idf.append({'name':'colorPerVertex', 1284 'widgetType':Tkinter.Checkbutton, 1285 'wcfg':{'text':'color per vertex', 1286 'variable':self.colorPerVertex, 1287 'command':self.colorPerVertex_cb}, 1288 'gridcfg':{'sticky':'w', 1289 'columnspan':2, 'row':row, 'column':0} 1290 }) 1291 1292 row+= 1 1293 self.idf.append({'widgetType':Tkinter.Frame, 1294 'wcfg':{'relief':'sunken','borderwidth':2,'height':2}, 1295 'gridcfg':{'columnspan':2, 'row':row, 'column':0}, 1296 }) 1297 1298 row+= 1 1299 self.idf.append({'name':'usePROTO', 1300 'widgetType':Tkinter.Checkbutton, 1301 'wcfg':{'text':'Use PROTO for instance\n'+\ 1302 'matrices to lower file size', 1303 'variable':self.usePROTO, 1304 'command':self.usePROTO_cb}, 1305 'gridcfg':{'sticky':'w', 1306 'columnspan':2, 'row':row, 'column':0} 1307 }) 1308 row+= 1 1309 self.idf.append({'widgetType':Tkinter.Frame, 1310 'wcfg':{'relief':'sunken','borderwidth':2,'height':2}, 1311 'gridcfg':{'columnspan':2, 'row':row, 'column':0}, 1312 }) 1313 1314 row+= 1 1315 self.idf.append({'widgetType':Tkinter.Label, 1316 'wcfg':{'text':'Sphere quality'}, 1317 'gridcfg':{'sticky':'w','columnspan':2, 'row':row, 1318 'column':0}, 1319 }) 1320 1321 self.idf.append({'name':'inpSphQual', 1322 'widgetType':Tkinter.Entry, 1323 'defaultValue':'2', 1324 'wcfg':{'font':('Courier',10), 1325 'width':5,'textvariable':self.sphInput, 1326 'command':self.sphereQuality_cb, 1327 }, 1328 'gridcfg':{'sticky':'e', 1329 'columnspan':2, 'row':row, 'column':1 } 1330 }) 1331 row+= 1 1332 self.idf.append({'widgetType':Tkinter.Label, 1333 'wcfg':{'text':'Cylinder quality'}, 1334 'gridcfg':{'sticky':'w','columnspan':2, 'row':row, 1335 'column':0}, 1336 }) 1337 1338 self.idf.append({'name':'inpCylQual', 1339 'widgetType':Tkinter.Entry, 1340 'defaultValue':'10', 1341 'wcfg':{'font':('Courier',10), 1342 'width':5,'textvariable':self.cylInput, 1343 'command':self.cylinderQuality_cb, 1344 }, 1345 'gridcfg':{'sticky':'e', 1346 'columnspan':2, 'row':row, 'column':1 } 1347 }) 1348 1349 row+= 1 1350 self.idf.append({'widgetType':Tkinter.Button, 1351 'text':'OK', 1352 'wcfg':{}, 1353 'gridcfg':{'sticky':'wens', 1354 'columnspan':1, 'row':row, 'column':0}, 1355 'command': self.OK_cb}) 1356 1357 1358 self.idf.append({'widgetType':Tkinter.Button, 1359 'text':'Cancel', 1360 'wcfg':{}, 1361 'gridcfg':{'sticky':'wens', 1362 'columnspan':1, 'row':row, 'column':1}, 1363 'command': self.Cancel_cb})
1364 1365 1366
1367 - def saveNormals_cb(self):
1368 pass
1369 1370
1371 - def colorPerVertex_cb(self):
1372 pass
1373 1374
1375 - def usePROTO_cb(self):
1376 pass
1377 1378
1379 - def getValues(self):
1380 vals = {} 1381 vals['saveNormals'] = self.saveNormals.get() 1382 co = self.colorPerVertex.get() 1383 if co == 1: 1384 co = True 1385 else: 1386 co = False 1387 vals['colorPerVertex'] = co 1388 vals['usePROTO'] = self.usePROTO.get() 1389 vals['sphereQuality'] = self.sphereQuality 1390 vals['cylinderQuality'] = self.cylinderQuality 1391 return vals
1392