home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / cgkit / offimport.py < prev    next >
Encoding:
Python Source  |  2007-01-11  |  10.0 KB  |  309 lines

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is the Python Computer Graphics Kit.
  15. #
  16. # The Initial Developer of the Original Code is Matthias Baas.
  17. # Portions created by the Initial Developer are Copyright (C) 2004
  18. # the Initial Developer. All Rights Reserved.
  19. #
  20. # Contributor(s):
  21. #
  22. # Alternatively, the contents of this file may be used under the terms of
  23. # either the GNU General Public License Version 2 or later (the "GPL"), or
  24. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25. # in which case the provisions of the GPL or the LGPL are applicable instead
  26. # of those above. If you wish to allow use of your version of this file only
  27. # under the terms of either the GPL or the LGPL, and not to allow others to
  28. # use your version of this file under the terms of the MPL, indicate your
  29. # decision by deleting the provisions above and replace them with the notice
  30. # and other provisions required by the GPL or the LGPL. If you do not delete
  31. # the provisions above, a recipient may use your version of this file under
  32. # the terms of any one of the MPL, the GPL or the LGPL.
  33. #
  34. # ***** END LICENSE BLOCK *****
  35. # $Id: offimport.py,v 1.3 2005/04/14 08:01:50 mbaas Exp $
  36.  
  37. import os.path, sys
  38. from cgtypes import *
  39. from worldobject import WorldObject
  40. from geomobject import *
  41. from trimesh import TriMesh
  42. from trimeshgeom import TriMeshGeom
  43. from polyhedron import Polyhedron
  44. from polyhedrongeom import PolyhedronGeom
  45. import pluginmanager
  46.  
  47. # OffImporter
  48. class OffImporter:
  49.  
  50.     _protocols = ["Import"]
  51.  
  52.     # extension
  53.     def extension():
  54.         """Return the file extensions for this format."""
  55.         return ["off"]
  56.     extension = staticmethod(extension)
  57.  
  58.     # description
  59.     def description(self):
  60.         """Return a short description for the file dialog."""
  61.         return "Geomview OFF file"
  62.     description = staticmethod(description)
  63.  
  64.     # importFile
  65.     def importFile(self, filename, invertfaces=False):
  66.         """Import an OFF file.
  67.  
  68.         If invertfaces is True the orientation of each face is reversed.
  69.         """
  70.  
  71.         self.invertfaces = invertfaces
  72.  
  73.         self.texcoord_flag = False
  74.         self.color_flag = False
  75.         self.normal_flag = False
  76.         self.four_flag = False
  77.         self.ndim_flag = False
  78.         self.ndim = 3
  79.         self.is_trimesh = True
  80.  
  81.         self.fhandle = file(filename)
  82.  
  83.         # Read the header
  84.         z = self.readLine()
  85.         self.parseHeaderKeyWord(z)
  86.  
  87.         # nOFF?
  88.         if self.ndim_flag:
  89.             # Read the dimension of vertices
  90.             z = self.readLine()
  91.             self.ndim = int(z)
  92.             if self.ndim>3:
  93.                 raise ValueError, "A vertex space dimension of %d is not supported"%(self.ndim)
  94.  
  95.         # Read the number of vertices and faces...
  96.         z = self.readLine().split(" ")
  97.         self.numverts = int(z[0])
  98.         self.numfaces = int(z[1])
  99.  
  100.         # Start with a TriMeshGeom
  101.         # (this will be later converted into a PolyhedronGeom if faces
  102.         # with more than 3 vertices are encountered)
  103.         self.geom = TriMeshGeom()
  104.         self.geom.verts.resize(self.numverts)
  105.         self.geom.faces.resize(self.numfaces)
  106.  
  107.         # Read the vertices...
  108.         self.readVertices()
  109.  
  110.         # Read the faces...
  111.         self.readFaces()
  112.  
  113.         self.fhandle.close()
  114.  
  115.         # Create the actual object...
  116.         nodename = os.path.basename(filename)
  117.         nodename = os.path.splitext(nodename)[0]
  118.         nodename = nodename.replace(" ","_")
  119.         if self.is_trimesh:
  120.             n = TriMesh(name=nodename)
  121.         else:
  122.             n = Polyhedron(name=nodename)
  123.         n.geom = self.geom
  124.  
  125.     # readFaces
  126.     def readFaces(self):
  127.         """Read the faces.
  128.         """
  129.         geom = self.geom
  130.  
  131.         Cs = None
  132.         
  133.         for i in range(self.numfaces):
  134.             z = self.readLine()
  135.             a = z.split()
  136.             # Get the number of vertices in this face
  137.             Nv = int(a[0])
  138.             if Nv<3:
  139.                 print >>sys.stderr, "Warning: Faces must have at least three vertices"
  140.                 continue
  141.  
  142.             # Set the face...
  143.             face = map(lambda x: int(x), a[1:Nv+1])
  144.             if self.invertfaces:
  145.                 face.reverse()
  146.             if self.is_trimesh:
  147.                 if Nv==3:
  148.                     geom.faces[i] = face
  149. #                    geom.faces[i] = (int(a[1]), int(a[3]), int(a[2]))
  150.                 else:
  151.                     # Convert the TriMeshGeom into a PolyhedronGeom...
  152.                     tm = self.geom
  153.                     geom = self.triMesh2Polyhedron(tm)
  154.                     self.geom = geom
  155.                     self.is_trimesh = False
  156.                     # Get the Cs slot (if there is one)
  157.                     try:
  158.                         Cs = geom.slot("Cs")
  159.                     except:
  160.                         Cs = None
  161.                     # Initialize the faces processed so far...
  162.                     for j in range(i):
  163.                         self.geom.setPoly(j, [tm.faces[j]])
  164.                     # ...and set the current face
  165.                     self.geom.setPoly(i, [face])
  166.             else:
  167.                 geom.setPoly(i, [face])
  168.  
  169.             # Process color...
  170.             ca = a[Nv+1:]
  171.             if len(ca)>2:
  172.                 # Check and see if the rgb values are given as ints, in this
  173.                 # case they have to be scaled down.
  174.                 try:
  175.                     r = int(ca[0])
  176.                     g = int(ca[1])
  177.                     b = int(ca[2])
  178.                     col = vec3(r,g,b)/255
  179.                 except:
  180.                     r = float(ca[0])
  181.                     g = float(ca[1])
  182.                     b = float(ca[2])
  183.                     col = vec3(r,g,b)
  184.                     
  185.                 if Cs==None:
  186.                     geom.newVariable("Cs", UNIFORM, COLOR)
  187.                     Cs = geom.slot("Cs")
  188.  
  189.                 Cs[i] = col
  190.                     
  191.  
  192.     # triMesh2Polyhedron
  193.     def triMesh2Polyhedron(self, tm):
  194.         """Convert a TriMeshGeom into a PolyhedronGeom.
  195.         """
  196.         pg = PolyhedronGeom()
  197.         # Copy the vertices...
  198.         pg.verts.resize(tm.verts.size())
  199.         tm.verts.copyValues(0, tm.verts.size(), pg.verts, 0)
  200.         # Allocate polygons...
  201.         pg.setNumPolys(tm.faces.size())
  202.  
  203.         # Copy primitive variables...
  204.         # (tm must not have any facevarying or facevertex variables)
  205.         for name, storage, type, mult in tm.iterVariables():
  206.             slot = tm.slot(name)
  207.             pg.newVariable(name, storage, type, mult, slot.size())
  208.             newslot = pg.slot(name)
  209.             slot.copyValues(0, slot.size(), newslot, 0)
  210.  
  211.         return pg
  212.         
  213.     # readVertices
  214.     def readVertices(self):
  215.         """Read the vertices (and varying variables).
  216.  
  217.         The number of vertices must have been stored in self.numverts
  218.         and the ST, C, N flags must have been initialized. self.geom must
  219.         be either a TriMeshGeom or a PolyhedronGeom.
  220.         """
  221.         geom = self.geom
  222.         
  223.         # Create primitive variables...
  224.         if self.normal_flag:
  225.             geom.newVariable("N", VARYING, NORMAL)
  226.             N = geom.slot("N")
  227.         if self.color_flag:
  228.             geom.newVariable("Cs", VARYING, COLOR)
  229.             Cs = geom.slot("Cs")
  230.         if self.texcoord_flag:
  231.             geom.newVariable("st", VARYING, FLOAT, 2)
  232.             st = geom.slot("st")
  233.         
  234.         # Read the vertices...
  235.         for i in range(self.numverts):
  236.             z = self.readLine()
  237.             f = map(lambda x: float(x), z.split())
  238.             geom.verts[i] = vec3(f[:self.ndim])
  239.             f = f[self.ndim:]
  240.             if self.four_flag:
  241.                 w = f[0]
  242.                 geom.verts[i] /= w
  243.                 f = f[1:]
  244.             if self.normal_flag:
  245.                 N[i] = vec3(f[:3])
  246.                 f = f[3:]
  247.             if self.color_flag:
  248.                 Cs[i] = vec3(f[:3])
  249.                 f = f[3:]
  250.             if self.texcoord_flag:
  251.                 st[i] = f[:2]
  252.         
  253.  
  254.     # parseHeaderKeyWord
  255.     def parseHeaderKeyWord(self, header):
  256.         """Parses the first line of an OFF file.
  257.  
  258.         Returns True if the line actually was the header keyword (as it
  259.         is optional).
  260.         The method sets the ST, C, N, 4 and ndim flag to True if the
  261.         according prefix is present.
  262.         """
  263.         header = header.strip()
  264.         if header[-3:]!="OFF":
  265.             return False
  266.  
  267.         if header[:2]=="ST":
  268.             self.texcoord_flag = True
  269.             header = header[2:]
  270.         if header[:1]=="C":
  271.             self.color_flag = True
  272.             header = header[1:]
  273.         if header[:1]=="N":
  274.             self.normal_flag = True
  275.             header = header[1:]
  276.         if header[:1]=="4":
  277.             self.four_flag = True
  278.             header = header[1:]
  279.         if header[:1]=="n":
  280.             self.ndim_flag = True
  281.             header = header[1:]
  282.  
  283.         if header!="OFF":
  284.             print >>sys.stderr, "Warning: Unknown prefixes in the header keyword"
  285.         return True
  286.  
  287.     # readLine
  288.     def readLine(self):
  289.         """Read the next line.
  290.  
  291.         Returns the next line (without the trailing newline) that is not
  292.         empty or a comment. If the end of the file was reached, an exception
  293.         is thrown.
  294.         """
  295.         while 1:
  296.             z = self.fhandle.readline()
  297.             if z=="":
  298.                 raise SyntaxError, "premature end of file"
  299.             z = z.strip()
  300.             if z=="" or z[0]=='#':
  301.                 continue
  302.             return z
  303.         
  304.  
  305. ######################################################################
  306.  
  307. # Register the OffImporter class as a plugin class
  308. pluginmanager.register(OffImporter)
  309.