xref: /plan9-contrib/sys/src/libgeometry/arith3.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #include <u.h>
2*219b2ee8SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier #include <libg.h>
4*219b2ee8SDavid du Colombier #include <geometry.h>
5*219b2ee8SDavid du Colombier /*
6*219b2ee8SDavid du Colombier  * Routines whose names end in 3 work on points in Affine 3-space.
7*219b2ee8SDavid du Colombier  * They ignore w in all arguments and produce w=1 in all results.
8*219b2ee8SDavid du Colombier  * Routines whose names end in 4 work on points in Projective 3-space.
9*219b2ee8SDavid du Colombier  */
10*219b2ee8SDavid du Colombier Point3 add3(Point3 a, Point3 b){
11*219b2ee8SDavid du Colombier 	return (Point3){a.x+b.x, a.y+b.y, a.z+b.z, 1.};
12*219b2ee8SDavid du Colombier }
13*219b2ee8SDavid du Colombier Point3 sub3(Point3 a, Point3 b){
14*219b2ee8SDavid du Colombier 	return (Point3){a.x-b.x, a.y-b.y, a.z-b.z, 1.};
15*219b2ee8SDavid du Colombier }
16*219b2ee8SDavid du Colombier Point3 neg3(Point3 a){
17*219b2ee8SDavid du Colombier 	return (Point3){-a.x, -a.y, -a.z, 1.};
18*219b2ee8SDavid du Colombier }
19*219b2ee8SDavid du Colombier Point3 div3(Point3 a, double b){
20*219b2ee8SDavid du Colombier 	return (Point3){a.x/b, a.y/b, a.z/b, 1.};
21*219b2ee8SDavid du Colombier }
22*219b2ee8SDavid du Colombier Point3 mul3(Point3 a, double b){
23*219b2ee8SDavid du Colombier 	return (Point3){a.x*b, a.y*b, a.z*b, 1.};
24*219b2ee8SDavid du Colombier }
25*219b2ee8SDavid du Colombier int eqpt3(Point3 p, Point3 q){
26*219b2ee8SDavid du Colombier 	return p.x==q.x && p.y==q.y && p.z==q.z;
27*219b2ee8SDavid du Colombier }
28*219b2ee8SDavid du Colombier /*
29*219b2ee8SDavid du Colombier  * Are these points closer than eps, in a relative sense
30*219b2ee8SDavid du Colombier  */
31*219b2ee8SDavid du Colombier int closept3(Point3 p, Point3 q, double eps){
32*219b2ee8SDavid du Colombier 	return 2.*dist3(p, q)<eps*(len3(p)+len3(q));
33*219b2ee8SDavid du Colombier }
34*219b2ee8SDavid du Colombier double dot3(Point3 p, Point3 q){
35*219b2ee8SDavid du Colombier 	return p.x*q.x+p.y*q.y+p.z*q.z;
36*219b2ee8SDavid du Colombier }
37*219b2ee8SDavid du Colombier Point3 cross3(Point3 p, Point3 q){
38*219b2ee8SDavid du Colombier 	return (Point3){p.y*q.z-p.z*q.y, p.z*q.x-p.x*q.z, p.x*q.y-p.y*q.x, 1.};
39*219b2ee8SDavid du Colombier }
40*219b2ee8SDavid du Colombier double len3(Point3 p){
41*219b2ee8SDavid du Colombier 	return sqrt(p.x*p.x+p.y*p.y+p.z*p.z);
42*219b2ee8SDavid du Colombier }
43*219b2ee8SDavid du Colombier double dist3(Point3 p, Point3 q){
44*219b2ee8SDavid du Colombier 	p.x-=q.x;
45*219b2ee8SDavid du Colombier 	p.y-=q.y;
46*219b2ee8SDavid du Colombier 	p.z-=q.z;
47*219b2ee8SDavid du Colombier 	return sqrt(p.x*p.x+p.y*p.y+p.z*p.z);
48*219b2ee8SDavid du Colombier }
49*219b2ee8SDavid du Colombier Point3 unit3(Point3 p){
50*219b2ee8SDavid du Colombier 	double len=sqrt(p.x*p.x+p.y*p.y+p.z*p.z);
51*219b2ee8SDavid du Colombier 	return (Point3){p.x/len, p.y/len, p.z/len, 1.};
52*219b2ee8SDavid du Colombier }
53*219b2ee8SDavid du Colombier Point3 midpt3(Point3 p, Point3 q){
54*219b2ee8SDavid du Colombier 	return (Point3){.5*(p.x+q.x), .5*(p.y+q.y), .5*(p.z+q.z), 1.};
55*219b2ee8SDavid du Colombier }
56*219b2ee8SDavid du Colombier Point3 lerp3(Point3 p, Point3 q, double alpha){
57*219b2ee8SDavid du Colombier 	return (Point3){p.x+(q.x-p.x)*alpha, p.y+(q.y-p.y)*alpha, p.z+(q.z-p.z)*alpha, 1.};
58*219b2ee8SDavid du Colombier }
59*219b2ee8SDavid du Colombier /*
60*219b2ee8SDavid du Colombier  * Reflect point p in the line joining p0 and p1
61*219b2ee8SDavid du Colombier  */
62*219b2ee8SDavid du Colombier Point3 reflect3(Point3 p, Point3 p0, Point3 p1){
63*219b2ee8SDavid du Colombier 	Point3 a, b;
64*219b2ee8SDavid du Colombier 	a=sub3(p, p0);
65*219b2ee8SDavid du Colombier 	b=sub3(p1, p0);
66*219b2ee8SDavid du Colombier 	return add3(a, mul3(b, 2*dot3(a, b)/dot3(b, b)));
67*219b2ee8SDavid du Colombier }
68*219b2ee8SDavid du Colombier /*
69*219b2ee8SDavid du Colombier  * Return the nearest point on segment [p0,p1] to point testp
70*219b2ee8SDavid du Colombier  */
71*219b2ee8SDavid du Colombier Point3 nearseg3(Point3 p0, Point3 p1, Point3 testp){
72*219b2ee8SDavid du Colombier 	double num, den;
73*219b2ee8SDavid du Colombier 	Point3 q, r;
74*219b2ee8SDavid du Colombier 	q=sub3(p1, p0);
75*219b2ee8SDavid du Colombier 	r=sub3(testp, p0);
76*219b2ee8SDavid du Colombier 	num=dot3(q, r);;
77*219b2ee8SDavid du Colombier 	if(num<=0) return p0;
78*219b2ee8SDavid du Colombier 	den=dot3(q, q);
79*219b2ee8SDavid du Colombier 	if(num>=den) return p1;
80*219b2ee8SDavid du Colombier 	return add3(p0, mul3(q, num/den));
81*219b2ee8SDavid du Colombier }
82*219b2ee8SDavid du Colombier /*
83*219b2ee8SDavid du Colombier  * distance from point p to segment [p0,p1]
84*219b2ee8SDavid du Colombier  */
85*219b2ee8SDavid du Colombier #define	SMALL	1e-8	/* what should this value be? */
86*219b2ee8SDavid du Colombier double pldist3(Point3 p, Point3 p0, Point3 p1){
87*219b2ee8SDavid du Colombier 	Point3 d, e;
88*219b2ee8SDavid du Colombier 	double dd, de, dsq;
89*219b2ee8SDavid du Colombier 	d=sub3(p1, p0);
90*219b2ee8SDavid du Colombier 	e=sub3(p, p0);
91*219b2ee8SDavid du Colombier 	dd=dot3(d, d);
92*219b2ee8SDavid du Colombier 	de=dot3(d, e);
93*219b2ee8SDavid du Colombier 	if(dd<SMALL*SMALL) return len3(e);
94*219b2ee8SDavid du Colombier 	dsq=dot3(e, e)-de*de/dd;
95*219b2ee8SDavid du Colombier 	if(dsq<SMALL*SMALL) return 0;
96*219b2ee8SDavid du Colombier 	return sqrt(dsq);
97*219b2ee8SDavid du Colombier }
98*219b2ee8SDavid du Colombier /*
99*219b2ee8SDavid du Colombier  * vdiv3(a, b) is the magnitude of the projection of a onto b
100*219b2ee8SDavid du Colombier  * measured in units of the length of b.
101*219b2ee8SDavid du Colombier  * vrem3(a, b) is the component of a perpendicular to b.
102*219b2ee8SDavid du Colombier  */
103*219b2ee8SDavid du Colombier double vdiv3(Point3 a, Point3 b){
104*219b2ee8SDavid du Colombier 	return (a.x*b.x+a.y*b.y+a.z*b.z)/(b.x*b.x+b.y*b.y+b.z*b.z);
105*219b2ee8SDavid du Colombier }
106*219b2ee8SDavid du Colombier Point3 vrem3(Point3 a, Point3 b){
107*219b2ee8SDavid du Colombier 	double quo=(a.x*b.x+a.y*b.y+a.z*b.z)/(b.x*b.x+b.y*b.y+b.z*b.z);
108*219b2ee8SDavid du Colombier 	return (Point3){a.x-b.x*quo, a.y-b.y*quo, a.z-b.z*quo, 1.};
109*219b2ee8SDavid du Colombier }
110*219b2ee8SDavid du Colombier /*
111*219b2ee8SDavid du Colombier  * Compute face (plane) with given normal, containing a given point
112*219b2ee8SDavid du Colombier  */
113*219b2ee8SDavid du Colombier Point3 pn2f3(Point3 p, Point3 n){
114*219b2ee8SDavid du Colombier 	return (Point3){n.x, n.y, n.z, -dot3(p, n)};
115*219b2ee8SDavid du Colombier }
116*219b2ee8SDavid du Colombier /*
117*219b2ee8SDavid du Colombier  * Compute face containing three points
118*219b2ee8SDavid du Colombier  */
119*219b2ee8SDavid du Colombier Point3 ppp2f3(Point3 p0, Point3 p1, Point3 p2){
120*219b2ee8SDavid du Colombier 	Point3 p01, p02;
121*219b2ee8SDavid du Colombier 	p01=sub3(p1, p0);
122*219b2ee8SDavid du Colombier 	p02=sub3(p2, p0);
123*219b2ee8SDavid du Colombier 	return pn2f3(p0, cross3(p01, p02));
124*219b2ee8SDavid du Colombier }
125*219b2ee8SDavid du Colombier /*
126*219b2ee8SDavid du Colombier  * Compute point common to three faces.
127*219b2ee8SDavid du Colombier  * Cramer's rule, yuk.
128*219b2ee8SDavid du Colombier  */
129*219b2ee8SDavid du Colombier Point3 fff2p3(Point3 f0, Point3 f1, Point3 f2){
130*219b2ee8SDavid du Colombier 	double det, x, y, z;
131*219b2ee8SDavid du Colombier 	det=dot3(f0, cross3(f1, f2));
132*219b2ee8SDavid du Colombier 	if(fabs(det)<SMALL) return (Point3){0,0,0,0};	/* parallel planes, bogus answer */
133*219b2ee8SDavid du Colombier 	x=f0.w*(f2.y*f1.z-f1.y*f2.z)+f1.w*(f0.y*f2.z-f2.y*f0.z)+f2.w*(f1.y*f0.z-f0.y*f1.z);
134*219b2ee8SDavid du Colombier 	y=f0.w*(f2.z*f1.x-f1.z*f2.x)+f1.w*(f0.z*f2.x-f2.z*f0.x)+f2.w*(f1.z*f0.x-f0.z*f1.x);
135*219b2ee8SDavid du Colombier 	z=f0.w*(f2.x*f1.y-f1.x*f2.y)+f1.w*(f0.x*f2.y-f2.x*f0.y)+f2.w*(f1.x*f0.y-f0.x*f1.y);
136*219b2ee8SDavid du Colombier 	return (Point3){x/det, y/det, z/det, 1.};
137*219b2ee8SDavid du Colombier }
138*219b2ee8SDavid du Colombier /*
139*219b2ee8SDavid du Colombier  * pdiv4 does perspective division to convert a projective point to affine coordinates.
140*219b2ee8SDavid du Colombier  */
141*219b2ee8SDavid du Colombier Point3 pdiv4(Point3 a){
142*219b2ee8SDavid du Colombier 	if(a.w==0) return a;
143*219b2ee8SDavid du Colombier 	return (Point3){a.x/a.w, a.y/a.w, a.z/a.w, 1.};
144*219b2ee8SDavid du Colombier }
145*219b2ee8SDavid du Colombier Point3 add4(Point3 a, Point3 b){
146*219b2ee8SDavid du Colombier 	return (Point3){a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w};
147*219b2ee8SDavid du Colombier }
148*219b2ee8SDavid du Colombier Point3 sub4(Point3 a, Point3 b){
149*219b2ee8SDavid du Colombier 	return (Point3){a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w};
150*219b2ee8SDavid du Colombier }
151