[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [3114] contrib/py/scripts/addons/ object_drop_to_ground.py: Largely rewritten.
Florian Meyer
florianfelix at web.de
Wed Mar 14 23:44:48 CET 2012
Revision: 3114
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=3114
Author: testscreenings
Date: 2012-03-14 22:44:47 +0000 (Wed, 14 Mar 2012)
Log Message:
-----------
Largely rewritten. 1. Uses bmesh now. 2. removed the Panel. Is in the Toolshelf now. 3. Added Support for linked_groups of Meshes (recursive grouping not yet supported) 4. Less hacky
Modified Paths:
--------------
contrib/py/scripts/addons/object_drop_to_ground.py
Modified: contrib/py/scripts/addons/object_drop_to_ground.py
===================================================================
--- contrib/py/scripts/addons/object_drop_to_ground.py 2012-03-14 22:27:14 UTC (rev 3113)
+++ contrib/py/scripts/addons/object_drop_to_ground.py 2012-03-14 22:44:47 UTC (rev 3114)
@@ -16,214 +16,166 @@
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
- "name": "Drop to ground",
- "author": "Unnikrishnan(kodemax), Florian Meyer(testscreenings)",
- "version": (1, 1),
- "blender": (2, 5, 9),
- "location": "Tool shelf",
- "description": "Drops the selected objects to the active object",
- "warning": "Before using it do :- ctrl+a -> apply rotation on the object to be dropped",
- "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/Object/Drop_to_ground",
- "tracker_url": "http://projects.blender.org/tracker/?func=detail&atid=467&aid=25349",
- "category": "Object"}
-
-import bpy , random
+ 'name': 'Drop to Ground',
+ 'author': 'Unnikrishnan(kodemax), Florian Meyer(testscreenings)',
+ 'version': (1,2),
+ "blender": (2, 6, 3),
+ 'location': '3D View -> Tool Shelf -> Object Tools Panel (at the bottom)',
+ 'description': 'Drop selected objects on active object',
+ 'warning': '',
+ 'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/Object/Drop_to_ground',
+ "wiki_url": "http://projects.blender.org/tracker/?func=detail&atid=467&aid=25349",
+ 'category': 'Object'}
+#################################################################
+import bpy, bmesh
+from mathutils import *
+from bpy.types import Operator
from bpy.props import *
-import mathutils
-import math
-
+#################################################################
def get_align_matrix(location, normal):
- up = mathutils.Vector((0,0,1))
+ up = Vector((0,0,1))
angle = normal.angle(up)
axis = up.cross(normal)
- mat_rot = mathutils.Matrix.Rotation(angle, 4, axis)
- mat_loc = mathutils.Matrix.Translation(location)
+ mat_rot = Matrix.Rotation(angle, 4, axis)
+ mat_loc = Matrix.Translation(location)
mat_align = mat_rot * mat_loc
return mat_align
+def transform_ground_to_world(sc, ground):
+ tmpMesh = ground.to_mesh(sc, True, 'PREVIEW')
+ tmpMesh.transform(ground.matrix_world)
+ tmp_ground = bpy.data.objects.new('tmpGround', tmpMesh)
+ sc.objects.link(tmp_ground)
+ sc.update()
+ return tmp_ground
-def get_lowest_Coord1(ob):
- matrix = ob.matrix_world.copy()
- verts = ob.data.vertices
- lowest = mathutils.Vector((0,0,10000))
- for vert in verts:
- if (matrix * vert.co).z < lowest.z:
- lowest = matrix * vert.co
- return lowest
+def get_lowest_world_co_from_mesh(ob, mat_parent=None):
+ bme = bmesh.new()
+ bme.from_object(ob)
+ mat_to_world = ob.matrix_world.copy()
+ if mat_parent:
+ mat_to_world = mat_parent * mat_to_world
+ lowest=None
+ #bme.verts.index_update() #probably not needed
+ for v in bme.verts:
+ if not lowest:
+ lowest = v
+ if (mat_to_world * v.co).z < (mat_to_world * lowest.co).z:
+ lowest = v
+ lowest_co = mat_to_world * lowest.co
+ bme.free()
+ return lowest_co
-
-def do_drop(context,tmpObj, ob):
- print('\n', ob.name)
- align_object = context.scene.align_object
- use_center = context.scene.use_center
- lowest = get_lowest_Coord1(ob)
- location, normal, index = tmpObj.ray_cast(lowest, lowest + mathutils.Vector((0,0,-10000)))
+def get_lowest_world_co(context, ob, mat_parent=None):
+ if ob.type == 'MESH':
+ return get_lowest_world_co_from_mesh(ob)
+
+ elif ob.type == 'EMPTY' and ob.dupli_type == 'GROUP':
+ if not ob.dupli_group:
+ return None
- if not index == -1:
- if not use_center:
- temp = (bpy.context.scene.cursor_location).copy()
- bpy.context.scene.cursor_location = lowest
- bpy.ops.object.origin_set(type = 'ORIGIN_CURSOR')
-
- if align_object:
- sca = ob.scale.copy()
- mat_align = get_align_matrix(location, normal)
- ob.matrix_world = mat_align
- ob.scale = sca
-
else:
- ob.location = location
-
-
- if not use_center:
- bpy.context.scene.cursor_location = temp
- bpy.ops.object.origin_set(type = 'ORIGIN_GEOMETRY')
-
- else:
- print('\nno hit')
- return
+ lowest_co = None
+ for ob_l in ob.dupli_group.objects:
+ if ob_l.type == 'MESH':
+ lowest_ob_l = get_lowest_world_co_from_mesh(ob_l, ob.matrix_world)
+ if not lowest_co:
+ lowest_co = lowest_ob_l
+ if lowest_ob_l.z < lowest_co.z:
+ lowest_co = lowest_ob_l
+
+ return lowest_co
-# compute randomisation based on the general or specific percentage chosen
-# if the specific percentage is zero then the general percentage is used
-def compute_percentage(min,max,value,percentage):
- range = max-min
- general_percentage = 100
-
- if percentage == 0:
- percentage_random = ( value -((range*(general_percentage/100))/2) )+ (range * (general_percentage / 100) * random.random())
- else:
- percentage_random = ( value - ((range*(percentage/100))/2)) + (range * (percentage / 100) * random.random())
-
- if percentage_random > max:
- percentage_random = max
- if percentage_random < min:
- percentage_random = min
-
- return percentage_random
-
-def main(self, context):
-
- print('\n_______START__________')
- obs = bpy.context.selected_objects
- ground = bpy.context.active_object
+def drop_objects(self, context):
+ ground = context.object
+ obs = context.selected_objects
obs.remove(ground)
- context = bpy.context
- sc = context.scene
-
-
- tmpMesh = ground.to_mesh(sc, True, 'PREVIEW')
- tmpMesh.transform(ground.matrix_world)
- tmpObj = bpy.data.objects.new('tmpGround', tmpMesh)
- """tmpObj.update(sc, 1, 1, 1)"""
- sc.objects.link(tmpObj)
- sc.update()
-
+ tmp_ground = transform_ground_to_world(context.scene, ground)
+ down = Vector((0, 0, -10000))
+
for ob in obs:
- bpy.ops.object.select_all(action='DESELECT')
- ob.select = True
+ if self.use_origin:
+ lowest_world_co = ob.location
+ else:
+ lowest_world_co = get_lowest_world_co(context, ob)
+ if not lowest_world_co:
+ print(ob.type, 'is not supported. Failed to drop', ob.name)
+ continue
+ hit_location, hit_normal, hit_index = tmp_ground.ray_cast(lowest_world_co,
+ lowest_world_co + down)
+ if hit_index == -1:
+ print(ob.name, 'didn\'t hit the ground')
+ continue
- #randomise location it its enabled
- if sc.random_loc :
- print("randomising the location of object : ", ob.name)
- print("current location :" + str(ob.location))
- bpy.ops.transform.translate(value=(compute_percentage(sc.rl_min_x,sc.rl_max_x,0,100),
- compute_percentage(sc.rl_min_y,sc.rl_max_y,0,100),
- compute_percentage(sc.rl_min_z,sc.rl_max_z,0,100)))
- print("randomised location : ", str(ob.location))
- do_drop(context, tmpObj, ob)
+ # simple drop down
+ to_ground_vec = hit_location - lowest_world_co
+ ob.location += to_ground_vec
+
+ # drop with align to hit normal
+ if self.align:
+ to_center_vec = ob.location - hit_location #vec: hit_loc to origin
+ # rotate object to align with face normal
+ mat_normal = get_align_matrix(hit_location, hit_normal)
+ rot_euler = mat_normal.to_euler()
+ mat_ob_tmp = ob.matrix_world.copy().to_3x3()
+ mat_ob_tmp.rotate(rot_euler)
+ mat_ob_tmp = mat_ob_tmp.to_4x4()
+ ob.matrix_world = mat_ob_tmp
+ # move_object to hit_location
+ ob.location = hit_location
+ # move object above surface again
+ to_center_vec.rotate(rot_euler)
+ ob.location += to_center_vec
+
+ #cleanup
bpy.ops.object.select_all(action='DESELECT')
- tmpObj.select = True
+ tmp_ground.select = True
bpy.ops.object.delete('EXEC_DEFAULT')
-
for ob in obs:
ob.select = True
ground.select = True
+
+#################################################################
+class OBJECT_OT_drop_to_ground(Operator):
+ '''Drop selected objects on active object'''
+ bl_idname = "object.drop_on_active"
+ bl_label = "Drop to Ground"
+ bl_options = {'REGISTER', 'UNDO'}
+ bl_description = "Drop selected objects on active object"
-
-class VIEW3D_PT_tools_drop_to_ground(bpy.types.Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'TOOLS'
- bl_label = "Drop to ground"
- bl_context = "objectmode"
+ align = BoolProperty(
+ name="Align to ground",
+ description="Aligns the object to the ground",
+ default=True)
+ use_origin = BoolProperty(
+ name="Use Center",
+ description="Drop to objects origins",
+ default=False)
- def draw(self, context):
- active_obj = context.active_object
- layout = self.layout
- col = layout.column(align=True)
- col.operator("object.drop_to_ground", text="Drop")
- col.prop(context.scene, "align_object")
- col.prop(context.scene, "use_center")
- box= layout.box()
- box.prop(context.scene, "random_loc")
-
- # random location gui appears only if its enabled
- if bpy.context.scene.random_loc:
-
- row = box.row()
- row.label(text="(X,Y,Z) [min/max]")
- row = box.row()
- a = row.split(percentage = 0.5, align = True)
- a.prop(context.scene, "rl_min_x")
- a.prop(context.scene, "rl_max_x")
- row = box.row()
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list