More elegant serialization of blobs in customdata using the pickle
[blender-addons-contrib.git] / mesh_easylattice.py
index 8d737bf5a7ff7a9778a9a3fa2537c4df6387fb59..7e98a95ca09a841666a9ef4fa5477d4f0cd84d54 100644 (file)
+# ##### 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 #####
+
+
 bl_info = {
-            "name": "Easy Lattice Object",
-            "author": "Kursad Karatas",
-            "version": ( 0, 5 ),
-            "blender": ( 2, 66, 0 ),
-            "location": "View3D > Easy Lattice",
-            "description": "Create a lattice for shape editing",
-            "warning": "",
-            "wiki_url": "http://wiki.blender.org/index.php/Easy_Lattice_Editing_Addon",
-            "tracker_url": "https://bitbucket.org/kursad/blender_addons_easylattice/src",
-            "category": "Mesh"}
+    "name": "Easy Lattice Object",
+    "author": "Kursad Karatas",
+    "version": (0, 5),
+    "blender": (2, 66, 0),
+    "location": "View3D > Easy Lattice",
+    "description": "Create a lattice for shape editing",
+    "warning": "",
+    "wiki_url": "http://wiki.blender.org/index.php/Easy_Lattice_Editing_Addon",
+    "tracker_url": "https://bitbucket.org/kursad/blender_addons_easylattice/src",
+    "category": "Mesh"}
+
 
 import bpy
 import mathutils
 import math
+
 # Cleanup
 def modifiersDelete( obj ):
+
     for mod in obj.modifiers:
+        print(mod)
         if mod.name == "latticeeasytemp":
             try:
                 if mod.object == bpy.data.objects['LatticeEasytTemp']:
+                    print("applying modifier")
                     bpy.ops.object.modifier_apply( apply_as = 'DATA', modifier = mod.name )
-                    
+
             except:
                 bpy.ops.object.modifier_remove( modifier = mod.name )
-        
+
+# Cleanup
+def modifiersApplyRemove( obj ):
+
+#     print("passed object is", obj)
+#     print("current object is", bpy.context.active_object)
+
+    bpy.ops.object.select_all( action = 'DESELECT' )
+    bpy.ops.object.select_pattern(pattern=obj.name, extend=False)
+    bpy.context.scene.objects.active=obj
+
+    for mod in obj.modifiers:
+#         print("modifier is ", mod)
+        if mod.name == "latticeeasytemp":
+#             try:
+            if mod.object == bpy.data.objects['LatticeEasytTemp']:
+#                 print("mod object is ", mod.object)
+#                 print("applying modifier", mod," - ", mod.name)
+
+                #obj.select= True
+#                 print("current object is", bpy.context.active_object)
+                bpy.ops.object.modifier_apply( apply_as = 'DATA', modifier = mod.name )
+                #obj.modifiers.remove(mod)
+
+#             except:
+#                 bpy.ops.object.modifier_remove( modifier = mod.name )
+
+
 # Cleanup
-def latticeDelete():
+def latticeDelete(obj):
     bpy.ops.object.select_all( action = 'DESELECT' )
     for ob in bpy.context.scene.objects:
          if "LatticeEasytTemp" in ob.name:
              ob.select = True
-    bpy.ops.object.delete( use_global = False )        
+    bpy.ops.object.delete( use_global = False )
+
+    #select the original object back
+    obj.select=True
 
 def createLattice( obj, size, pos, props ):
     # Create lattice and object
     lat = bpy.data.lattices.new( 'LatticeEasytTemp' )
     ob = bpy.data.objects.new( 'LatticeEasytTemp', lat )
-    
-    loc = getTransformations( obj )[0]
-    rot = getTransformations( obj )[1]
-    scl = getTransformations( obj )[2]
-    
+
+    loc,rot,scl = getTransformations( obj )
+
     #get the combined rotation matrix and apply to the lattice
     #ob.matrix_world=buildRot_WorldMat(obj)*ob.matrix_world
