Finding Angle between Vertices

Hi,

I want to find the angle between three vertices (they may have different x, y, z value). However, I don't know how to find it efficiently. Now, I only have the idea to find the length of three lines between each vertice first. Then, I use cosine law to find the angle using the lenght of three lines.

Is there any efficient method to find the angle between three vertices?

The angle between two normal vectors is the arccos of their dot product, so you can compute the angle at x as follows:


angle = acos( dot( normalize(y-x), normalize(z-x) ) )

I’m sorry. Since I implement it in WebGL, WebGL does not have this function. Is there any other possible methods to do it?

this function -> Which one ?
If you want to do this calculation on CPU, find a math libs or implement what you need yourself.
Otherwise this looks like legit code for both GLSL and “WebGLSL”.

Hi,

I mean the normalize and dot function. This is because I will use three vertices to calculate the angle and use the angle to change one of three vertices. However, I still don't know how can I change the angle and get the related vertices.

Until now, I can input the length of the line to find out new vertices. But I am required to implement the angle part (and I think this is the most important and diffiuclt part).

Since there are three vertices, if I update the angle, it may change one/two of three vertices (at least one vertice is fixed) to form the new angle. But I'm thinking how to implement it well with javascript and WebGL.

Get/implement a math lib for Javascript. Without it you won’t get any far. (are vital, as you see with your task).
The “normalize” and “dot” are the most basic of basic operations you’ll meet.
For the second half, you’ll need cross() to find the triangle plane-normal, and then a rotate(axis,angle) function.

well dot and normalize functions are quite simple actually, C-like pseudo code :


double dot(vector a, vector b) {
  return (ax*bx + ay*by + az*bz);
)

vector normalize(vector a) {
  double term = 1.0/sqrt(ax*ax + ay*ay + az*az);
  vector b = (ax*term , ay*term , az*term);
  return b;
)

Hi,

I have already completed the first part (finding angle). However, I still don't understand the second part. You mentioned I need the cross product function to find the vertice. However, I only know the cross product can find the area, not the vertice. How can I find the vertice?

http://en.wikipedia.org/wiki/Cross_product

struct

You need to normalize both its inputs.


struct vec3{
	float x,y,z;
};

float dot(vec3 a, vec3 b) {
  return (a.x*b.x + a.y*b.y + a.z*b.z);
)

vec3 normalize(vec3 a) {
  double term = 1.0/sqrt(a.x*a.x + a.y*a.y + a.z*a.z);
  vec3 b = {ax*term , ay*term , az*term};
  return b;
)
vec3 vsub(vec3 a,vec3 b){
	vec3 result = {a.x-b.x,a.y-b.y,a.z-b.z};
	return result;
}




struct Mat4{
	float a00, a10, a20, a30;
	float a01, a11, a21, a31;
	float a02, a12, a22, a32;
	float a03, a13, a23, a33;   // XYZ of translation is here!
	
	void CreateRotate(float angle, const vec3 &v);
	
	vec3 DoTransform(const vec3& v);
};

void Mat4::CreateRotate(float angle, const vec3 &v){
	float ct = cosf(angle);
	float st = sinf(angle);

	float xx = v.x * v.x;
	float yy = v.y * v.y;
	float zz = v.z * v.z;
	float xy = v.x * v.y;
	float xz = v.x * v.z;
	float yz = v.y * v.z;

	Mat4 m;
	m.a00 = xx + ct*(1-xx);
	m.a01 = xy + ct*(-xy) + st*-v.z;
	m.a02 = xz + ct*(-xz) + st*v.y;
	m.a03 = 0;

	m.a10 = xy + ct*(-xy) + st*v.z;
	m.a11 = yy + ct*(1-yy);
	m.a12 = yz + ct*(-yz) + st*-v.x;
	m.a13 = 0;

	m.a20 = xz + ct*(-xz) + st*-v.y;
	m.a21 = yz + ct*(-yz) + st*v.x;
	m.a22 = zz + ct*(1-zz);
	m.a23 = 0;

	m.a30 = 0;
	m.a31 = 0;
	m.a32 = 0;
	m.a33 = 1;
	//*this = *this * m;
	*this = m;
}



vec3 Mat4::DoTransform(const vec3& v){
	vec3 u;
	u.x = a00 * v.x + a01 * v.y + a02 * v.z + a03;
	u.y = a10 * v.x + a11 * v.y + a12 * v.z + a13;
	u.z = a20 * v.x + a21 * v.y + a22 * v.z + a23;
	return u;
}

void MyTask(vec3 a,vec3 b,vec3 c,	float NewAngle){
	vec3 dir1 = normalize(vsub(b,a));	
	vec3 dir2 = normalize(vsub(c,a));
	
	float RESULT_ANGLE = acos(dot(dir1,dir2)); // task 1 done.
	
	vec3 planeNorm = cross(dir1,dir2);
	
	Mat4 rotMatrix;
	rotMatrix.CreateRotate(NewAngle-RESULT_ANGLE, planeNorm);
	
	
	vec3 RESULT_C = rotMatrix.DoTransform(c); // task 2 done.
	
	
}

Thanks for your great help.

This sample code can update the vertex C.

I have tested it and it can solve most of the problem.
However, I find that it may not works properly on some cases.
For example,
case 1: if I set angle to 60 degree, it may return a new vertex that form the angle 120 degree. I think it cannot be solved because sin 60 degree is equal to sin 120 degree.

case 2: if my orginal vertice are A(0.5 0.5 -1), B(3.5 0.5 -1), F(3.5 0.5 -5). Angle of FBA is 90 degree. But if I set the angle to 50 degree, it fails to change the vertice A. Is there any method to handle this case?

Once again, thanks for your great help.

The sin(60) = sin(120) is no problem, as there’s also cos() used in the code above. Still, the “RESULT_ANGLE” is always 0…180 degrees (0…Pi) . Can’t find 180…360 angles with a simple dot-product.
In 3D space, one of the ways to find if you should use (2*Pi-result_angle) instead of result_angle is by using 2-3 cross() on different normalized vectors like the dir1 and dir2, and check their signs. (if they flip direction).
Another way is to construct a plane, that goes through vertices “b”, “c” and “d”, where:
d = b + planeNorm;
Then check if “a” is behind or in front of this new plane. (check the sign of distance-of-point-to-plane) . If it’s negative, then:

RESULT_ANGLE = 2*math_pi - RESULT_ANGLE;


Once the true 0…2*Pi “Result_angle” is known, try this for reconstructing C at a new angle:


Mat4 rotMatrix;
rotMatrix.CreateRotate(NewAngle, planeNorm);
float lenCA = distance(c,a);
vec3 RESULT_C = rotMatrix.DoTransform(-dir1)*lenCA  + a;

Basically it reconstructs a normal vector, at which “result_angle=0”, rotates that vector by NewAngle, scales it by the length of the [c,a] edge, and offsets by a.

Thanks for your help very much.