diff options
Diffstat (limited to 'io_mesh_stl/stl_utils.py')
-rw-r--r-- | io_mesh_stl/stl_utils.py | 228 |
1 files changed, 0 insertions, 228 deletions
diff --git a/io_mesh_stl/stl_utils.py b/io_mesh_stl/stl_utils.py deleted file mode 100644 index 92723e98..00000000 --- a/io_mesh_stl/stl_utils.py +++ /dev/null @@ -1,228 +0,0 @@ -''' -Import and export STL files - -Used as a blender script, it load all the stl files in the scene: - -blender -P stl_utils.py -- file1.stl file2.stl file3.stl ... -''' - -import struct -import mmap -import contextlib -import itertools - -# TODO: endien - - -@contextlib.contextmanager -def mmap_file(filename): - ''' - Context manager over the data of an mmap'ed file (Read ONLY). - - - Example: - - with mmap_file(filename) as m: - m.read() - print m[10:50] - ''' - with open(filename, 'rb') as file: - # check http://bugs.python.org/issue8046 to have mmap context - # manager fixed in python - map = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) - yield map - map.close() - - -class ListDict(dict): - ''' - Set struct with order. - - You can: - - insert data into without doubles - - get the list of data in insertion order with self.list - - Like collections.OrderedDict, but quicker, can be replaced if - ODict is optimised. - ''' - - def __init__(self): - dict.__init__(self) - self.list = [] - self._len = 0 - - def add(self, item): - ''' - Add a value to the Set, return its position in it. - ''' - value = self.setdefault(item, self._len) - if value == self._len: - self.list.append(item) - self._len += 1 - - return value - - -def _binary_read(data): - # an stl binary file is - # - 80 bytes of description - # - 2 bytes of size (unsigned int) - # - size triangles : - # - # - 12 bytes of normal - # - 9 * 4 bytes of coordinate (3*3 floats) - # - 2 bytes of garbage (usually 0) - - # OFFSET for the first byte of coordinate (headers + first normal bytes) - # STRIDE between each triangle (first normal + coordinates + garbage) - OFFSET, STRIDE = 84 + 12, 12 * 4 + 2 - - # read header size, ignore description - size = struct.unpack_from('<I', data, 80)[0] - unpack = struct.Struct('<9f').unpack_from - - for i in range(size): - # read the points coordinates of each triangle - pt = unpack(data, OFFSET + STRIDE * i) - yield pt[:3], pt[3:6], pt[6:] - - -def _ascii_read(data): - # an stl ascii file is like - # HEADER: solid some name - # for each face: - # - # facet normal x y z - # outerloop - # vertex x y z - # vertex x y z - # vertex x y z - # endloop - # endfacet - - # strip header - data.readline() - - while True: - # strip facet normal // or end - data.readline() - - # strip outer loup, in case of ending, break the loop - if not data.readline(): - break - - yield [tuple(map(float, data.readline().split()[1:])) - for _ in range(3)] - - # strip facet normalend and outerloop end - data.readline() - data.readline() - - -def _binary_write(filename, faces): - with open(filename, 'wb') as data: - # header - # we write padding at header begginning to avoid to - # call len(list(faces)) which may be expensive - data.write(struct.calcsize('<80sI') * b'\0') - - # 3 vertex == 9f - pack = struct.Struct('<9f').pack - # pad is to remove normal, we do use them - pad = b'\0' * struct.calcsize('<3f') - - nb = 0 - for verts in faces: - # write pad as normal + vertexes + pad as attributes - data.write(pad + pack(*itertools.chain.from_iterable(verts))) - data.write(b'\0\0') - nb += 1 - - # header, with correct value now - data.seek(0) - data.write(struct.pack('<80sI', b"Exported from blender", nb)) - - -def _ascii_write(filename, faces): - with open(filename, 'w') as data: - data.write('solid Exported from blender\n') - - for face in faces: - data.write('''facet normal 0 0 0\nouter loop\n''') - for vert in face: - data.write('vertex %f %f %f\n' % vert) - data.write('endloop\nendfacet\n') - - data.write('endsolid Exported from blender\n') - - -def write_stl(filename, faces, ascii=False): - ''' - Write a stl file from faces, - - filename - output filename - - faces - iterable of tuple of 3 vertex, vertex is tuple of 3 coordinates as float - - ascii - save the file in ascii format (very huge) - ''' - (_ascii_write if ascii else _binary_write)(filename, faces) - - -def read_stl(filename): - ''' - Return the triangles and points of an stl binary file. - - Please note that this process can take lot of time if the file is - huge (~1m30 for a 1 Go stl file on an quad core i7). - - - returns a tuple(triangles, points). - - triangles - A list of triangles, each triangle as a tuple of 3 index of - point in *points*. - - points - An indexed list of points, each point is a tuple of 3 float - (xyz). - - Example of use: - - >>> tris, pts = read_stl(filename, lambda x:) - >>> pts = list(pts) - >>> - >>> # print the coordinate of the triangle n - >>> print([pts[i] for i in tris[n]]) - ''' - - tris, pts = [], ListDict() - - with mmap_file(filename) as data: - # check for ascii or binary - gen = _ascii_read if data.read(5) == b'solid' else _binary_read - - for pt in gen(data): - # Add the triangle and the point. - # If the point is allready in the list of points, the - # index returned by pts.add() will be the one from the - # first equal point inserted. - tris.append([pts.add(p) for p in pt]) - - return tris, pts.list - - -if __name__ == '__main__': - import sys - import bpy - from io_mesh_stl import blender_utils - - filenames = sys.argv[sys.argv.index('--') + 1:] - - for filename in filenames: - objName = bpy.path.display_name(filename) - tris, pts = read_stl(filename) - - blender_utils.create_and_link_mesh(objName, tris, pts) |