I am trying to write a code in Matlab that will calculate all three
interior angles of a triangle that is made by three random points in a
2D plane. I have tried using the 'acos' function as well as the
'atan2' function yet i cant seem to get the desired results. The total
of the calculated angles is no where near 180 degrees (most of them
end up greater than 300 degrees).
For example if i have these three points:
P1=[5,15]
P2=[6,12]
P3=[7,9]
what would be the best way to calculate the angles in the triangle
formed by these points?
Thanks for any help.
What have you tried with the acos function?
For example, this?
http://en.wikipedia.org/wiki/Law_of_cosines
John
Roger Stafford
What i tried to do was find the angle between two lines as it was
mentioned here:
http://groups.google.com/group/comp.soft-sys.matlab/browse_thread/thread/894e0a087ae36d42/8d265047cfbcb7bf?lnk=gst&q=angles+between+two+lines#8d265047cfbcb7bf
I did it three times using the different points so as to get the three
angles but it seems I'm making a mistake somewhere.
What i did is as follows though I'm not sure now that i did it the
right way:
v1=[P2(1,1)-P1(1,1),P2(1,2)-
P1(1,2)];
v2=[P3(1,1)-P1(1,1),P3(1,2)-
P1(1,2)];
v3=[P3(1,1)-P2(1,1),P3(1,2)-P1(1,2)];
a1=acosd(dot(v1,v2)/
((sqrt(v1(1,1)^2+v1(1,2)^2))*(sqrt(v2(1,1)^2+v2(1,2)^2))));
a2=acosd(dot(v1,v3)/
((sqrt(v1(1,1)^2+v1(1,2)^2))*(sqrt(v3(1,1)^2+v3(1,2)^2))));
a3=acosd(dot(v2,v3)/
((sqrt(v2(1,1)^2+v2(1,2)^2))*(sqrt(v3(1,1)^2+v3(1,2)^2))));
I'm pretty sure I'm making a mistake somewhere (or else i would be
getting the right answers) but i just cant point out where it is.
I also tried using the atan2 function that was mentioned my Roger
Stafford in that thread but i was getting same results as with the
acos function.
thanks for the help
Hisham
Ok. You tried something and even showed what
you tried. Its more than most seem willing to
do. 8-(
The problem with the angle between two lines
from atan2 is it depends on the way you present
them. Will you get the desired angle, or 180
minus that angle? Its also why I suggested
using the law of cosines, since that law will not
suffer from order. Admittedly, law of cosines
might sometimes suffer from subtractive
cancellation issues, but that is not likely to be
a big issue here.
First, I'll point out that your coding style will
take a step forward if you start using the ability
of matlab to work with vectors and arrays.
Instead of writing this:
v1=[P2(1,1)-P1(1,1),P2(1,2)-P1(1,2)];
write it as
v1 = p2 - p1;
The second is much clearer. Easier to read,
write, and debug, and it will probably even
run faster. Its certainly a better choice when
you begin to use larger vectors and arrays.
Next, an easy way to compute the length of
a vector (the length of an edge here) is to use
norm. Thus the length of the side connecting
p1 and p2 is just norm(p1-p2).
p1=[5,15];
p2=[6,12];
p3=[7,9];
s12 = norm(p2 - p1);
s13 = norm(p3 - p1);
s23 = norm(p3 - p1);
Norm can (sometimes) be more accurate than
the simple sum of squares of a difference.
So now law of cosines yields
a12 = acosd((s13^2 + s23^2 - s12^2)/(2*s13*s23))
a13 = acosd((s12^2 + s23^2 - s13^2)/(2*s12*s23))
a23 = acosd((s12^2 + s13^2 - s23^2)/(2*s12*s13))
a12 =
28.955
a13 =
75.522
a23 =
75.522
a12 + a13 + a23
ans =
180
John
> Hint: There is a formula that gives the tangent of half an interior angle in
> ...........
Since you have the coordinates of the points, I really should have advised
you to use the following method, which does not require computing the
lengths of the triangle's three sides. It uses matlab's 'atan2' function. If P1 =
[x1,y1], P2 = [x2,y2], and P3 = [x3,y3], then the interior angle, A1, at P1 is
given by
x21 = x2-x1; y21 = y2-y1;
x31 = x3-x1; y31 = y3-y1;
A1 = atan2(abs(x21*y31-y21*x31),x21*x31+y21*y31);
The angle will be in radians. The formulas for the other two angles are
analogous.
The above is the two-dimensional version of the more general three-
dimensional case with P1 = [x1,y1,z1], P2 = [x2,y2,z2], P3 = [x3,y3,z3]:
P21 = P2-P1; P31 = P3-P1;
A1 = atan2(norm(cross(P21,P31),dot(P21,P31));
This holds because the norm of the cross product is the product of the two
sides times the sine of the angle between, while the dot product is the
product of the two sides times the cosine of this angle, and therefore they
constitute appropriate arguments for atan2.
Roger Stafford
x21 = x2-x1; y21 = y2-y1;
x31 = x3-x1; y31 = y3-y1;
A1 = atan2(abs(x21*y31-y21*x31),x21*x31+y21*y31);
you are assured of getting a correct answer for the interior angle, as well as
avoiding the accuracy problems in acos that occur with angles near 0 or pi.
Roger Stafford
I also tried the 'atan2' function as mentioned, though I'm not sure it
worked. As a test, i applied it to the three points:
p1=[5,15];
p2=[6,12];
p3=[7,9];
using the following code:
x1=5;
x2=6;
x3=7;
y1=15;
y2=12;
y3=9;
x21 = x2-x1; y21 = y2-y1;
x31 = x3-x1; y31 = y3-y1;
A1 = atan2(abs(x21*y31-y21*x31),x21*x31+y21*y31);
this resulted in
A1=
0
Using the cosine code as stated by John, from what i understand, it
should be near about 75.522 degrees or 1.3181 rad.
Although the code is working with the cosine function i would still
like to understand how the 'atan2' function can be applied here.
Once again thank you both for the great help you have provided. Its
greatly appreciated.
Hisham
John has an error in his computations where he writes:
s12 = norm(p2 - p1);
s13 = norm(p3 - p1);
s23 = norm(p3 - p1);
and this leads to the erroneous results. That last line should read
s23 = norm(p3 - p2);
I have rewritten the formula I previously gave you to be in a vector form and
given it for all three interior angles. Let the three triangle vertices be P1, P2,
and P3, where each is a column vector of x and y coordinates. Let the three
interior angles at these points be denoted by A1, A2, and A3, respectively.
Then
A1 = atan2(abs(det([P2-P1,P3-P1])),dot(P2-P1,P3-P1));
A2 = atan2(abs(det([P3-P2,P1-P2])),dot(P3-P2,P1-P2));
A3 = atan2(abs(det([P1-P3,P2-P3])),dot(P1-P3,P2-P3));
give these three angles in radians. Multiply them by 180/pi to get degrees.
If your vertices are given as row vectors, then change these formulas to:
A1 = atan2(abs(det([P2-P1;P3-P1])),dot(P2-P1,P3-P1));
A2 = atan2(abs(det([P3-P2;P1-P2])),dot(P3-P2,P1-P2));
A3 = atan2(abs(det([P1-P3;P2-P3])),dot(P1-P3,P2-P3));
so as to retain a square array in the determinant arguments.
I still contend that this formula with atan2 is preferable to the use of acos
because this latter function begins to suffer a potential loss of accuracy when
the angle is near either 0 or pi (180 degrees), (as in the case of your
example.) That is because the slope of the acos(x) curve becomes infinite at
x = -1 and at x = +1. Look at a plot of acos(x) over the range -1 <= x <=
+1 to see this demonstrated.
Note that if you are in three dimensions with P1, P2, and P3 being 3 by 1
column vectors in x, y, and z coordinates, then the formulas become:
A1 = atan2(norm(cross(P2-P1,P3-P1)),dot(P2-P1,P3-P1));
A2 = atan2(norm(cross(P3-P2,P1-P2)),dot(P3-P2,P1-P2));
A3 = atan2(norm(cross(P1-P3,P2-P3)),dot(P1-P3,P2-P3));
Roger Stafford