[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [595] trunk/py/scripts/addons: Import original io_mesh_stl from Guillaum HG

Bouchard Guillaume guillaume.bouchard at insa-lyon.fr
Sat Apr 17 14:28:49 CEST 2010


Revision: 595
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-extensions&revision=595
Author:   guillaum
Date:     2010-04-17 14:28:49 +0200 (Sat, 17 Apr 2010)

Log Message:
-----------
Import original io_mesh_stl from Guillaum HG

Added Paths:
-----------
    trunk/py/scripts/addons/io_mesh_stl/
    trunk/py/scripts/addons/io_mesh_stl/__init__.py
    trunk/py/scripts/addons/io_mesh_stl/blender_utils.py
    trunk/py/scripts/addons/io_mesh_stl/stl_utils.py

Added: trunk/py/scripts/addons/io_mesh_stl/__init__.py
===================================================================
--- trunk/py/scripts/addons/io_mesh_stl/__init__.py	                        (rev 0)
+++ trunk/py/scripts/addons/io_mesh_stl/__init__.py	2010-04-17 12:28:49 UTC (rev 595)
@@ -0,0 +1,155 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+'''
+Import/Export STL files (binary or ascii)
+
+- Import automatically remove the doubles.
+- Export can export with/without modifiers applied
+
+Issues:
+
+Import:
+    - Does not handle the normal of the triangles
+    - Does not handle endien
+
+Export:
+    - Does not do the object space transformation
+    - Export only one object (the selected one)
+'''
+
+bl_addon_info = {
+    'name': 'I/O: STL',
+    'author': 'Guillaume Bouchard (Guillaum)',
+    'version': '1',
+    'blender': (2, 5, 3),
+    'location': 'File > Import/Export > Stl',
+    'description': 'Import/Export Stl files',
+    'url': '...',
+    'category': 'Import/Export'}
+
+import bpy
+from bpy.props import *
+
+from io_mesh_stl import stl_utils, blender_utils
+
+
+class StlImporter(bpy.types.Operator):
+    '''
+    Load STL triangle mesh data
+    '''
+    bl_idname = "import_mesh.stl"
+    bl_label = "Import STL"
+
+    path = StringProperty(name="File Path",
+                          description="File path used for importing "
+                                      "the STL file",
+                          maxlen=1024,
+                          default="")
+    filename = StringProperty(name="File Name",
+                              description="Name of the file.")
+    directory = StringProperty(name="Directory",
+                               description="Directory of the file.")
+
+    def execute(self, context):
+        objName = bpy.utils.display_name(self.properties.filename)
+        tris, pts = stl_utils.read_stl(self.properties.path)
+
+        blender_utils.create_and_link_mesh(objName, tris, pts)
+
+        return {'FINISHED'}
+
+    def invoke(self, context, event):
+        wm = context.manager
+        wm.add_fileselect(self)
+
+        return {'RUNNING_MODAL'}
+
+
+class StlExporter(bpy.types.Operator):
+    '''
+    Save STL triangle mesh data from the active object
+    '''
+    bl_idname = "export_mesh.stl"
+    bl_label = "Export STL"
+
+    path = StringProperty(name="File Path",
+                          description="File path used for exporting "
+                                      "the active object to STL file",
+                          maxlen=1024,
+                          default="")
+    filename = StringProperty(name="File Name",
+                              description="Name of the file.")
+    directory = StringProperty(name="Directory",
+                               description="Directory of the file.")
+    check_existing = BoolProperty(name="Check Existing",
+                                  description="Check and warn on "
+                                              "overwriting existing files",
+                                  default=True,
+                                  options={'HIDDEN'})
+
+    ascii = BoolProperty(name="Ascii",
+                         description="Save the file in ASCII file format",
+                         default=False)
+    apply_modifiers = BoolProperty(name="Apply Modifiers",
+                                   description="Apply the modifiers "
+                                               "before saving",
+                                   default=True)
+
+    def execute(self, context):
+        ob = context.active_object
+
+        faces = blender_utils.faces_from_mesh(ob,
+                                              self.properties.apply_modifiers)
+        stl_utils.write_stl(self.properties.path, faces, self.properties.ascii)
+
+        return {'FINISHED'}
+
+    def invoke(self, context, event):
+        wm = context.manager
+        wm.add_fileselect(self)
+        return {'RUNNING_MODAL'}
+
+
+def menu_import(self, context):
+    self.layout.operator(StlImporter.bl_idname,
+                         text="Stl (.stl)").path = "*.stl"
+
+
+def menu_export(self, context):
+    default_path = bpy.data.filename.replace(".blend", ".stl")
+    self.layout.operator(StlExporter.bl_idname,
+                         text="Stl (.stl)").path = default_path
+
+
+def register():
+    bpy.types.register(StlImporter)
+    bpy.types.register(StlExporter)
+    bpy.types.INFO_MT_file_import.append(menu_import)
+    bpy.types.INFO_MT_file_export.append(menu_export)
+
+
+def unregister():
+    bpy.types.unregister(StlImporter)
+    bpy.types.unregister(StlExporter)
+    bpy.types.INFO_MT_file_import.remove(menu_import)
+    bpy.types.INFO_MT_file_export.remove(menu_export)
+
+
+if __name__ == "__main__":
+    register()

Added: trunk/py/scripts/addons/io_mesh_stl/blender_utils.py
===================================================================
--- trunk/py/scripts/addons/io_mesh_stl/blender_utils.py	                        (rev 0)
+++ trunk/py/scripts/addons/io_mesh_stl/blender_utils.py	2010-04-17 12:28:49 UTC (rev 595)
@@ -0,0 +1,50 @@
+import bpy
+
+
+def create_and_link_mesh(name, faces, points):
+    '''
+    Create a blender mesh and object called name from a list of
+    *points* and *faces* and link it in the current scene.
+    '''
+
+    mesh = bpy.data.meshes.new(name)
+    mesh.from_pydata(points, [], faces)
+
+    ob = bpy.data.objects.new(name, mesh)
+    bpy.context.scene.objects.link(ob)
+
+    # update mesh to allow proper display
+    mesh.update()
+
+
+def faces_from_mesh(ob, apply_modifier=False, triangulate=True):
+    '''
+    From an object, return a generator over a list of faces.
+
+    Each faces is a list of his vertexes. Each vertex is a tuple of
+    his coordinate.
+
+    apply_modifier
+        Apply the preview modifier to the returned liste
+
+    triangulate
+        Split the quad into two triangles
+    '''
+
+    # get the modifiers
+    mesh = ob.create_mesh(bpy.context.scene,
+                          True, "PREVIEW") if apply_modifier else ob.data
+
+    def iter_face_index():
+        '''
+        From a list of faces, return the face triangulated if needed.
+        '''
+        for face in mesh.faces:
+            if triangulate and len(face.verts) == 4:
+                yield face.verts[:3]
+                yield face.verts[2:] + [face.verts[0]]
+            else:
+                yield list(face.verts)
+
+    return ([tuple(mesh.verts[index].co)
+             for index in indexes] for indexes in iter_face_index())

Added: trunk/py/scripts/addons/io_mesh_stl/stl_utils.py
===================================================================
--- trunk/py/scripts/addons/io_mesh_stl/stl_utils.py	                        (rev 0)
+++ trunk/py/scripts/addons/io_mesh_stl/stl_utils.py	2010-04-17 12:28:49 UTC (rev 595)
@@ -0,0 +1,228 @@
+'''
+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
+
+
+ at 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)]
+

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list