0
$\begingroup$

enter image description hereI 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

point_radius = .025

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
line_radius = .01
P_y = 1
P_x = 1

A = np.array([0, 0, 0])
bpy.ops.mesh.primitive_uv_sphere_add(radius=point_radius, location=A)

P = np.array([P_x, P_y, 0])
bpy.ops.mesh.primitive_cylinder_add(location=P,
                                    scale=(line_radius, line_radius, line_len))

# 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.ops.mesh.primitive_uv_sphere_add(radius=point_radius, location=A_proj)
bpy.ops.mesh.primitive_plane_add(size=1, location=A_proj)
bpy.context.object.delta_rotation_euler = (line_rot_x, line_rot_y, np.pi/2)

# connect the A and A_proj
bpy.ops.curve.primitive_bezier_curve_add()
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?

$\endgroup$
2
  • $\begingroup$ Your link doesn’t work $\endgroup$
    – Chris
    Oct 17, 2021 at 22:43
  • $\begingroup$ @Chris fixed it. thanks for letting me know $\endgroup$ Oct 18, 2021 at 6:23

1 Answer 1

0
$\begingroup$

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

# bpy.ops.wm.read_factory_settings(use_empty=True)

point_radius = .025
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
line_radius = .01
P_y = 1
P_x = 1

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


bpy.ops.mesh.primitive_uv_sphere_add(radius=point_radius, location=A)

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.ops.mesh.primitive_uv_sphere_add(radius=point_radius, location=A_proj)



bpy.ops.mesh.primitive_cylinder_add(location=A_proj,
                                    scale=(line_radius, line_radius, line_len))
bpy.context.object.rotation_euler = (line_rot_x,line_rot_y,0)
bpy.ops.mesh.primitive_plane_add(size=1, location=A_proj)
bpy.context.object.rotation_euler = (line_rot_x,line_rot_y,0)

# connect the A and A_proj
bpy.ops.curve.primitive_bezier_curve_add()
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'
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.