Multiple rotations do not add up I am trying to place 4 object on a sphere so that they are equidistant. I can do this by placing them at the 4 corners of a tetrahedron, and a tetrahedron is just 4 corners of a cube. (The cube is just a construction object that will go away.)
I put my object at 0,0,0, then rotate it 45 degrees on two axes. (I then translate it to the corner of the cube.)
See screenshot part 1
I know this worked because when I turn the look down the corner of the cube, I can see my object is perfectly aligned.
See screenshot part 2
But when I add the sphere in, the object is not perpendicular to the sphere's surface.
See screenshot part 3
What have I done wrong? I'm pretty sure I'm doing the multiple axis rotation correct. I set the Transformation Orientation to Local so the rotations should be relative to the object, not Global.
(I can fix it manually by rotating X to about 54 degrees rather than 45, but that's pretty sloppy.)
What am I doing wrong? Or better yet, is there an easier way of placing 4 objects at equidistant angles from each other?
My first thought was that the vectors from the origin of a regular unit tetrahedron are normal to the plane tangent to the sphere where the vector intercepts, and we must be able to recover the rotation from that.
We see that Wikipedia gives the rather ugly values of $( 0, 0, 1 )$, $(\sqrt{\frac{8}{9}},         0, -1/3 )$, $( -\sqrt{\frac{2}{9}}, -\sqrt{\frac{2}{3}}, -\frac{1}{3} )$, and $( -\sqrt{\frac{2}{9}}, \sqrt{\frac{2}{3}}, -\frac{1}{3} )$ for these vertices, so I wrote some Python to draw it.
D = bpy.data
from math import sqrt, radians
from mathutils import Vector

radius = 1

bpy.ops.mesh.primitive_solid_add(source='4', size=radius)

tetrahedron = C.active_object


empties = []

theta = radians(120)
vectors = [ Vector( (   0, 0, 0, 1 ) ),
            Vector( ( theta, sqrt(8/9),         0, -1/3 ) ),
            Vector( ( theta,-sqrt(2/9), -sqrt(2/3), -1/3 ) ),
            Vector( ( theta,-sqrt(2/9),  sqrt(2/3), -1/3 ) ),]
hack=[ 0, 2, 3, 1]


for n in range(4):
    bpy.ops.object.empty_add(type='SINGLE_ARROW', align='WORLD', location=(0, 0, 0))
    empties.append(C.active_object)

    empties[n].rotation_mode= 'AXIS_ANGLE'
    empties[n].rotation_axis_angle = vectors[n]
    empties[n].location = radius * Vector(vectors[hack[n]][1:4])


for n in range(4):
    bpy.ops.mesh.primitive_monkey_add(size=0.5, enter_editmode=False, align='WORLD', 
        location=radius * Vector(vectors[hack[n]][1:4]) )
    monkey = C.active_object
    monkey.rotation_mode= 'AXIS_ANGLE'
    monkey.rotation_axis_angle = vectors[n]