Could someone help me solve this problem? How can I find the angle shown in picture? I think I need to find angle between 2 vectors but im really bad at geometry.
http://i.stack.imgur.com/W0RKh.png
If you are developing your program in C++, then to calculating an angle between two vectors you can use the atan2 function, it is present in many programming languages.
You need to call atan2 giving it the two components of a single vector and then you make calculations this way:
Calculating for the first vector: atan2(v1_y, v1_x)
Calculating for the second vector: atan2(v2_y, v2_x)
Caution:
If the value returned by atan2 is negative (as atan2 returns value from range (-pi;+pi]), then you need to add 2 * pi to the result for each of the vector.
Finally you subtract the values of the vectors and what you get is the angle. The angle will be either positive or negative, depending which atan2 value you subtract from which one.
You need to normalize both vectors and then perform a dot product.
Step 1: Vector normalization:
A normalized vector has a length of 1. To achieve this, you divide its coordinates by its length:
float d = 1 / sqrt(X * X + Y * Y + Z * Z);
normalizedX = X * d;
normalizedY = Y * d;
normalizedZ = Z * d;
Note: The length is inversed and then multiplied instead of divided in order to increase performance.
Step 2: Dot product
After your normalized both vectors like in Step 1, you need to perform a dot product:
float angle = acos(x1 * x2 + y1 * y2 + z1 * z2);
The result is the cosine of the angle between the two vectors. After an acos you have your angle.
Related
I have two vectors and I want to get the angle between those vectors, I am currently doing it with this formula :
acos(dot(v1.unitVector, v2.unitVector))
Here is what I get with it :
I would want the green angle rather than the red angle, but I don't know what formula I should use...
Thank you.
EDIT : So, hen the vectors are still in a certain position (like the first two pairs of vectors, it's ok, but whenever it is in a configuration like in the third pair, it doesn't give me the right angle anymore)
With the dot product you get always an angle that is independent of the order of the vectors and the smaller of the two possibilities.
For what you want, you need the argument function of complex numbers that is realized by the atan2 function. The angle from a=ax+i*ay to b=bx+i*by is the argument of the conjugate of a times b (rotating b backwards by the angle of a, scale not considered), which in coordinates is
(ax-i*ay) * (bx+i*by) = ax*bx+ay*by + i*(ax*by-ay*bx)
so the angle is
atan2( ax*by-ay*bx, ax*bx+ay*by ).
Adding to the accepted answer, the problem with atan2 is that, if you imagine vector a being static and vector b rotating in anti-clockwise direction, you will see the return value ranging from 0 to π, but then it suddenly turns negative and proceeds from -π to 0, which is not exactly good if you're interested in an angle increasing from 0 to 2π.
To tackle that problem, the function below conveniently maps the result from atan2 and returns a value between 0 and 2π as one would expect:
const TAU = Math.PI * 2;
/**
* Gives the angle in radians from vector a to vector b in anticlockwise direction,
* ranging from 0 to 2π.
*
* #param {Vector} a
* #param {Vector} b
* #returns {Number}
*/
static angle(a, b) {
let angle = Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);
if (angle < 0) {
angle += TAU;
}
return angle;
}
It is written in JavaScript, but it's easily portable to other languages.
Lutz already answered this correctly but let me add that I highly recommend basing modern vector math code on Geometric Algebra which raises the abstraction level dramatically.
Using GA, you can simply multiply the two vectors U and V to get a rotor. The rotor internally looks like A + Bxy where A = U dot V = |U|V|cos(angle) and Bxy = U wedge V = |U||V|sin(angle)xy (this is isomorphic to the complex numbers). Then you can return the rotor's signed CCW angle which is atan2( B, A ).
So with operator overloading, you can just type (u * v).Angle. The final calculations end up the same, but the abstraction level you think and work in is much higher.
Maybe this one is more fit:
atan2( ax*by-ay*bx, ax*bx+ay*by ) % (PI*2)
the calculation which could get the full anti-clockwise radian.
I have an object at coordinates (0, 0, 0) and I want to translate this object in any direction a predetermined distance, for example 5.
How do I to find the final coordinates? (not iteratively checking)
You can achieve exactly the same as T.Kiley said just picking a totally random vector, it will have a random direction and random magnitude. You can then normalize that vector and multiply it by 5 (or the desired magnitude).
I believe what you are asking is how do you generate a point that is 5 away from the origin (0,0,0). In general, you can use the parametric equations of a sphere to generate these points by first picking two random numbers in the range [0, 2pi] and [0, pi] respectively, then your point is
x = r * cos(theta) * sin(phi)
y = r * sin(theta) * sin(phi)
z = r * cos(phi)
Where theta is the first random number, phi is the second and r is your distance from the origin.
In Unity, it is even easier as you can use Random.onUnitSphere to give you a point exactly 1 away from the origin. Then just multiply by 5, e.g.:
finalPosition = Random.onUnitSphere * r
Again, where r in your example would be 5.
The magnitude of the cross product describes the signed area of the parallelogram described by the two vectors (u, v) used to build the cross product, it has its uses. This same magnitude can be calculated as the magnitude of u times the magnitude of v times the sine of the angle between u and v:
||u||||v||sin(theta).
Now the dot product of u (normalized) and v (normalized) gives the cosine of the angle between u and v:
cos(theta)==dot(normalize(u), normalize(v))
I want to be able to get the signed sine value that is related to the cosine value. It is related because the sine and cosine waves are PI/2 out of sync. I know that the square root of 1 less the cosine value squared gives the unsigned sine value:
sin(theta)==sqrt(1 - (cos(theta) * cos(theta))
Where by cos(theta) I mean the dot product not the angle.
But the attendant sign calculation (+/-) requires theta as an angle:
(cos(theta + PI / 2)) > or == or < 0
If I have to perform an acos function I might as well just do the cross product and find the magnitude.
Is there a known ratio or step that can be added to a cosine value to get its related sine value?
For each possible cosine, both signs are possible for the sine if the corresponding angle is unrestricted.
If you know the angle is between [0,pi], then the sine must be positive or zero.
If you want to know the area of a parallelogram, always take the positive branch sin(x) = sqrt(1 - cos(x)^2). Negative area rarely makes sense (only to define orientation w.r.t. to a plane such as for backface culling)
If you have the two vectors, use a cross product or dot product directly, not the other one and convert.
Seems to me like a complicated way to get to atan2 identities:
d = 𝐚·𝐛 = |𝐚||𝐛|cosθ
c = |𝐚×𝐛| = |𝐚||𝐛|sinθ (with 0° < θ < 180°)
tanθ = 𝐚·𝐛 / |𝐚×𝐛|
θ = atan2(c·sgn(c|z), d) (= four quadrant)
where sgn(c|z) is the sign of the z-component in c (unless 𝐚 and 𝐛 both run exactly parallel with the xz or yz plane, then its the sign of the y-component and x-component, respectively).
Now, from basic trig identities,
r = √(x²+y²)
cos(atan2(y,x)) = x/r
sin(atan2(y,x)) = y/r
Therefore,
sinθ = c·sgn(c|z)/√(c²+d²)
cosθ = d/√(c²+d²)
I think I have found a solution.
cos(b) == sin(a)
v_parallel = dot(normalize(u), v) // the projection of v on u
v_perp = normalize(v) - v_parallel
cos(b) = dot(normalize(v), v_perp) // v_perp is already normalized
Therefore, the magnitude of
u cross v = magnitude(u) * magnitude(v) * cos(b)
What is a formula to get a three dimensional vector B lying on the plane perpendicular to a vector A?
That is, given a vector A, what is a formula f(angle,modulus) which gives a vector that is perpendicular to A, with said modulus and rotated through an angle?
If the two vectors are perpendicular then their dot product is zero.
So: v1(x1, y1, z1), v2(x2, y2, z2).
=> x1 * x2 + y1 * y2 + z1 * z2 = 0
You know (x1, y1, z1). Put arbitrary x2 andy2 and you will receive the corresponding z2:
z1 * z2 = -x1 * x2 - y1 * y2
=> z2 = (-x1 * x2 - y1 * y2) / z1
Be aware if z1 is 0. Then you are in the plane.
function (a,b,c)
{
return (-b,a,0)
}
But this answer is not numerical stable when a,b are close to 0.
To avoid that case, use:
function (a,b,c)
{
return c<a ? (b,-a,0) : (0,-c,b)
}
The above answer is numerical stable, because in case c < a then max(a,b) = max(a,b,c), then vector(b,-a,0).length() > max(a,b) = max(a,b,c) , and since max(a,b,c) should not be close to zero, so is the vector. The c > a case is similar.
Calculate the cross product AxC with another vector C which is not collinear with A.
There are many possible directions in the plane perpendicular to A. If you don't really care, which one to pick, just create an arbitrary vector C not collinear with A:
if (A2 != 0 || A3 != 0)
C = (1, 0, 0);
else
C = (0, 1, 0);
B = A x C;
I believe that this should produce an arbitrary vector that is perpendicular to the given vector vec while remaining numerically stable regardless of the angle of vec (assuming that the magnitude of vec is not close to zero). Assume that Vec3D is a three dimensional vector of arbitrary numerical type.
Vec3D arbitrary_orthogonal(Vec3D vec)
{
bool b0 = (vec[0] < vec[1]) && (vec[0] < vec[2]);
bool b1 = (vec[1] <= vec[0]) && (vec[1] < vec[2]);
bool b2 = (vec[2] <= vec[0]) && (vec[2] <= vec[1]);
return cross(vec, Vec3D(int(b0), int(b1), int(b2)));
}
Informal explanation
Exactly 1 and only 1 of the bools get set; bN gets set if dimension N has magnitude strictly less than all subsequent dimensions and not greater than all previous dimensions. We then have a unit vector with a single non-zero dimension that corresponds to a dimension of minimum magnitude in vec. The cross product of this with vec is orthogonal to vec by defn of cross product. Consider now that the cross product is numerically unstable only when the two vectors are very closely aligned. Consider that our unit vector is large in only a single dimension and that that dimension corresponds to the dimension where vec was small. It's thus guaranteed to be loosely orthogonal to vec before taking the cross product, with least orthogonality in the case where all dimensions of vec are equal. In this least-orthogonal case, we're still quite orthogonal given that our unit vector has all but one dimension 0 whereas vec has all equal. We thus avoid the unstable case of taking the cross product of two nearly-aligned vectors.
q4w56's is almost there for a robust solution. Problems: 1) Doesn't take in account scaling. 2) Doesn't compare the magnitude between two variables when it should.
scale = |x| + |y| + |z|
if scale == 0:
return (0,0,0)
x = x/scale
y = y/scale
z = z/scale
if |x| > |y|:
return (z, 0,-x)
else:
return (0, z,-y)
Scaling is important when dealing with very large or very small numbers. Plus in general you are better off doing floating point operations on values between 0 and 1.
One way would be to find a rotation transform from the positive z-axis (or any other axis) to your given vector. Then transform <modulus * cos(angle), modulus * sin(angle), 0> using this transform.
def getPerpendicular(v1,modulus,angle):
v2 = vector(0,0,1)
v1_len = v2.length()
axis = v1.cross_product(v2)
sinAngle = axis.length() / v1_len # |u x v| = |u| * |v| * sin(angle)
cosAngle = v1.dot_product(v2) / v1_len # u . v = |u| * |v| * cos(angle)
axis = axis.normalize()
# atan2(sin(a), cos(a)) = a, -pi < a < pi
angle = math.atan2(sinAngle, cosAngle)
rotationMatrix = fromAxisAngle(axis, angle)
# perpendicular to v2
v3 = vector(modulus*cos(angle),modulus*sin(angle),0)
return rotationMatrix.multiply(v3);
To calculate the rotation matrix, see this article: WP: Rotation matrix from axis and angle
Another method would be to use quaternion rotation. It's a little more to wrap your head around, but it's less numbers to keep track of.
I have a unit vector in 3D space whose direction I wish to perturb by some angle within the range 0 to theta, with the position of the vector remaining the same. What is a way I can accomplish this?
Thanks.
EDIT: After thinking about the way I posed the question, it seems to be a bit too general. I'll attempt to make it more specific: Assume that the vector originates from the surface of an object (i.e. sphere, circle, box, line, cylinder, cone). If there are different methods to finding the new direction for each of those objects, then providing help for the sphere one is fine.
EDIT 2: I was going to type this in a comment but it was too much.
So I have orig_vector, which I wish to perturb in some direction between 0 and theta. The theta can be thought of as forming a cone around my vector (with theta being the angle between the center and one side of the cone) and I wish to generate a new vector within that cone. I can generate a point lying on the plane that is tangent to my vector and thus creating a unit vector in the direction of the point, call it rand_vector. At this time, I orig_vector and trand_vector are two unit vectors perpendicular to each other.
I generate my first angle, angle1 between 0 and 2pi and I rotate rand_vector around orig_vector by angle1, forming rand_vector2. I looked up a resource online and it said that the second angle, angle2 should be between 0 and sin(theta) (where theta is the original "cone" angle). Then I rotate rand_vector2 by acos(angle2) around the vector defined by the cross product between rand_vector2 and orig_vector.
When I do this, I don't obtain the desired results. That is, when theta=0, I still get perturbed vectors, and I expect to get orig_vector. If anyone can explain the reason for the angles and why they are the way they are, I would greatly appreciate it.
EDIT 3: This is the final edit, I promise =). So I fixed my bug and everything that I described above works (it was an implementation bug, not a theory bug). However, my question about the angles (i.e. why is angle2 = sin(theta)*rand() and why is perturbed_vector = rand_vector2.Rotate(rand_vector2.Cross(orig_vector), acos(angle2)). Thanks so much!
Here's the algorithm that I've used for this kind of problem before. It was described in Ray Tracing News.
1) Make a third vector perpendicular to the other two to build an orthogonal basis:
cross_vector = unit( cross( orig_vector, rand_vector ) )
2) Pick two uniform random numbers in [0,1]:
s = rand( 0, 1 )
r = rand( 0, 1 )
3) Let h be the cosine of the cone's angle:
h = cos( theta )
4) Modify uniform sampling on a sphere to pick a random vector in the cone around +Z:
phi = 2 * pi * s
z = h + ( 1 - h ) * r
sinT = sqrt( 1 - z * z )
x = cos( phi ) * sinT
y = sin( phi ) * sinT
5) Change of basis to reorient it around the original angle:
perturbed = rand_vector * x + cross_vector * y + orig_vector * z
If you have another vector to represent an axis of rotation, there are libraries that will take the axis and the angle and give you a rotation matrix, which can then be multiplied by your starting vector to get the result you want.
However, the axis of rotation should be at right angles to your starting vector, to get the amount of rotation you expect. If the axis of rotation does not lie in the plane perpendicular to your vector, the result will be somewhat different than theta.
That being said, if you already have a vector at right angles to the one you want to perturb, and you're not picky about the direction of the perturbation, you can just as easily take a linear combination of your starting vector with the perpendicular one, adjust for magnitude as needed.
I.e., if P and Q are vectors having identical magnitude, and are perpendicular, and you want to rotate P in the direction of Q, then the vector R given by R = [Pcos(theta)+Qsin(theta)] will satisfy the constraints you've given. If P and Q have differing magnitude, then there will be some scaling involved.
You may be interested in 3D-coordinate transformations to change your vector angle.
I don't know how many directions you want to change your angle in, but transforming your Cartesian coordinates to spherical coordinates should allow you to make your angle change as you like.
Actually, it is very easy to do that. All you have to do is multiply your vector by the correct rotation matrix. The resulting vector will be your rotated vector. Now, how do you obtain such rotation matrix? That depends on the 3d framework/engine you are using. Any 3d framework must provide functions for obtaining rotation matrices, normally as static methods of the Matrix class.
Good luck.
Like said in other comments you can rotate your vector using a rotation matrix.
The rotation matrix has two angles you rotate your vector around. You can pick them with a random number generator, but just picking two from a flat generator is not correct. To ensure that your rotation vector is generated flat, you have to pick one random angle φ from a flat generator and the other one from a generator flat in cosθ ;this ensures that your solid angle element dcos(θ)dφ is defined correctly (φ and θ defined as usual for spherical coordinates).
Example: picking a random direction with no restriction on range, random() generates flat in [0,1]
angle1 = acos(random())
angle2 = 2*pi*random()
My code in unity - tested and working:
/*
* this is used to perturb given vector 'direction' by changing it by angle not more than 'angle' vector from
* base direction. Used to provide errors for player playing algorithms
*
*/
Vector3 perturbDirection( Vector3 direction, float angle ) {
// division by zero protection
if( Mathf.Approximately( direction.z, 0f )) {
direction.z = 0.0001f;
}
// 1 get some orthogonal vector to direction ( solve direction and orthogonal dot product = 0, assume x = 1, y = 1, then z = as below ))
Vector3 orthogonal = new Vector3( 1f, 1f, - ( direction.x + direction.y ) / direction.z );
// 2 get random vector from circle on flat orthogonal to direction vector. get full range to assume all cone space randomization (-180, 180 )
float orthoAngle = UnityEngine.Random.Range( -180f, 180f );
Quaternion rotateTowardsDirection = Quaternion.AngleAxis( orthoAngle, direction );
Vector3 randomOrtho = rotateTowardsDirection * orthogonal;
// 3 rotate direction towards random orthogonal vector by vector from our available range
float perturbAngle = UnityEngine.Random.Range( 0f, angle ); // range from (0, angle), full cone cover guarantees previous (-180,180) range
Quaternion rotateDirection = Quaternion.AngleAxis( perturbAngle, randomOrtho );
Vector3 perturbedDirection = rotateDirection * direction;
return perturbedDirection;
}