/* Find angle between two vectors.
For two vectors p, q, the angle A between them is given by
p.q / (|p| |q|) = cos A .
If the angle is small, an expression in sin A would be preferred.
Set r = q - p. Then
p.q = p.p + p.r ,
|p|^2 = p.p ,
|q|^2 = p.p + 2 p.r + r.r ,
p.p^2 + 2 p.p p.r + p.r^2
cos^2 A = ----------------------------
p.p (p.p + 2 p.r + r.r)
p.p + 2 p.r + p.r^2 / p.p
= --------------------------- ,
p.p + 2 p.r + r.r
sin^2 A = 1 - cos^2 A
r.r - p.r^2 / p.p
= --------------------
p.p + 2 p.r + r.r
= (r.r - p.r^2 / p.p) / q.q .
*/
#if __STDC__
double sqrt (double);
double acos (double);
double asin (double);
double atan (double);
#else
double sqrt(), acos(), asin(), atan();
#endif
/* extern double PIO2, PI; */
double arcdot(p,q)
double p[], q[];
{
double pp, pr, qq, rr, rt, pt, qt, pq;
int i;
pq = 0.0;
qq = 0.0;
pp = 0.0;
pr = 0.0;
rr = 0.0;
for (i=0; i<3; i++)
{
pt = p[i];
qt = q[i];
pq += pt * qt;
qq += qt * qt;
pp += pt * pt;
rt = qt - pt;
pr += pt * rt;
rr += rt * rt;
}
if (rr == 0.0 || pp == 0.0 || qq == 0.0)
return 0.0;
/*
if (pq == 0.0)
return PIO2;
if (pr == 0.0)
return (atan(sqrt(rr/pp)));
*/
rt = (rr - (pr * pr) / pp) / qq;
#if DEBUG
pt = pq / sqrt(pp*qq);
pt = acos(pt);
qt = sqrt(rt);
qt = asin(qt);
if( pq < 0.0)
qt = PI - qt;
printf("%.16e %.16e\n", qt, pt);
#endif
if (rt <= 0.25 && pq > 0.0)
{
rt = sqrt(rt);
qt = asin(rt);
}
else
{
pt = pq / sqrt(pp*qq);
qt = acos(pt);
}
return qt;
}
#if DEBUG
main()
{
double p[3], q[3], a;
int i, j;
for(j=0; j<10; j++)
{
for (i=0; i<3; i++)
{
drand(&p[i]);
drand(&q[i]);
p[i] -= 1.5;
q[i] -= 1.5;
}
a = arcdot(p,q);
}
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1