-    
-    #the position comes from the bbox 
+
+    #the position comes from the bbox
     ob.location = pos
-        # ob.location=(pos.x+loc.x,pos.y+loc.y,pos.z+loc.z)
-    
-    #the size  from bbox bbox
+        #ob.location=(pos.x+loc.x,pos.y+loc.y,pos.z+loc.z)
+
+    #the size  from bbox
     ob.scale = size
-        # ob.scale=(size.x*scl.x, size.y*scl.y,size.z*scl.z)
-    
-    #rotation come from the combined obj world matrix    
+        #ob.scale=(size.x*scl.x, size.y*scl.y,size.z*scl.z)
+
+    #the rotation comes from the combined obj world matrix which was converted to euler pairs.
     ob.rotation_euler = buildRot_World(obj)
-    
+
     ob.show_x_ray = True
     # Link object to scene
     scn = bpy.context.scene
     scn.objects.link( ob )
     scn.objects.active = ob
     scn.update()
+
     # Set lattice attributes
     lat.interpolation_type_u = props[3]
     lat.interpolation_type_v = props[3]
     lat.interpolation_type_w = props[3]
+
     lat.use_outside = False
-    lat.points_u = 4
-    lat.points_v = 4
-    lat.points_w = 4
-    
+
     lat.points_u = props[0]
     lat.points_v = props[1]
     lat.points_w = props[2]
 
-   # Set lattice points
-#    s = 0.0
-#    points = [
-#        (-s,-s,-s), (s,-s,-s), (-s,s,-s), (s,s,-s),
-#        (-s,-s,s), (s,-s,s), (-s,s,s), (s,s,s)
-#    ]
-#    for n,pt in enumerate(lat.points):
-#        for k in range(3):
-#            #pt.co[k] = points[n][k]
+    #Set lattice points
+    '''s = 0.0
+    points = [
+        (-s,-s,-s), (s,-s,-s), (-s,s,-s), (s,s,-s),
+        (-s,-s,s), (s,-s,s), (-s,s,s), (s,s,s)
+    ]
+    for n,pt in enumerate(lat.points):
+        for k in range(3):
+            #pt.co[k] = points[n][k]
+    '''
+
     return ob
 
 
 def selectedVerts_Grp( obj ):
 #     vertices=bpy.context.active_object.data.vertices
     vertices = obj.data.vertices
-    
+
     selverts = []
-    
+
     if obj.mode == "EDIT":
         bpy.ops.object.editmode_toggle()
 
     for grp in obj.vertex_groups:
-        
+
         if "templatticegrp" in grp.name:
             bpy.ops.object.vertex_group_set_active( group = grp.name )
             bpy.ops.object.vertex_group_remove()
-        
+
     tempgroup = obj.vertex_groups.new( "templatticegrp" )
-    
+
     # selverts=[vert for vert in vertices if vert.select==True]
     for vert in vertices:
         if vert.select == True:
             selverts.append( vert )
             tempgroup.add( [vert.index], 1.0, "REPLACE" )
-    
+
     # print(selverts)
-    
+
     return selverts
 
 def getTransformations( obj ):
@@ -124,37 +174,23 @@ def getTransformations( obj ):
     return [loc, rot, size]
 
 def findBBox( obj, selvertsarray ):
-    
+
 #     mat = buildTrnSclMat( obj )
     mat =buildTrnScl_WorldMat(obj)
-    
+
     mat_world = obj.matrix_world
-#     print("mat_final", mat)
-#     print("mat_world", mat_world)
-    
-    minx = selvertsarray[0].co.x
-    miny = selvertsarray[0].co.y
-    minz = selvertsarray[0].co.z
-    
-    maxx = selvertsarray[0].co.x
-    maxy = selvertsarray[0].co.y
-    maxz = selvertsarray[0].co.z
-#     print("")    
-    
-    # Median Centers
-    x_sum = minx
-    y_sum = miny
-    z_sum = minz
-    
-    middle = mathutils.Vector( ( x_sum, y_sum, z_sum ) )
+
+    minx, miny, minz = selvertsarray[0].co
+    maxx, maxy, maxz = selvertsarray[0].co
+
     c = 1
 #     for vert in selvertsarray:
     for c in range( len( selvertsarray ) ):
         # co=obj.matrix_world*vert.co.to_4d()
