# How to make these scripted duplivert meshes always face “out” using duplicates?

How can my script ensure the dupliverted meshes on an icosphere faces, and on its vertices will all be facing "outwards". There is an excellent answer that describes using a different technique using an "all-in-one" or a single multi-monkey-faced larger mesh, but that makes it more difficult to animate the shape mesh.

I'd like to understand the logic and/or math behind how bpy.context.object.use_dupli_vertices_rotation actually works. If I understand it, then I will be able to script the desired behavior in more complex situations every time without trial-and-error.

Here's an example. How can I adjust the script so that all the monkeys will reliably face "out" - in the direction of the vertex or face normals? (and which one is it exactly?)

note: I will not always use monkeys on icospheres - this is an abstraction. I'm working towards correctly animating this constellation of 4,425 Earth-facing satellites where I'll have roughly eighty rotating circles with sixty "monkeys" each. However I will also be using 2D meshes in a second project (rather than circles), so I really want to understand the underlying logic/math of the orientations, both on 1D (circles) and 2D meshes.

edit: Here is one of the images from the linked satellite question to help illustrate why I want to learn to use dupliverts, and not create and keyframe four thousand individual "monkeys":

# monkey.rotation_euler = 0, 0, pi   # ??

bpy.ops.object.parent_set(type='OBJECT', keep_transform=True) # keep_transform ??

bpy.context.object.use_dupli_vertices_rotation = True  # ??


Ok here is a basic script:

import bpy, math

pi = math.pi
loco_f, loco_v = (-5, 0, 5), (+5, 0, 5)

bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)

shape_mesh_f = bpy.context.active_object

shape_mesh_v = bpy.context.active_object

monkey_f = bpy.context.active_object
# monkey.rotation_euler = 0, 0, pi

monkey_v = bpy.context.active_object
# monkey.rotation_euler = 0, 0, pi

bpy.ops.object.select_all(action='DESELECT')

monkey_f.select = True
bpy.context.scene.objects.active = shape_mesh_f

bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
bpy.context.object.dupli_type = 'FACES'
bpy.context.object.use_dupli_vertices_rotation = True

bpy.ops.object.select_all(action='DESELECT')

monkey_v.select = True
bpy.context.scene.objects.active = shape_mesh_v

bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
bpy.context.object.dupli_type = 'VERTS'
bpy.context.object.use_dupli_vertices_rotation = True