/* 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