Aligning plane normal vector side to face a point : Python I have 2 points P1 = (x1, y1, z1) and P2 = (x2, y2, z2). The problem statement is some what like this. 

Draw a plane at point P1 (any arbitrary point in 3D space). Rotate the plane to face point P2 (another arbitrary point in 3D space) such that the normal vector of plane at point P1 is facing point P2. Change the rotation of the plane such that it maintains it perpendicularity to point P2 as much it can while one of its X, Y or Z rotations is 0

So far, I've managed to draw the plane and make it face the point P2 using this code:

def align_plane_to_point(obj, point):
    normal = obj.data.polygons[0].normal.xyz
    mat_obj = obj.matrix_basis
    mat_scale = mathutils.Matrix.Scale(1, 4, mat_obj.to_scale())
    trans = mat_obj.to_translation()
    mat_trans = mathutils.Matrix.Translation(trans)
    point_trans = point - trans
    q = normal.rotation_difference(point_trans)
    mat_rot = q.to_matrix()
    mat_rot.resize_4x4()
    mat_obj = mat_trans * mat_rot * mat_scale 
    obj.matrix_basis = mat_obj


Calling this function with arguments obj = Plane at Point P1 and point = point P2, makes sure that the normal side is facing point P2.

Now I am not sure as to how to go about the last part of the problem. Maintaining perpendicularity to point P2 but making sure at least one of the rotations is 0.

Say for example the rotations (in degrees) are like so after executing the above function:

X: -40
Y: 60
Z: -80


Again how do I know (programmatically) which value can I set to 0, making sure plane is as much perpendicular as it can be. I don't mind changing the rest of the values as well as long as the normal is facing towards the point P2.
Manually changing the values, I can see the rotation of the plane and thus decide, but using Python I don't know how to figure this out.

Any help is appreciated.
The function precisely for that is to_track_quat 
Works much like track to constraints. Gives more than rotation difference.

to_track_quat(track, up)


This uses the Vector to point with the specified track axis, (Z for normal) and a secondary "up" axis (x or y, never same ...).

Code would be:

def align_plane_to_point(obj, point):
    dir = point - obj.location
    return dir.to_track_quat("Z", "X").to_euler()


if obj:
    obj.rotation_euler = align_plane_to_point(obj, point)


Of course you can extra check for obj rotation type, the function giving a quaternion, I convert it here to euler assuming the usual kind. Or may use it for rotation matrix, like:

rotMatrix = dir.to_track_quat("Z", "X").to_matrix().to_4x4()


(as quat to matrix produces a 3x3 matrix)


If u need more control, but more complicated, you can have the second dir (up be controlled by another vector) you may look into this, if it helps.


I build there the rotation matrix directly out of 1 vector and a second that is not necessarily perpendicular. 

First I make the second/third vector perpendicular by the cross functions, with some exceptions. I'll not copy that here ... Then can build a 3x3 matrix (only rotation) by putting the 3 vecs into columns

mat3x3 = mathutils.Matrix().to_3x3()"
mat3x3.col[0], mat3x3.col[1], mat3x3.col[2] = mx, my, mz"
eulerRotation = mat3x3.to_euler()


where 3 vecs,  mx, my, mz,  mz would be the point - obj.location, the other 2 being determined as in the linked code

if u use directly such matrix (to 4x4 ok) you'll have some difficulty controlling the scale for some exceptional cases (may fall to 0 on some axes), so to euler or to quaternion is the way, even if u further convert back to a full matrix