-        
+
 #         co = vert.co
         co = selvertsarray[c].co
-        
+
         if co.x < minx: minx = co.x
         if co.y < miny: miny = co.y
         if co.z < minz: minz = co.z
@@ -162,48 +198,43 @@ def findBBox( obj, selvertsarray ):
         if co.x > maxx: maxx = co.x
         if co.y > maxy: maxy = co.y
         if co.z > maxz: maxz = co.z
-        
+
 #         print("local cord", selvertsarray[c].co)
 #         print("world cord", co)
         c += 1
-        
+
 #     print("total verts", len(selvertsarray))
 #     print("counted verts",c)
-    
+
     # Based on world coords
 #     print("-> minx miny minz",minx, miny, minz )
 #     print("-> maxx maxy maxz",maxx, maxy, maxz )
-    
+
     minpoint = mathutils.Vector( ( minx, miny, minz ) )
     maxpoint = mathutils.Vector( ( maxx, maxy, maxz ) )
-    
+
     # middle point has to be calculated based on the real world matrix
-#     middle = mat_world * mathutils.Vector((x_sum, y_sum, z_sum))/float(c)
+    #middle = mat_world * mathutils.Vector((x_sum, y_sum, z_sum))/float(c)
     middle = ( ( minpoint + maxpoint ) / 2 )
 
-    # Calculate world coordinates
     minpoint = mat * minpoint  # Calculate only based on loc/scale
     maxpoint = mat * maxpoint  # Calculate only based on loc/scale
     middle = mat_world * middle  # the middle has to be calculated based on the real world matrix
-    
+
     size = maxpoint - minpoint
     size = mathutils.Vector( ( abs( size.x ), abs( size.y ), abs( size.z ) ) )
-    
-    # local coords   
+
+    # local coords
     #####################################################
-#    minpoint=mathutils.Vector((minx,miny,minz))
-#    maxpoint=mathutils.Vector((maxx,maxy,maxz))
-#    middle=mathutils.Vector( (x_sum/float(len(selvertsarray)), y_sum/float(len(selvertsarray)), z_sum/float(len(selvertsarray))) )
-#    size=maxpoint-minpoint
-#    size=mathutils.Vector((abs(size.x),abs(size.y),abs(size.z)))
+    '''minpoint=mathutils.Vector((minx,miny,minz))
+    maxpoint=mathutils.Vector((maxx,maxy,maxz))
+    middle=mathutils.Vector( (x_sum/float(len(selvertsarray)), y_sum/float(len(selvertsarray)), z_sum/float(len(selvertsarray))) )
+    size=maxpoint-minpoint
+    size=mathutils.Vector((abs(size.x),abs(size.y),abs(size.z)))
+    '''
     #####################################################
-    
-    # print("-@ world matrix", obj.matrix_world)
-#     print("-@ min - max", minpoint, " ", maxpoint)
-#     print("-@ size", size)
-#     print("-@ median point ->", middle)
 
-    # return [minx, miny, minz, maxx, maxy, maxz, pos_median  ]
+
     return [minpoint, maxpoint, size, middle  ]
 
 
@@ -214,43 +245,36 @@ def buildTrnSclMat( obj ):
     mat_scale = mathutils.Matrix.Scale( obj.scale[0], 4, ( 1, 0, 0 ) )
     mat_scale *= mathutils.Matrix.Scale( obj.scale[1], 4, ( 0, 1, 0 ) )
     mat_scale *= mathutils.Matrix.Scale( obj.scale[2], 4, ( 0, 0, 1 ) )
-    
+
     mat_final = mat_trans * mat_scale
