[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [2571] trunk/py/scripts/addons: Added the first public version of C3D importer addon.

Daniel M. Basso danielmbasso at gmail.com
Thu Nov 3 00:52:03 CET 2011


Revision: 2571
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=2571
Author:   dmbasso
Date:     2011-11-02 23:52:03 +0000 (Wed, 02 Nov 2011)
Log Message:
-----------
Added the first public version of C3D importer addon.

Added Paths:
-----------
    trunk/py/scripts/addons/io_anim_c3d/
    trunk/py/scripts/addons/io_anim_c3d/__init__.py
    trunk/py/scripts/addons/io_anim_c3d/c3d.py

Added: trunk/py/scripts/addons/io_anim_c3d/__init__.py
===================================================================
--- trunk/py/scripts/addons/io_anim_c3d/__init__.py	                        (rev 0)
+++ trunk/py/scripts/addons/io_anim_c3d/__init__.py	2011-11-02 23:52:03 UTC (rev 2571)
@@ -0,0 +1,239 @@
+# ##### 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 3
+#  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 #####
+
+# <pep8-80 compliant>
+
+# This script was developed with financial support from the Foundation for
+# Science and Technology of Portugal, under the grant SFRH/BD/66452/2009.
+
+
+bl_info = {
+    'name': "C3D Graphics Lab Motion Capture file (.c3d)",
+    'author': "Daniel Monteiro Basso <daniel at basso.inf.br>",
+    'version': (2011, 11, 2, 1),
+    'blender': (2, 6, 0),
+    'api': 41226,
+    'location': "File > Import",
+    'description': "Imports C3D Graphics Lab Motion Capture files",
+    'wiki_url': "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
+        "Scripts/Import-Export/C3D_Importer",
+    'tracker_url': "http://projects.blender.org/tracker/?func=detail&atid=467"\
+        "&aid=29061&group_id=153",
+    'category': 'Import-Export'}
+
+
+import bpy
+import math
+import time
+from bpy.props import StringProperty, BoolProperty, FloatProperty, IntProperty
+from mathutils import Vector as vec
+from . import c3d
+
+
+class C3DAnimateCloud(bpy.types.Operator):
+    """
+        Animate the Marker Cloud
+    """
+    bl_idname = "import_anim.c3danim"
+    bl_label = "Animate C3D"
+
+    markerset = None
+    uname = None
+    curframe = 0
+    fskip = 0
+    scale = 0
+    timer = None
+
+    def modal(self, context, event):
+        if event.type == 'ESC':
+            return self.cancel(context)
+        if event.type == 'TIMER':
+            if self.curframe > self.markerset.endFrame:
+                return self.cancel(context)
+            fno = self.curframe
+            if not self.useFrameNo:
+                fno = (self.curframe - self.markerset.startFrame) / self.fskip
+            for i in range(self.fskip):
+                self.markerset.readNextFrameData()
+            for ml in self.markerset.markerLabels:
+                name = self.unames[self.prefix + ml]
+                o = bpy.context.scene.objects[name]
+                m = self.markerset.getMarker(ml, self.curframe)
+                o.location = vec(m.position) * self.scale
+                if m.confidence >= self.confidence:
+                    o.keyframe_insert('location', frame=fno)
+            self.curframe += self.fskip
+        return {'PASS_THROUGH'}
+
+    def execute(self, context):
+        context.window_manager.modal_handler_add(self)
+        self.timer = context.window_manager.\
+            event_timer_add(0.001, context.window)
+        return {'RUNNING_MODAL'}
+
+    def cancel(self, context):
+        bpy.context.scene.frame_set(bpy.context.scene.frame_current)
+        context.window_manager.event_timer_remove(self.timer)
+        return {'CANCELLED'}
+
+
+class C3DImporter(bpy.types.Operator):
+    """
+        Load a C3D Marker Cloud
+    """
+    bl_idname = "import_anim.c3d"
+    bl_label = "Import C3D"
+
+    filepath = StringProperty(name="File Path", maxlen=1024, default="",
+                          description="Path to the C3D file")
+    from_inches = BoolProperty(name="Convert from inches to metric",
+                          default=False, description="Scale by 2.54/100")
+    scale = FloatProperty(name="Scale", default=1.,
+                          description="Scale the positions by this value",
+                          min=0.0001, max=1000000.0,
+                          soft_min=0.001, soft_max=100.0)
+    auto_scale = BoolProperty(name="Adjust scale automatically", default=False,
+                          description="Guess correct scale factor")
+    auto_magnitude = BoolProperty(name="Adjust scale magnitude", default=True,
+                          description="Automatically adjust scale magnitude")
+    size = FloatProperty(name="Empty Size", default=.03,
+                          description="The size of each empty",
+                          min=0.0001, max=1000000.0,
+                          soft_min=0.001, soft_max=100.0)
+    x_ray = BoolProperty(name="Use X-Ray", default=True,
+                          description="Show the empties over other objects")
+    frame_skip = IntProperty(name="Fps divisor", default=4,
+    # usually the sample rate is 120, so the default 4 gives you 30fps
+                          description="Frame supersampling factor", min=1)
+    useFrameNo = BoolProperty(name="Use frame numbers", default=False,
+              description="Offset start of animation according to the source")
+    show_names = BoolProperty(name="Show Names", default=False,
+                          description="Show the markers' name")
+    prefix = StringProperty(name="Name Prefix", maxlen=1024, default="",
+                          description="Prefix object names with this")
+    confidence = FloatProperty(name="Minimum Confidence Level", default=0,
+                          description="Only consider markers with at least "
+                                      "this confidence level",
+                          min=-1., max=1000000.0,
+                          soft_min=-1., soft_max=100.0)
+    filter_glob = StringProperty(default="*.c3d;*.csv", options={'HIDDEN'})
+
+    def find_height(self, ms):
+        """
+            Heuristic to find the height of the subject in the markerset
+            (only works for standing poses)
+        """
+        zmin = None
+        for ml in ms.markerLabels:
+            if 'LTOE' in ml:
+                hd = ml.replace('LTOE', 'LFHD')
+                if hd not in ms.markerLabels:
+                    break
+                pmin_idx = ms.markerLabels.index(ml)
+                pmax_idx = ms.markerLabels.index(hd)
+                zmin = ms.frames[0][pmin_idx].position[2]
+                zmax = ms.frames[0][pmax_idx].position[2]
+        if zmin is None:  # could not find named markers, get extremes
+            allz = [m.position[2] for m in ms.frames[0]]
+            zmin, zmax = min(allz), max(allz)
+        return abs(zmax - zmin)
+
+    def adjust_scale_magnitude(self, height, scale):
+        mag = math.log10(height * scale)
+        #print('mag',mag, 'scale',scale)
+        return scale * math.pow(10, -int(mag))
+
+    def adjust_scale(self, height, scale):
+        factor = height * scale / 1.75  # normalize
+        if factor < .5:
+            scale /= 10
+            factor *= 10
+        cmu_factors = [(1.0, 1.0), (1.1, 1.45), (1.6, 1.6), (2.54, 2.54)]
+        sqerr, fix = min(((cf[0] - factor) ** 2, 1 / cf[1])
+            for cf in cmu_factors)
+        #print('height * scale: {:.2f}'.format(height * scale))
+        #print(factor, fix)
+        return scale * fix
+
+    def execute(self, context):
+        s = self.properties.size
+        empty_size = (s, s, s)
+        ms = c3d.read(self.properties.filepath, onlyHeader=True)
+        ms.readNextFrameData()
+        #print(ms.fileName)
+
+        # determine the final scale
+        height = self.find_height(ms)
+        #print('h', height)
+        scale = 1.0 if not self.properties.from_inches else 2.54
+        scale *= ms.scale
+        if self.properties.auto_magnitude:
+            scale = self.adjust_scale_magnitude(height, scale)
+            #print('scale',scale)
+        if self.properties.auto_scale:
+            scale = self.adjust_scale(height, scale)
+        scale *= self.properties.scale
+
+        # create the empties and get their collision-free names
+        unames = {}
+        for ml in ms.markerLabels:
+            bpy.ops.object.add()
+            bpy.ops.transform.resize(value=empty_size)
+            name = self.properties.prefix + ml
+            bpy.context.active_object.name = name
+            unames[name] = bpy.context.active_object.name
+            bpy.context.active_object.show_name = self.properties.show_names
+            bpy.context.active_object.show_x_ray = self.properties.x_ray
+        for name in unames.values():
+            bpy.context.scene.objects[name].select = True
+
+        # start animating the empties
+        C3DAnimateCloud.markerset = ms
+        C3DAnimateCloud.unames = unames
+        C3DAnimateCloud.scale = scale
+        C3DAnimateCloud.fskip = self.properties.frame_skip
+        C3DAnimateCloud.prefix = self.properties.prefix
+        C3DAnimateCloud.useFrameNo = self.properties.useFrameNo
+        C3DAnimateCloud.confidence = self.properties.confidence
+        C3DAnimateCloud.curframe = ms.startFrame
+        bpy.ops.import_anim.c3danim()
+        return {'FINISHED'}
+
+    def invoke(self, context, event):
+        wm = context.window_manager
+        wm.fileselect_add(self)
+        return {'RUNNING_MODAL'}
+
+
+def menu_func(self, context):
+    self.layout.operator(C3DImporter.bl_idname,
+                         text="Graphics Lab Motion Capture (.c3d)")
+
+
+def register():
+    bpy.utils.register_module(__name__)
+    bpy.types.INFO_MT_file_import.append(menu_func)
+
+
+def unregister():
+    bpy.utils.unregister_module(__name__)
+    bpy.types.INFO_MT_file_import.remove(menu_func)
+
+
+if __name__ == "__main__":
+    register()

Added: trunk/py/scripts/addons/io_anim_c3d/c3d.py
===================================================================
--- trunk/py/scripts/addons/io_anim_c3d/c3d.py	                        (rev 0)
+++ trunk/py/scripts/addons/io_anim_c3d/c3d.py	2011-11-02 23:52:03 UTC (rev 2571)
@@ -0,0 +1,262 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list