# How to combine vector algebra and blender modeling?

I do some simple vector algebra and want to illustrate the vectors and points in Blender. However, there is a disconnect that I would like some outside perspective on to disentangle. Here is the code that shows my issue.

I have a slightly tilted line given by the point P and a direction vector, and I have a point A. I want to calculate the vector projection of the point A onto the line. I want to connect the point A with the projected point with a straight line.

import bpy
import numpy as np

line_rot_x = 0 * np.pi / 180  # 5° rotation around x axis
line_rot_y = 0 * np.pi / 180  # 3° rotation around y axis
line_len = 1  # in meter
P_y = 1
P_x = 1

A = np.array([0, 0, 0])

P = np.array([P_x, P_y, 0])

# align the line (more or less, given the rotation) with the z-axis
bpy.context.object.delta_rotation_euler = (line_rot_x, line_rot_y, np.pi/2)

# set up some helpful math things to make calculation of the planes and vectors easy
rotation_matrix = np.dot(
np.array([[1, 0, 0], [0, np.cos(line_rot_x), np.sin(line_rot_x)], [0, -np.sin(line_rot_x), np.cos(line_rot_x)]]),
np.array([[np.cos(line_rot_y), 0, -np.sin(line_rot_y)], [0, 1, 0],[np.sin(line_rot_y), 0, np.cos(line_rot_y)]]))
line_direction_vector = np.dot(rotation_matrix, np.array([0, 0, 1])) # rotate the direction vector of the z-axis

print(str("direction vector of the line " + str(line_direction_vector)))

A_proj = P + line_direction_vector * np.dot((P-A), line_direction_vector) / np.dot(line_direction_vector, line_direction_vector)
print(str("point A, projected on line: " + str(A_proj)))

# mark the projected point, and the normal plane in the point
bpy.context.object.delta_rotation_euler = (line_rot_x, line_rot_y, np.pi/2)

# connect the A and A_proj
obj = bpy.context.object
obj.data.dimensions = '3D'
obj.data.fill_mode = 'FULL'
obj.data.bevel_depth = 0.01
obj.data.bevel_resolution = 4
obj.data.splines[0].bezier_points[0].co = A_proj
obj.data.splines[0].bezier_points[0].handle_left_type = 'VECTOR'
obj.data.splines[0].bezier_points[1].co = A
obj.data.splines[0].bezier_points[1].handle_left_type = 'VECTOR'


This should work with all kind of As, Ps and direction vectors for the line.

As you can see, Blender's perception of where the point_coordinate is differing between drawing the sphere and when drawing the connecting line. My math to calculate the vector projection is also off - the globe should be in the plane, and so should the connecting line.

When I subsequently increase just one value of the code, e.g. one of the rotation angles, rerunning the script without cleaning the canvas, the expected result and blenders reality diverge more with each step, and I don't quite understand why.

This is an example of what I expect to happen (thanks to Sam-Hirsch for the vid).

Where did I go off the tracks?

• @Chris fixed it. thanks for letting me know Oct 18, 2021 at 6:23

This code seems to work. Still thinking through this, there still might be flaws.

One issue was the curser, which seems to confuse the bezier curves if not set to the origin. An other was the left/right-handedness of the rotation (the minus sign on the sin() functions). I am still not sure about the vector projection, but it produces reasonable results for the cases that I checked.

import bpy
import numpy as np

line_rot_x = 5 * np.pi / 180  # 5Â° rotation around x axis
line_rot_y = 30 * np.pi / 180  # 3Â° rotation around y axis
line_len = 1  # in meter
P_y = 1
P_x = 1

A = np.array([1, 0.5, 0.5])

P = np.array([P_x, P_y, 0])

# align the line (more or less, given the rotation) with the z-axis
#bpy.context.object.rotation_euler = (line_rot_x, line_rot_y, np.pi/2)

# set up some helpful math things to make calculation of the planes and vectors easy
rotation_matrix = np.matmul(
np.array([[1, 0, 0], [0, np.cos(line_rot_x), -np.sin(line_rot_x)], [0, np.sin(line_rot_x), np.cos(line_rot_x)]]),
np.array([[np.cos(line_rot_y), 0, np.sin(line_rot_y)], [0, 1, 0],[-np.sin(line_rot_y), 0, np.cos(line_rot_y)]]))
line_direction_vector = np.matmul(rotation_matrix, np.array([0, 0, 1])) #

print(str("direction vector of the line " + str(line_direction_vector)))

A_proj = P - line_direction_vector * np.matmul((P-A), line_direction_vector)/np.linalg.norm(line_direction_vector)

print(str("point A, projected on line: " + str(A_proj)))

# mark the projected point, and the normal plane in the point

bpy.context.object.rotation_euler = (line_rot_x,line_rot_y,0)
bpy.context.object.rotation_euler = (line_rot_x,line_rot_y,0)

# connect the A and A_proj