I am trying to make a geometry in Houdini face the same direction as a normal on a line. I am getting the normal as a vector with magnitude 1 and then using the formula angle = arccos((x dot y)/(magnitude x * magnitude y). to get the angle to rotate the object and then multiplying by 180 to convert it to degrees. for some reason this does not give a consistent result.
Am I doing something obviously wrong with my math? I am new to Houdini so I'm not sure if I might be missing something about the environment that would complicate this.
Here is the python code I am using.
#normalize and store as vector3
currentNormal = hou.Vector3(currentNormal).normalized()
previousNormal = hou.Vector3(previousNormal).normalized()
#get dot product and magnitudes
dotProd = numpy.dot(previousNormal, currentNormal)
previousMagnitude = numpy.sqrt((previousNormal[0]**2) + (previousNormal[1]**2) + (previousNormal[2]**2))
currentMagnitude = numpy.sqrt((currentNormal[0]**2) + (currentNormal[1]**2) + (currentNormal[2]**2))
nextLocationRotate = numpy.arccos(dotProd/(previousMagnitude * currentMagnitude))
nextLocationRotate = [0.0, nextLocationRotate*180, 0.0]
I am trying to get a rotation around the y axis.
Related
I'm trying to use ray casting to gather all the surfaces in a room and determine it's volume.
I have a centroid location where the rays will be coming from, but I'm drawing a blank on how to get the rays in all 360 degrees (in 3D space).
I'm not getting any points on the floors or ceilings, it's like it's doing a 60 degree spread rotated about the Z axis.
I think I have the rest of it working, but this is stumping me.
for y in range(360):
for x in range(360):
vector = DB.XYZ(math.sin(math.radians(x)), math.cos(math.radians(x)), math.cos(math.radians(y))).Normalize()
prox = ri.FindNearest(origin, direction).Proximity
point = origin + (direction * prox)
Look at it this way: x and y of vector are created from angle x (-> a circle in the plane) and then you add a z component which lies between -1 and 1 (which cos does). So it's obvious that you end up with a cylindrical distribution.
What you might want are spherical coordinates. Modify your code like this:
for y in range(-90, 91):
for x in range(360):
vector = DB.XYZ(math.sin(math.radians(x)) * cos(math.radians(y)),
math.cos(math.radians(x)) * cos(math.radians(y)),
math.sin(math.radians(y))) # Normalize unnecessary, since vector² = sin² * cos² + cos² * cos² + sin² = 1
prox = ri.FindNearest(origin, direction).Proximity
point = origin + (direction * prox)
But be aware that the angle distribution of rays is not uniform using spherical coordinates. At the poles it's more dense than at the equator. You can mitigate this e.g. by scaling the density of x down, depending on y. The surface elements scale down by cos(y)², so I think you have to scale by cos(y).
I'm disassembling a rotation matrix to Euler angles (Tait-Bryan angles more specifically in the order x-y-z, that is rotation around x axis first) and back to a rotation matrix. I used the transforms3d python library (https://github.com/matthew-brett/transforms3d) and also followed this tutorial www.gregslabaugh.net/publications/euler.pdf Both give the same result.
The problem is that the reassambled rotation matrix doesn't match the one that I started with.
The matrix I'm working with was created by the "decomposeHomographyMat" function from openCV, so I expect it to be a valid rotation matrix. Maybe it is a special case?
The matrix is
The three angles are [-1.8710997 , 0.04623301, -0.03679793]. If I convert them back to a rotation matrix I get
where R_23 cannot be a rounding error.
Following the paper above, rotation around the y axis (beta) can be calculated by asin(-R_31). Another valid angle would be pi-asin(-R_31).
The angle around the x axis (alpha) can be calculated by atan2(R_32,R_33). I could also get alpha by asin(R_32/cos(beta)) or by acos(R_33/cos(beta)). If I use the latter two equations I only get the same result for alpha if I use beta=pi-arcsin(-R_31), which implies that there is only one valid solution for beta. atan2(R_32,R_33) gives a different result from both.
Anyway something seems to be wrong with my matrix or I cannot figure out why the disassambly doesn't work.
import numpy as np
def rot2eul(R):
beta = -np.arcsin(R[2,0])
alpha = np.arctan2(R[2,1]/np.cos(beta),R[2,2]/np.cos(beta))
gamma = np.arctan2(R[1,0]/np.cos(beta),R[0,0]/np.cos(beta))
return np.array((alpha, beta, gamma))
def eul2rot(theta) :
R = np.array([[np.cos(theta[1])*np.cos(theta[2]), np.sin(theta[0])*np.sin(theta[1])*np.cos(theta[2]) - np.sin(theta[2])*np.cos(theta[0]), np.sin(theta[1])*np.cos(theta[0])*np.cos(theta[2]) + np.sin(theta[0])*np.sin(theta[2])],
[np.sin(theta[2])*np.cos(theta[1]), np.sin(theta[0])*np.sin(theta[1])*np.sin(theta[2]) + np.cos(theta[0])*np.cos(theta[2]), np.sin(theta[1])*np.sin(theta[2])*np.cos(theta[0]) - np.sin(theta[0])*np.cos(theta[2])],
[-np.sin(theta[1]), np.sin(theta[0])*np.cos(theta[1]), np.cos(theta[0])*np.cos(theta[1])]])
return R
R = np.array([[ 0.9982552 , -0.03323557, -0.04880523],
[-0.03675031, 0.29723396, -0.95409716],
[-0.04621654, -0.95422606, -0.29549393]])
ang = rot2eul(R)
eul2rot(ang)
import transforms3d.euler as eul
ang = eul.mat2euler(R, axes='sxyz')
eul.euler2mat(ang[0], ang[1], ang[2], axes='sxyz')
It turns out the rotation matrix has a negative determinant, which makes it an improper rotation matrix. The openCV function "decomposeHomographyMat" has a bug: https://github.com/opencv/opencv/issues/4978
May be you can use scipy
from scipy.spatial.transform import Rotation
### first transform the matrix to euler angles
r = Rotation.from_matrix(rotation_matrix)
angles = r.as_euler("zyx",degrees=True)
#### Modify the angles
print(angles)
angles[0] += 5
#### Then transform the new angles to rotation matrix again
r = Rotation.from_euler("zyx",angles,degrees=True)
new_rotation_matrix = new_r.as_matrix()
I have two curves which meet around origin z and y, listed below. When I plot these according to certain functions I get the attached plot.
origin_z = 260
origin_y = 244
plt.plot(phi_z+origin_z,phi_y+origin_y,'b')
plt.plot(phi_z+origin_z,phi_y+origin_y,'r')
Where phi_z and _y are some functions (which I have avoided posting for the sake of clarity). I want to rotate both lines about 45 degrees clockwise around the specified origin, but when I try the following code, it merely shifts the curves further along each axis rather than rotating them:
phi_z_rot = origin_z + np.cos(45) * (phi_z - origin_z) - np.sin(45) * (phi_z - origin_z)
phi_y_rot = origin_y + np.cos(45) * (phi_y - origin_y) - np.sin(45) * (phi_y - origin_y)
Can anyone tell me what I'm doing wrong? Sorry for not posting more of the functions, but hopefully it isn't necessary.
Without much information is very little what I can explicitly provide. Anyhow, you have your rotation wrong. First the angles are in degrees instead of radians, and then you use the incorrect rotation matrix.
Avoiding the translation of the coordinates, the proper rotation is as follows:
rot = np.pi/4
phi_z_rot = phi_z*np.cos(rot)+phi_y*np.sin(rot)
phi_y_rot = -phi_z*np.sin(rot)+phi_y*np.cos(rot)
I am working in python and i have previous (x_prev,y_prev) = (1.5, 3) coordinate and current (x,y) = (2, 3.2)coordinate and angle difference between them and i want the next coordinate to be at a certain distance d with the same orientation as the current (x,y)coordinate. I have tried using the rotation and translation formula but it fails to give the proper answer. here is the code so far what i tried.
d = 0.5
angle = np.arctan2((y - y_prev), (x - x_prev))
x_ = x * np.cos(angle) - y * np.sin(angle) + (d * np.sinc(angle_/2)* np.cos(angle/2))
y_ = x * np.sin(angle) + y * np.cos(angle) + (d * np.sinc(angle_/2)* np.sin(angle/2))
the expected coordinate is approximately (x_,y_) = (2.5, 3.6) with the same orientation as the current but it results in wrong coordinate so is there anything i am missing.
Thanks in advance
I partly agree with #ImportanceOfBeingErnest that your question is a geometrical one. However, I'm adding an answer because numpy lets you avoid all that trigonometric work that you are trying to do in the first place.
What you want is to find the point (x_new,y_new) based on (x_prev,y_prev) and (x_now,y_now) such that the three points lie on the same line and the distance between (x_prev,y_prev) and (x_new,y_new) is a preset d.
You don't need trigonometry if you can work with proper two-dimensional vectors. You can normalize the vector (x_now,y_now) - (x_prev,y_prev) to get an orientation vector of the line along which you need to move from (x_prev,y_prev) in order to end up at (x_new,y_new). Numpy lets you handle this elegantly:
import numpy as np
x_prev,y_prev = (1.5, 3)
x_now,y_now = (2, 3.2)
d = 0.5
# use 2d arrays for elegant vector operations
# of course we can directly define these from coordinates if we want to
p_prev = np.array([x_prev,y_prev])
p_now = np.array([x_now,y_now])
# compute the unit direction vector for p_new - p_prev
t = p_now - p_prev
t /= np.linalg.norm(t) # use Euclidean norm by default
# p_new is simple now:
p_new = p_prev + d*t
print(p_prev)
print(p_now)
print(p_new)
The above results in (x_new,y_new)=(1.96423835,3.18569534). Your points are actually such that (x_now,y_now) is almost at 0.5 distance from (x_prev,y_prev), so the resulting vector is hardly different from the original one. But anyway, the above procedure will always give you a new point which is at the same angle from (x_prev,y_prev) as (x_now,y_now) but at the fixed distance.
I want to compute the distance between an arc and a point in a 3D space. All I found is the distance between a circle and a point link (which is either wrong, or where I made a mistake, as I get wrong values):
P = np.array([1,0,1])
center = np.array([0,0,0])
radius = 1
n2 = np.array([0,0,1])
Delta = P-center
dist_tmp = np.sqrt( (n2*Delta)**2 + (np.abs(np.cross(n2, Delta))-radius)**2 )
dist = np.linalg.norm(dist_tmp)
I have a circle in the x-y-plane with origin at x-y-z = 0 and radius = 1. The point of interest is in distance 1 above the circle. The result of the distance from the code is 1.73.. and not 1.
What is the right equation for point-circle distance?
How can I extend it to point-arc distance?
You have several errors in your code. Here is the answer to your first question.
First, you try to implement the dot product of n2 and Delta as n2*Delta, but that is not what the multiplication of 2 np arrays does. Use np.dot() instead. Next, you try to take the "absolute value" (magnitude) of a vector with np.abs, but that latter is for real and complex numbers only. One way to get the vector magnitude is np.linalg.norm(). Changing those gives you the proper answer, and you don't need the calculation you used for variable dist. So use
Delta = P-center
dist = np.sqrt(np.dot(n2, Delta)**2 + (np.linalg.norm(np.cross(n2, Delta))- radius)**2)
That gives the proper answer for dist, 1.0.