I have a set of data points in 3D space which apparently all fall onto a specific plane. I use PCA to compute the plane parameters. The 3rd component of PCA gives me the normal vector of the plane (weakest component).
What I want to do next is to transform all the points onto said plane and look at it in 2D.
My idea was to do the following:
Now I'm stuck at finding the right rotation operation. I tried working with acos or atan and setting up two rotation matrices. Seems both methods (using acos, using atan) give me the wrong result. Perhaps you can help me out here!
Matlab code follows:
b = atan(n(1) / n(2));
rotb = [cos(b) -sin(b) 0; sin(b) cos(b) 0; 0 0 1];
n2 = n * rotb;
a = atan(n(1) / n(3));
rota = [cos(a) 0 sin(a); 0 1 0; -sin(a) 0 cos(a)];
n3 = n2 * rotaows:
I expect n2
to have y component of zero. However that fails already for the vector (-0.6367, 0.7697, 0.0467).
Rotate space about the x axis so that the rotation axis lies in the xz plane. Let U = (a,b,c) be the unit vector along the rotation axis. and define d = sqrt(b2 + c2) as the length of the projection onto the yz plane. If d = 0 then the rotation axis is along the x axis and no additional rotation is necessary.
If a standard right-handed Cartesian coordinate system is used, with the x-axis to the right and the y-axis up, the rotation R(θ) is counterclockwise. If a left-handed Cartesian coordinate system is used, with x directed to the right but y directed down, R(θ) is clockwise.
Here's the accepted answer made in Python:
import numpy as np
def rotate(points, normal, around):
# Let's rotate the points such that the normal is the new Z axis
# Following https://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane
old_x_axis = np.array([1, 0, 0])
z_axis = normal
y_axis = np.cross(old_x_axis, z_axis)
x_axis = np.cross(z_axis, y_axis)
axis = np.stack([x_axis, y_axis, z_axis])
return np.dot(points - around, axis.T)
points = np.array([
[0, 1, 1],
[0, 1, 0.2],
[1, 0, -7]
])
v1 = points[1] - points[0]
v2 = points[2] - points[0]
normal = np.cross(v1, v2)
print("rotated points", rotate(points, normal, points[0]))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With