While playing with quaternions, I noticed that I could not find the angle of rotation of a vector using the dot product between this vector, and its original position. In my example, I rotated a vector by 90 degrees around an arbitrary axis, but the dot product yielded a different angle.
// Axis of rotation (unit vector).
Vec3 Axis = Vec3(1, 1, 0) / sqrt(1 + 1 + 0);
// Creates a quaternion that will rotate a point by 90 degrees around the (1, 1, 0) axis.
Quat q(cos(3.14 / 4), Axis * sin(3.14 / 4));
// Creates a point.
Vec3 Point = Vec3(1, 0, 0);
// Rotates the point by q.
Quat Rot = q * Quat(0, Point) * q.GetConjugate();// Rot == (0, 0.5, 0.5, -0.707)
// Getting Rot's coordinates.
Vec3 v = Vec3(Rot.x, Rot.y, Rot.z);
// Angle is equal to 1.047, but it should be 1.57 (3.14/2)...
float Angle = acos(Dot(Point, v));
Note that every vector and quaternion is of length of 1.
I find that really intriguing, because the shortest angle between a vector rotated by 90 degrees and its original position is 90 degrees.
So my question is: why am I not getting 1.57 radians? What I am not understanding here?
Thank you for your attention.
With the dot product, you are measuring the angle between the initial vector, and the rotated vector, which is generally not the same as the magnitude of the applied rotation.
Imagine if your point was on the rotation axis, then the point would not move when the rotation is applied. To test this, set your point to (1, 1, 0)/sqrt(2), and the angle should be zero.
Then set the point to (1,-1,0)/sqrt(2) and you should get your expected pi/2.
Since you are rotation about the origin, only the component of the point perpendicular to the axis of rotation is effected by the rotation.
A good reference:
https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula
Related
I am trying to alter vertex positions in a vertex shader to form a sine curve along a shape's surface.
As seen in the middle of the page here, a sine wave moving vertically along the z axis could be generated with the simple pattern z = sin(u_time + y);. For every new Y pos, increment the Z pos inward/outward, forming a sine path.
For some reason the outcome is different in my vertex shader. The surface of the shape is changing, but it always stays flat, instead of conforming to a sine curve. See the vertex shader in the example here: https://jsfiddle.net/35w7fsqo/1/ , namely the line
p.z += sin((time + position.y) / duration) * amplitude;
Here's a diagram showing what I mean:
What do I need to do to get this surface to conform to a sine curve?
The BoxGeometry which this shader was running on didn't have enough vertices along the face, it only had one at each corner. I added more heightSegments in the constructor like so var geometry = new THREE.BoxGeometry(200, 200, 200, 1, 10, 1); and now sine curves are visible: https://jsfiddle.net/35w7fsqo/2/
I was doing one of the examples on the p5.js website - https://p5js.org/examples/form-regular-polygon.html. I got really confused by the way rotate function worked in that code . IN the below function if I just pass rotate(frameCount) , in the browser it shows me rotating two triangles intersected within forming a star , but as soon as I divide the frameCount it disappears. Also the equation used in the code - can some one give the mathematical intuition on how we reached to this point.
let sx = x + cos(a) * radius;
let sy = y + sin(a) * radius;
push();
translate(width * 0.2, height * 0.5);
rotate(frameCount / 50);
polygon(0,0,82,3);
pop();
Regarding "two triangles intersected within forming a star":
By default, the rotate function takes radians. When you do rotate(frameCount), you are increasing the angle by 1 radian at each frame. One radian equals about 57 degrees, so your triangle would rotate about 57 degrees at each frame. At frame 3, the triangle would have rotated about 120 degrees, and it would roughly overlap with the triangle at frame 1. Similarly, the triangle at frame 4 would roughly overlap with the triangle at frame 2.
The "two triangles" you are seeing is just two groups of triangles, one group being triangles at frame 1, 3, 5... and another group being triangles at frame 2, 4, 6...
That is why you should divide frameCount by some number if you would like to obtain a rather continuous rotation. Alternatively, you could also set angleMode to DEGREES. In that case, you don't have to divide frameCount anymore because at each frame the triangle would only rotate 1 degree instead of 1 radian.
Regarding the math formula:
In fact, the function used in that example should be called regularPolygon instead of polygon because it only draws regular polygons.
Now, how do you draw a regular polygon? You know the distance from each vertex to the center is a constant number. In this example, that number is the radius variable. And you know if you use polar coordinates with the center of the polygon as the origin point, the angle difference between every two adjacent vertices is also a constant number. In this example, that number is the angle variable.
More precisely, the polar coordinates of the vertices should take the form of:
v1 = (radius, 0)
v2 = (radius, angle)
v3 = (radius, angle*2)
...
Convert them to cartesian coordinates, you would obtain something like:
v1 = (cos(0) * radius, sin(0) * radius)
v2 = (cos(angle) * radius, sin(angle) * radius)
v3 = (cos(angle*2) * radius, sin(angle*2) * radius)
...
But what if the center of the polygon is not the origin point, but point (x, y), as in the example? Now the cartesian coordinates of the vertices become:
v1 = (x + cos(0) * radius, y + sin(0) * radius)
v2 = (x + cos(angle) * radius, y + sin(angle) * radius)
v3 = (x + cos(angle*2) * radius, y + sin(angle*2) * radius)
So when you do:
for (let a = 0; a < TWO_PI; a += angle) {
let sx = x + cos(a) * radius;
let sy = y + sin(a) * radius;
vertex(sx, sy);
}
You are really drawing the vertices v1, v2, v3....
I would like to rotate an object on a certain angle along Y axis.
Based on this answer How to rotate a Three.js Vector3 around an axis? I suppose to get an updated vector.
My code is :
var vec = new THREE.Vector3( 0,0,0 );
var axis = new THREE.Vector3( 0,1,0 );
var angle = Math.PI / 2;
vec.applyAxisAngle( axis, angle );
I'm using r67 and it returns me 0,0,0. I've tried r69 as well and it is returns me the same. I'm not quiet ready to move to r69. Could you guys tell me please how to do the same thing but using r67. Thanks.
Your are rotating vector (0, 0, 0) which is center and whatever angle you use to rotate center around any axis you will always get (0, 0, 0). Just imagine you are doing simple 2d rotation. After all, rotation around Y axis can be viewed as 2d rotation in X-Z plane.
Try with some other values for vec variable, for example (1, 0, 0) or (0, 0, 1) and you will see results
I've got two nodes, and I know the rotation of only one of them.
I want to apply the rotation of node 1 to node 2, but with one axis zeroed out (in Euler terms).
How?
Never mind, I figured it out.
e.g. For x axis:
double xRot = -(myQuat.ToEuler().x)
Quat qDiff = Quat(sin(xRot / 2.0), 0, 0, cos(xRot / 2.0)).Normalize()
Quat myQuatZeroX = myQuat * qDiff
Im trying to find out the angle (in degrees) between two 2D vectors. I know I need to use trig but I'm not too good with it. This is what I'm trying to work out (the Y axis increases downward):
I'm trying to use this code at the moment, but it's not working at all (calculates random angles for some reason):
private float calcAngle(float x, float y, float x1, float y1)
{
float _angle = (float)Math.toDegrees(Math.atan2(Math.abs(x1-x), Math.abs(y1-y)));
Log.d("Angle","Angle: "+_angle+" x: "+x+" y: "+y+" x1: "+x1+" y1: "+y1);
return _angle;
}
These are my results (There constant when providing a constant position, but when I change the position, the angle changes and I can't find any link between the two angles):
Position 1:
x:100 y:100
x1:50 y1:50
Angle: 45
Position 2:
x:92 y:85
x1:24 y1:16
Angle: 44.58
Position 3:
x:44 y: 16
x1:106 y1:132
Angle: 28.12
Edit: Thanks everyone who answered and helped me figure out that was wrong! Sorry the title and the question was confusing.
You first have to understand how to compute angle between two vectors and there are several of them. I will give you what I think is the simplest.
Given v1 and v2, their dot product is: v1x * v2x + v1y * v2y
The norm of a vector v is given by: sqtr(vx^2+vy^2)
With this information, please take this definition:
dot(v1, v2) = norm(v1) * norm(v2) * cos(angle(v1, v2))
Now, you solve for angle(v1, v2):
angle(v1, v2) = acos( dot(v1, v2) / (norm(v1) * norm(v2)) )
Finally, taking the definitions given at the beginning, then you end up with:
angle(v1, v2) = acos( (v1x * v2x + v1y * v2y) / (sqrt(v1x^2+v1y^2) * sqrt(v2x^2+v2y^2)) )
Again, there are many ways to do this, but I like this one because it is helpful for dot product given angle and norm, or angle, given vectors.
The answer will be in radians, but you know that pi radians (that is 3.14 radians) are 180 degrees, so you simply multiply by the conversion factor 180/pi.
Aha! Turns out I just needed to flip my angle and use atan2. This is my final code:
private float calcAngle(float x, float y, float x1, float y1)
{
float _angle = (float)Math.toDegrees(Math.atan2(x1-x, y-y1));
return _angle;
}
Thanks everyone for helping me figure this out and also for helping me to understand what I'm actually doing! :)
Do not take the absolute value of the arguments to atan2. The whole point of atan2 is that it uses the signs of its arguments to work out which qaudrant the angle is in. By taking the absolute values you are forcing atan2 to only return values between 0 and pi/2 instead of -pi to pi.
It looks like Niall figured it out, but I'll finish my explanation, anyways. In addition to explaining why the solution works, my solution has two advantages:
Potential division by zero within atan2() is avoided
Return value is always positive in the range 0 to 360 degrees
atan2() returns the counter-clockwise angle relative to the positive X axis. Niall was looking for the clockwise angle relative to the positive Y axis (between the vector formed by the two points and the positve Y axis).
The following function is adapted from my asteroids game where I wanted to calculate the direction a ship/velocity vector was "pointing:"
// Calculate angle between vector from (x1,y1) to (x2,y2) & +Y axis in degrees.
// Essentially gives a compass reading, where N is 0 degrees and E is 90 degrees.
double bearing(double x1, double y1, double x2, double y2)
{
// x and y args to atan2() swapped to rotate resulting angle 90 degrees
// (Thus angle in respect to +Y axis instead of +X axis)
double angle = Math.toDegrees(atan2(x1 - x2, y2 - y1));
// Ensure result is in interval [0, 360)
// Subtract because positive degree angles go clockwise
return (360 - angle) % 360;
}
It should be :
atan( abs(x1 - x)/abs(y1 - y) )
abs stands for absolute (to avoid negative values)
I believe the equation for the angle between two vectors should look more like:
toDegrees(acos((x*x1+y*y1)/(sqrt(x*x+y*y)*sqrt(x1*x1+y1*y1))))
Your above equation will calculate the angle made between the vector p1-p2 and the line made by extending an orthogonal from the point p2 to the vector p1.
The dot product of two vectors V1 and V2 is equal to |V1|*|V2|cos(theta). Therefore, theta is equal to acos((V1 dot V2)/(|V1||V2|)). V1 dot V2 is V1.xV2.x+V1.yV2.y.
The magnitude of V (i.e., |V|) is the pathogorean theorem... sqrt(V.x^2 + V.y^2)
My first guess would be to calculate the angle of each vector with the axes using atan(y/x) and then subtract those angels and take the absolute value, that is:
abs(atan(y/x) - atan(y1/x1))
Are you using integers? Cast the arguments as doubles, and I would use fabs on the result, not the arguments. The result will be in radians; to get degrees, use:
res *= (360.0/(2.0*Math.PI));
The angle of the second vector relative to the first = atan2(y2,x2) - atan2(y1,x1).
http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm