From f0b345d39b7a2c43224c056c05e5cfa94434d601 Mon Sep 17 00:00:00 2001 From: Martin Buerbaum Date: Thu, 15 Apr 2010 08:21:16 +0000 Subject: * Version 0.3.3 * Updated store_recall_properties, apply_object_align and create_mesh_object. * Changed how recall data is stored. --- add_mesh_3d_function_surface.py | 175 ++++++++++++++++++++++------------------ 1 file changed, 98 insertions(+), 77 deletions(-) (limited to 'add_mesh_3d_function_surface.py') diff --git a/add_mesh_3d_function_surface.py b/add_mesh_3d_function_surface.py index eff69042..9c1ac624 100644 --- a/add_mesh_3d_function_surface.py +++ b/add_mesh_3d_function_surface.py @@ -24,7 +24,7 @@ from bpy.props import * bl_addon_info = { 'name': 'Add Mesh: 3D Function Surfaces', 'author': 'Buerbaum Martin (Pontiac)', - 'version': '0.3.2', + 'version': '0.3.3', 'blender': (2, 5, 3), 'location': 'View3D > Add > Mesh > Z Function Surface &' \ ' XYZ Function Surface', @@ -63,6 +63,9 @@ and menu. Version history: +v0.3.3 - Updated store_recall_properties, apply_object_align + and create_mesh_object. + Changed how recall data is stored. v0.3.2 - Various fixes&streamlining by ideasman42/Campbell Barton. r544 Compile expressions for faster execution r544 Use operator reports for errors too @@ -105,26 +108,33 @@ safe_list = ['math', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', safe_dict = dict([(k, globals().get(k, None)) for k in safe_list]) -# Stores the values of a list of properties in a -# property group (named like the operator) in the object. -# Always replaces any existing property group with the same name! -# @todo: Should we do this in EDIT Mode? Sounds dangerous. -def obj_store_recall_properties(ob, op, prop_list): - if ob and op and prop_list: - #print("Storing recall data for operator: " + op.bl_idname) # DEBUG +# Stores the values of a list of properties and the +# operator id in a property group ('recall_op') inside the object. +# Could (in theory) be used for non-objects. +# Note: Replaces any existing property group with the same name! +# ob ... Object to store the properties in. +# op ... The operator that should be used. +# op_args ... A dictionary with valid Blender +# properties (operator arguments/parameters). +def store_recall_properties(ob, op, op_args): + if ob and op and op_args: + recall_properties = {} + + # Add the operator identifier and op parameters to the properties. + recall_properties['op'] = op.bl_idname + recall_properties['args'] = op_args # Store new recall properties. - prop_list['recall_op'] = op.bl_idname - ob['recall'] = prop_list + ob['recall'] = recall_properties -# Apply view rotation to objects if "Align To" for new objects -# was set to "VIEW" in the User Preference. -def apply_view_rotation(context, ob): - align = bpy.context.user_preferences.edit.object_align +# Apply view rotation to objects if "Align To" for +# new objects was set to "VIEW" in the User Preference. +def apply_object_align(context, ob): + obj_align = bpy.context.user_preferences.edit.object_align if (context.space_data.type == 'VIEW_3D' - and align == 'VIEW'): + and obj_align == 'VIEW'): view3d = context.space_data region = view3d.region_3d viewMatrix = region.view_matrix @@ -132,75 +142,55 @@ def apply_view_rotation(context, ob): ob.rotation_euler = rot.invert().to_euler() -def createFaces(vertIdx1, vertIdx2, ring): - ''' - A very simple "bridge" tool. - Connects two equally long vertex-loops with faces and - returns a list of the new faces. - - Parameters - vertIdx1 ... List of vertex indices of the first loop. - vertIdx2 ... List of vertex indices of the second loop. - ''' - faces = [] +# Create a new mesh (object) from verts/edges/faces. +# verts/edges/faces ... List of vertices/edges/faces for the +# new mesh (as used in from_pydata). +# name ... Name of the new mesh (& object). +# edit ... Replace existing mesh data. +# Note: Using "edit" will destroy/delete existing mesh data. +def create_mesh_object(context, verts, edges, faces, name, edit): + scene = context.scene + obj_act = scene.objects.active - if (len(vertIdx1) != len(vertIdx2)) or (len(vertIdx1) < 2): + # Can't edit anything, unless we have an active obj. + if edit and not obj_act: return None - total = len(vertIdx1) - - if (ring): - # Bridge the start with the end. - faces.append([vertIdx2[0], vertIdx1[0], - vertIdx1[total - 1], vertIdx2[total - 1]]) - - # Bridge the rest of the faces. - for num in range(total - 1): - faces.append([vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]]) - - return faces - - -def createObject(context, verts, faces, name, edit): - '''Creates Meshes & Objects for the given lists of vertices and faces.''' - - scene = context.scene - # Create new mesh mesh = bpy.data.meshes.new(name) - # Add the geometry to the mesh. - #mesh.add_geometry(len(verts), 0, len(faces)) - #mesh.verts.foreach_set("co", unpack_list(verts)) - #mesh.faces.foreach_set("verts_raw", unpack_face_list(faces)) + # Make a mesh from a list of verts/edges/faces. + mesh.from_pydata(verts, edges, faces) - # To quote the documentation: - # "Make a mesh from a list of verts/edges/faces Until we have a nicer - # way to make geometry, use this." - # http://www.blender.org/documentation/250PythonDoc/ - # bpy.types.Mesh.html#bpy.types.Mesh.from_pydata - mesh.from_pydata(verts, [], faces) + # Update mesh geometry after adding stuff. + mesh.update() # Deselect all objects. bpy.ops.object.select_all(action='DESELECT') - # Update mesh geometry after adding stuff. - mesh.update() - if edit: - # Recreate geometry of existing object - obj_act = context.active_object + # Replace geometry of existing object + + # Use the active obj and select it. ob_new = obj_act + ob_new.selected = True - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.delete(type='VERT') - bpy.ops.object.mode_set(mode='OBJECT') + if obj_act.mode == 'OBJECT': + # Get existing mesh datablock. + old_mesh = ob_new.data - ob_new.data = mesh + # Set object data to nothing + ob_new.data = None - ob_new.selected = True + # Clear users of existing mesh datablock. + old_mesh.user_clear() + + # Remove old mesh datablock if no users are left. + if (old_mesh.users == 0): + bpy.data.meshes.remove(old_mesh) + + # Assign new mesh datablock. + ob_new.data = mesh else: # Create new object @@ -213,9 +203,7 @@ def createObject(context, verts, faces, name, edit): # Place the object at the 3D cursor location. ob_new.location = scene.cursor_location - obj_act = scene.objects.active - - apply_view_rotation(context, ob_new) + apply_object_align(context, ob_new) if obj_act and obj_act.mode == 'EDIT': if not edit: @@ -234,6 +222,8 @@ def createObject(context, verts, faces, name, edit): # Switching back to EditMode. bpy.ops.object.mode_set(mode='EDIT') + ob_new = obj_act + else: # We are in ObjectMode. # Make the new object the active one. @@ -242,6 +232,36 @@ def createObject(context, verts, faces, name, edit): return ob_new +def createFaces(vertIdx1, vertIdx2, ring): + ''' + A very simple "bridge" tool. + Connects two equally long vertex-loops with faces and + returns a list of the new faces. + + Parameters + vertIdx1 ... List of vertex indices of the first loop. + vertIdx2 ... List of vertex indices of the second loop. + ''' + faces = [] + + if (len(vertIdx1) != len(vertIdx2)) or (len(vertIdx1) < 2): + return None + + total = len(vertIdx1) + + if (ring): + # Bridge the start with the end. + faces.append([vertIdx2[0], vertIdx1[0], + vertIdx1[total - 1], vertIdx2[total - 1]]) + + # Bridge the rest of the faces. + for num in range(total - 1): + faces.append([vertIdx1[num], vertIdx2[num], + vertIdx2[num + 1], vertIdx1[num + 1]]) + + return faces + + class AddZFunctionSurface(bpy.types.Operator): '''Add a surface defined defined by a function z=f(x,y)''' bl_idname = "mesh.primitive_z_function_surface" @@ -340,17 +360,17 @@ class AddZFunctionSurface(bpy.types.Operator): edgeloop_prev = edgeloop_cur - obj = createObject(context, verts, faces, "Z Function", edit) + obj = create_mesh_object(context, verts, [], faces, "Z Function", edit) # Store 'recall' properties in the object. - recall_prop_list = { + recall_args_list = { "edit": True, "equation": equation, "div_x": div_x, "div_y": div_y, "size_x": size_x, "size_y": size_y} - obj_store_recall_properties(obj, self, recall_prop_list) + store_recall_properties(obj, self, recall_args_list) return {'FINISHED'} @@ -548,10 +568,11 @@ class AddXYZFunctionSurface(bpy.types.Operator): if not verts: return {'CANCELLED'} - obj = createObject(context, verts, faces, "XYZ Function", props.edit) + obj = create_mesh_object(context, verts, [], faces, + "XYZ Function", props.edit) # Store 'recall' properties in the object. - recall_prop_list = { + recall_args_list = { "edit": True, "x_eq": props.x_eq, "y_eq": props.y_eq, @@ -564,7 +585,7 @@ class AddXYZFunctionSurface(bpy.types.Operator): "range_v_max": props.range_v_max, "range_v_step": props.range_v_step, "wrap_v": props.wrap_v} - obj_store_recall_properties(obj, self, recall_prop_list) + store_recall_properties(obj, self, recall_args_list) return {'FINISHED'} -- cgit v1.2.3