-    
-    
+
+
     return mat_final
-    
+
 def buildTrnScl_WorldMat( obj ):
     # This function builds a real world matrix that encodes translation and scale and it leaves out the rotation matrix
     # The rotation is applied at obejct level if there is any
     loc,rot,scl=obj.matrix_world.decompose()
-    
     mat_trans = mathutils.Matrix.Translation( loc)
-    
-    
+
     mat_scale = mathutils.Matrix.Scale( scl[0], 4, ( 1, 0, 0 ) )
     mat_scale *= mathutils.Matrix.Scale( scl[1], 4, ( 0, 1, 0 ) )
     mat_scale *= mathutils.Matrix.Scale( scl[2], 4, ( 0, 0, 1 ) )
-    
-    
+
     mat_final = mat_trans * mat_scale
-    
-    
+
+
     return mat_final
 
-#Feature use    
+#Feature use
 def buildRot_WorldMat( obj ):
-    # This function builds a real world matrix that encodes translation and scale and it leaves out the rotation matrix
-    # The rotation is applied at obejct level if there is any
+    # This function builds a real world matrix that encodes rotation and it leaves out translation and scale matrices
     loc,rot,scl=obj.matrix_world.decompose()
-    
     rot=rot.to_euler()
-    
-    mat_rot = mathutils.Matrix.Rotation(rot[0], 4,'X') 
+
+    mat_rot = mathutils.Matrix.Rotation(rot[0], 4,'X')
     mat_rot *= mathutils.Matrix.Rotation(rot[1],4,'Z')
     mat_rot *= mathutils.Matrix.Rotation(rot[2], 4,'Y')
-
-    
     return mat_rot
 
 #Feature use
@@ -259,7 +283,7 @@ def buildTrn_WorldMat( obj ):
     # The rotation is applied at obejct level if there is any
     loc,rot,scl=obj.matrix_world.decompose()
     mat_trans = mathutils.Matrix.Translation( loc)
-    
+
     return mat_trans
 
 #Feature use
@@ -267,50 +291,74 @@ def buildScl_WorldMat( obj ):
     # This function builds a real world matrix that encodes translation and scale and it leaves out the rotation matrix
     # The rotation is applied at obejct level if there is any
     loc,rot,scl=obj.matrix_world.decompose()
-    
+
     mat_scale = mathutils.Matrix.Scale( scl[0], 4, ( 1, 0, 0 ) )
     mat_scale *= mathutils.Matrix.Scale( scl[1], 4, ( 0, 1, 0 ) )
     mat_scale *= mathutils.Matrix.Scale( scl[2], 4, ( 0, 0, 1 ) )
-    
+
     return mat_scale
 
-    
 def buildRot_World( obj ):
-    # This function builds a real world matrix that encodes translation and scale and it leaves out the rotation matrix
-    # The rotation is applied at obejct level if there is any
+    # This function builds a real world rotation values
     loc,rot,scl=obj.matrix_world.decompose()
-    
     rot=rot.to_euler()
-    
-    return rot
 
+    return rot
 
 def run( lat_props ):
-    
-    obj = bpy.context.active_object
+
+#     print("<-------------------------------->")
+    #obj = bpy.context.active_object
+    obj = bpy.context.object
+
     if obj.type == "MESH":
+        # set global property for the currently active latticed object
+        bpy.types.Scene.activelatticeobject = bpy.props.StringProperty( name = "currentlatticeobject", default = "" )
+        bpy.types.Scene.activelatticeobject = obj.name
+
         modifiersDelete( obj )
         selvertsarray = selectedVerts_Grp( obj )
         bbox = findBBox( obj, selvertsarray )
-        
+
         size = bbox[2]
-        # pos=mathutils.Vector( ( bbox[3][0], bbox[3][1], bbox[3][2]) )
         pos = bbox[3]
-        
+
 #         print("lattce size, pos", size, " ", pos)
-        latticeDelete()
+        latticeDelete(obj)
         lat = createLattice( obj, size, pos, lat_props )
-        
+
         modif = obj.modifiers.new( "latticeeasytemp", "LATTICE" )
         modif.object = lat
         modif.vertex_group = "templatticegrp"
-        
+
+
+        bpy.ops.object.select_all( action = 'DESELECT' )
+        bpy.ops.object.select_pattern(pattern=lat.name, extend=False)
+        bpy.context.scene.objects.active=lat
+
         bpy.context.scene.update()
         bpy.ops.object.mode_set( mode = 'EDIT' )
-    
-    return
 
+    if obj.type == "LATTICE":
+
+
+        if bpy.types.Scene.activelatticeobject:
+            name = bpy.types.Scene.activelatticeobject
+            print("last active latticed object", name)
+
+            #Are we in edit lattice mode? If so move on to object mode
+            if obj.mode=="EDIT":
+                bpy.ops.object.editmode_toggle()
+
+            for ob in bpy.context.scene.objects:
+                if ob.name == name:  # found the object with the lattice mod
+                    print("apply mod on", ob)
+                    object = ob
+                    modifiersApplyRemove(object)
+                    #modifiersDelete( object )  # apply the modifier and delete the lattice
+                    latticeDelete(obj)
+
+    return
 
 
 def main( context, latticeprops ):
@@ -322,25 +370,25 @@ class EasyLattice( bpy.types.Operator ):
     bl_label = "Easy Lattice Creator"
     bl_space_type = "VIEW_3D"
     bl_region_type = "TOOLS"
-    
+
     lat_u = bpy.props.IntProperty( name = "Lattice u", default = 3 )
     lat_w = bpy.props.IntProperty( name = "Lattice w", default = 3 )
     lat_m = bpy.props.IntProperty( name = "Lattice m", default = 3 )
-    
+
     lat_types = ( ( '0', 'KEY_LINEAR', '0' ), ( '1', 'KEY_CARDINAL', '1' ), ( '2', 'KEY_BSPLINE', '2' ) )
     lat_type = bpy.props.EnumProperty( name = "Lattice Type", items = lat_types, default = '0' )
-    
-    
+
+
     @classmethod
     def poll( cls, context ):
         return context.active_object is not None
 
     def execute( self, context ):
-        
+
         lat_u = self.lat_u
         lat_w = self.lat_w
         lat_m = self.lat_m
-        
+
         # this is a reference to the "items" used to generate the
         # enum property.
         lat_type = self.lat_types[int( self.lat_type )][1]
@@ -353,23 +401,22 @@ class EasyLattice( bpy.types.Operator ):
         wm = context.window_manager
         return wm.invoke_props_dialog( self )
 
-def menu_draw( self, context ): 
-    self.layout.operator_context = 'INVOKE_REGION_WIN' 
-    self.layout.operator( EasyLattice.bl_idname, "Easy Lattice" ) 
+def menu_draw( self, context ):
+    self.layout.operator_context = 'INVOKE_REGION_WIN'
+    self.layout.operator( EasyLattice.bl_idname, "Easy Lattice" )
 
 def register():
     bpy.utils.register_class( EasyLattice )
     # bpy.utils.register
     # menu_func = (lambda self, context: self.layout.operator('EasyLattice'))
     # bpy.types.VIEW3D_PT_tools_objectmode.append(menu_draw)
-    bpy.types.VIEW3D_MT_edit_mesh_specials.append( menu_draw ) 
+    bpy.types.VIEW3D_MT_edit_mesh_specials.append( menu_draw )
 
 
 def unregister():
     bpy.utils.unregister_class( EasyLattice )
     # bpy.types.VIEW3D_PT_tools_objectmode.remove(menu_draw)
-    bpy.types.VIEW3D_MT_edit_mesh_specials.remove( menu_draw ) 
-
+    bpy.types.VIEW3D_MT_edit_mesh_specials.remove( menu_draw )
 
 if __name__ == "__main__":
     register()