1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3*7dd7cddfSDavid du Colombier #include <draw.h>
4219b2ee8SDavid du Colombier #include <geometry.h>
5219b2ee8SDavid du Colombier /*
6219b2ee8SDavid du Colombier * Routines whose names end in 3 work on points in Affine 3-space.
7219b2ee8SDavid du Colombier * They ignore w in all arguments and produce w=1 in all results.
8219b2ee8SDavid du Colombier * Routines whose names end in 4 work on points in Projective 3-space.
9219b2ee8SDavid du Colombier */
add3(Point3 a,Point3 b)10219b2ee8SDavid du Colombier Point3 add3(Point3 a, Point3 b){
11*7dd7cddfSDavid du Colombier a.x+=b.x;
12*7dd7cddfSDavid du Colombier a.y+=b.y;
13*7dd7cddfSDavid du Colombier a.z+=b.z;
14*7dd7cddfSDavid du Colombier a.w=1.;
15*7dd7cddfSDavid du Colombier return a;
16219b2ee8SDavid du Colombier }
sub3(Point3 a,Point3 b)17219b2ee8SDavid du Colombier Point3 sub3(Point3 a, Point3 b){
18*7dd7cddfSDavid du Colombier a.x-=b.x;
19*7dd7cddfSDavid du Colombier a.y-=b.y;
20*7dd7cddfSDavid du Colombier a.z-=b.z;
21*7dd7cddfSDavid du Colombier a.w=1.;
22*7dd7cddfSDavid du Colombier return a;
23219b2ee8SDavid du Colombier }
neg3(Point3 a)24219b2ee8SDavid du Colombier Point3 neg3(Point3 a){
25*7dd7cddfSDavid du Colombier a.x=-a.x;
26*7dd7cddfSDavid du Colombier a.y=-a.y;
27*7dd7cddfSDavid du Colombier a.z=-a.z;
28*7dd7cddfSDavid du Colombier a.w=1.;
29*7dd7cddfSDavid du Colombier return a;
30219b2ee8SDavid du Colombier }
div3(Point3 a,double b)31219b2ee8SDavid du Colombier Point3 div3(Point3 a, double b){
32*7dd7cddfSDavid du Colombier a.x/=b;
33*7dd7cddfSDavid du Colombier a.y/=b;
34*7dd7cddfSDavid du Colombier a.z/=b;
35*7dd7cddfSDavid du Colombier a.w=1.;
36*7dd7cddfSDavid du Colombier return a;
37219b2ee8SDavid du Colombier }
mul3(Point3 a,double b)38219b2ee8SDavid du Colombier Point3 mul3(Point3 a, double b){
39*7dd7cddfSDavid du Colombier a.x*=b;
40*7dd7cddfSDavid du Colombier a.y*=b;
41*7dd7cddfSDavid du Colombier a.z*=b;
42*7dd7cddfSDavid du Colombier a.w=1.;
43*7dd7cddfSDavid du Colombier return a;
44219b2ee8SDavid du Colombier }
eqpt3(Point3 p,Point3 q)45219b2ee8SDavid du Colombier int eqpt3(Point3 p, Point3 q){
46219b2ee8SDavid du Colombier return p.x==q.x && p.y==q.y && p.z==q.z;
47219b2ee8SDavid du Colombier }
48219b2ee8SDavid du Colombier /*
49219b2ee8SDavid du Colombier * Are these points closer than eps, in a relative sense
50219b2ee8SDavid du Colombier */
closept3(Point3 p,Point3 q,double eps)51219b2ee8SDavid du Colombier int closept3(Point3 p, Point3 q, double eps){
52219b2ee8SDavid du Colombier return 2.*dist3(p, q)<eps*(len3(p)+len3(q));
53219b2ee8SDavid du Colombier }
dot3(Point3 p,Point3 q)54219b2ee8SDavid du Colombier double dot3(Point3 p, Point3 q){
55219b2ee8SDavid du Colombier return p.x*q.x+p.y*q.y+p.z*q.z;
56219b2ee8SDavid du Colombier }
cross3(Point3 p,Point3 q)57219b2ee8SDavid du Colombier Point3 cross3(Point3 p, Point3 q){
58*7dd7cddfSDavid du Colombier Point3 r;
59*7dd7cddfSDavid du Colombier r.x=p.y*q.z-p.z*q.y;
60*7dd7cddfSDavid du Colombier r.y=p.z*q.x-p.x*q.z;
61*7dd7cddfSDavid du Colombier r.z=p.x*q.y-p.y*q.x;
62*7dd7cddfSDavid du Colombier r.w=1.;
63*7dd7cddfSDavid du Colombier return r;
64219b2ee8SDavid du Colombier }
len3(Point3 p)65219b2ee8SDavid du Colombier double len3(Point3 p){
66219b2ee8SDavid du Colombier return sqrt(p.x*p.x+p.y*p.y+p.z*p.z);
67219b2ee8SDavid du Colombier }
dist3(Point3 p,Point3 q)68219b2ee8SDavid du Colombier double dist3(Point3 p, Point3 q){
69219b2ee8SDavid du Colombier p.x-=q.x;
70219b2ee8SDavid du Colombier p.y-=q.y;
71219b2ee8SDavid du Colombier p.z-=q.z;
72219b2ee8SDavid du Colombier return sqrt(p.x*p.x+p.y*p.y+p.z*p.z);
73219b2ee8SDavid du Colombier }
unit3(Point3 p)74219b2ee8SDavid du Colombier Point3 unit3(Point3 p){
75219b2ee8SDavid du Colombier double len=sqrt(p.x*p.x+p.y*p.y+p.z*p.z);
76*7dd7cddfSDavid du Colombier p.x/=len;
77*7dd7cddfSDavid du Colombier p.y/=len;
78*7dd7cddfSDavid du Colombier p.z/=len;
79*7dd7cddfSDavid du Colombier p.w=1.;
80*7dd7cddfSDavid du Colombier return p;
81219b2ee8SDavid du Colombier }
midpt3(Point3 p,Point3 q)82219b2ee8SDavid du Colombier Point3 midpt3(Point3 p, Point3 q){
83*7dd7cddfSDavid du Colombier p.x=.5*(p.x+q.x);
84*7dd7cddfSDavid du Colombier p.y=.5*(p.y+q.y);
85*7dd7cddfSDavid du Colombier p.z=.5*(p.z+q.z);
86*7dd7cddfSDavid du Colombier p.w=1.;
87*7dd7cddfSDavid du Colombier return p;
88219b2ee8SDavid du Colombier }
lerp3(Point3 p,Point3 q,double alpha)89219b2ee8SDavid du Colombier Point3 lerp3(Point3 p, Point3 q, double alpha){
90*7dd7cddfSDavid du Colombier p.x+=(q.x-p.x)*alpha;
91*7dd7cddfSDavid du Colombier p.y+=(q.y-p.y)*alpha;
92*7dd7cddfSDavid du Colombier p.z+=(q.z-p.z)*alpha;
93*7dd7cddfSDavid du Colombier p.w=1.;
94*7dd7cddfSDavid du Colombier return p;
95219b2ee8SDavid du Colombier }
96219b2ee8SDavid du Colombier /*
97219b2ee8SDavid du Colombier * Reflect point p in the line joining p0 and p1
98219b2ee8SDavid du Colombier */
reflect3(Point3 p,Point3 p0,Point3 p1)99219b2ee8SDavid du Colombier Point3 reflect3(Point3 p, Point3 p0, Point3 p1){
100219b2ee8SDavid du Colombier Point3 a, b;
101219b2ee8SDavid du Colombier a=sub3(p, p0);
102219b2ee8SDavid du Colombier b=sub3(p1, p0);
103219b2ee8SDavid du Colombier return add3(a, mul3(b, 2*dot3(a, b)/dot3(b, b)));
104219b2ee8SDavid du Colombier }
105219b2ee8SDavid du Colombier /*
106219b2ee8SDavid du Colombier * Return the nearest point on segment [p0,p1] to point testp
107219b2ee8SDavid du Colombier */
nearseg3(Point3 p0,Point3 p1,Point3 testp)108219b2ee8SDavid du Colombier Point3 nearseg3(Point3 p0, Point3 p1, Point3 testp){
109219b2ee8SDavid du Colombier double num, den;
110219b2ee8SDavid du Colombier Point3 q, r;
111219b2ee8SDavid du Colombier q=sub3(p1, p0);
112219b2ee8SDavid du Colombier r=sub3(testp, p0);
113219b2ee8SDavid du Colombier num=dot3(q, r);;
114219b2ee8SDavid du Colombier if(num<=0) return p0;
115219b2ee8SDavid du Colombier den=dot3(q, q);
116219b2ee8SDavid du Colombier if(num>=den) return p1;
117219b2ee8SDavid du Colombier return add3(p0, mul3(q, num/den));
118219b2ee8SDavid du Colombier }
119219b2ee8SDavid du Colombier /*
120219b2ee8SDavid du Colombier * distance from point p to segment [p0,p1]
121219b2ee8SDavid du Colombier */
122219b2ee8SDavid du Colombier #define SMALL 1e-8 /* what should this value be? */
pldist3(Point3 p,Point3 p0,Point3 p1)123219b2ee8SDavid du Colombier double pldist3(Point3 p, Point3 p0, Point3 p1){
124219b2ee8SDavid du Colombier Point3 d, e;
125219b2ee8SDavid du Colombier double dd, de, dsq;
126219b2ee8SDavid du Colombier d=sub3(p1, p0);
127219b2ee8SDavid du Colombier e=sub3(p, p0);
128219b2ee8SDavid du Colombier dd=dot3(d, d);
129219b2ee8SDavid du Colombier de=dot3(d, e);
130219b2ee8SDavid du Colombier if(dd<SMALL*SMALL) return len3(e);
131219b2ee8SDavid du Colombier dsq=dot3(e, e)-de*de/dd;
132219b2ee8SDavid du Colombier if(dsq<SMALL*SMALL) return 0;
133219b2ee8SDavid du Colombier return sqrt(dsq);
134219b2ee8SDavid du Colombier }
135219b2ee8SDavid du Colombier /*
136219b2ee8SDavid du Colombier * vdiv3(a, b) is the magnitude of the projection of a onto b
137219b2ee8SDavid du Colombier * measured in units of the length of b.
138219b2ee8SDavid du Colombier * vrem3(a, b) is the component of a perpendicular to b.
139219b2ee8SDavid du Colombier */
vdiv3(Point3 a,Point3 b)140219b2ee8SDavid du Colombier double vdiv3(Point3 a, Point3 b){
141219b2ee8SDavid 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);
142219b2ee8SDavid du Colombier }
vrem3(Point3 a,Point3 b)143219b2ee8SDavid du Colombier Point3 vrem3(Point3 a, Point3 b){
144219b2ee8SDavid 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);
145*7dd7cddfSDavid du Colombier a.x-=b.x*quo;
146*7dd7cddfSDavid du Colombier a.y-=b.y*quo;
147*7dd7cddfSDavid du Colombier a.z-=b.z*quo;
148*7dd7cddfSDavid du Colombier a.w=1.;
149*7dd7cddfSDavid du Colombier return a;
150219b2ee8SDavid du Colombier }
151219b2ee8SDavid du Colombier /*
152219b2ee8SDavid du Colombier * Compute face (plane) with given normal, containing a given point
153219b2ee8SDavid du Colombier */
pn2f3(Point3 p,Point3 n)154219b2ee8SDavid du Colombier Point3 pn2f3(Point3 p, Point3 n){
155*7dd7cddfSDavid du Colombier n.w=-dot3(p, n);
156*7dd7cddfSDavid du Colombier return n;
157219b2ee8SDavid du Colombier }
158219b2ee8SDavid du Colombier /*
159219b2ee8SDavid du Colombier * Compute face containing three points
160219b2ee8SDavid du Colombier */
ppp2f3(Point3 p0,Point3 p1,Point3 p2)161219b2ee8SDavid du Colombier Point3 ppp2f3(Point3 p0, Point3 p1, Point3 p2){
162219b2ee8SDavid du Colombier Point3 p01, p02;
163219b2ee8SDavid du Colombier p01=sub3(p1, p0);
164219b2ee8SDavid du Colombier p02=sub3(p2, p0);
165219b2ee8SDavid du Colombier return pn2f3(p0, cross3(p01, p02));
166219b2ee8SDavid du Colombier }
167219b2ee8SDavid du Colombier /*
168219b2ee8SDavid du Colombier * Compute point common to three faces.
169219b2ee8SDavid du Colombier * Cramer's rule, yuk.
170219b2ee8SDavid du Colombier */
fff2p3(Point3 f0,Point3 f1,Point3 f2)171219b2ee8SDavid du Colombier Point3 fff2p3(Point3 f0, Point3 f1, Point3 f2){
172*7dd7cddfSDavid du Colombier double det;
173*7dd7cddfSDavid du Colombier Point3 p;
174219b2ee8SDavid du Colombier det=dot3(f0, cross3(f1, f2));
175*7dd7cddfSDavid du Colombier if(fabs(det)<SMALL){ /* parallel planes, bogus answer */
176*7dd7cddfSDavid du Colombier p.x=0.;
177*7dd7cddfSDavid du Colombier p.y=0.;
178*7dd7cddfSDavid du Colombier p.z=0.;
179*7dd7cddfSDavid du Colombier p.w=0.;
180*7dd7cddfSDavid du Colombier return p;
181*7dd7cddfSDavid du Colombier }
182*7dd7cddfSDavid du Colombier p.x=(f0.w*(f2.y*f1.z-f1.y*f2.z)
183*7dd7cddfSDavid du Colombier +f1.w*(f0.y*f2.z-f2.y*f0.z)+f2.w*(f1.y*f0.z-f0.y*f1.z))/det;
184*7dd7cddfSDavid du Colombier p.y=(f0.w*(f2.z*f1.x-f1.z*f2.x)
185*7dd7cddfSDavid du Colombier +f1.w*(f0.z*f2.x-f2.z*f0.x)+f2.w*(f1.z*f0.x-f0.z*f1.x))/det;
186*7dd7cddfSDavid du Colombier p.z=(f0.w*(f2.x*f1.y-f1.x*f2.y)
187*7dd7cddfSDavid du Colombier +f1.w*(f0.x*f2.y-f2.x*f0.y)+f2.w*(f1.x*f0.y-f0.x*f1.y))/det;
188*7dd7cddfSDavid du Colombier p.w=1.;
189*7dd7cddfSDavid du Colombier return p;
190219b2ee8SDavid du Colombier }
191219b2ee8SDavid du Colombier /*
192219b2ee8SDavid du Colombier * pdiv4 does perspective division to convert a projective point to affine coordinates.
193219b2ee8SDavid du Colombier */
pdiv4(Point3 a)194219b2ee8SDavid du Colombier Point3 pdiv4(Point3 a){
195219b2ee8SDavid du Colombier if(a.w==0) return a;
196*7dd7cddfSDavid du Colombier a.x/=a.w;
197*7dd7cddfSDavid du Colombier a.y/=a.w;
198*7dd7cddfSDavid du Colombier a.z/=a.w;
199*7dd7cddfSDavid du Colombier a.w=1.;
200*7dd7cddfSDavid du Colombier return a;
201219b2ee8SDavid du Colombier }
add4(Point3 a,Point3 b)202219b2ee8SDavid du Colombier Point3 add4(Point3 a, Point3 b){
203*7dd7cddfSDavid du Colombier a.x+=b.x;
204*7dd7cddfSDavid du Colombier a.y+=b.y;
205*7dd7cddfSDavid du Colombier a.z+=b.z;
206*7dd7cddfSDavid du Colombier a.w+=b.w;
207*7dd7cddfSDavid du Colombier return a;
208219b2ee8SDavid du Colombier }
sub4(Point3 a,Point3 b)209219b2ee8SDavid du Colombier Point3 sub4(Point3 a, Point3 b){
210*7dd7cddfSDavid du Colombier a.x-=b.x;
211*7dd7cddfSDavid du Colombier a.y-=b.y;
212*7dd7cddfSDavid du Colombier a.z-=b.z;
213*7dd7cddfSDavid du Colombier a.w-=b.w;
214*7dd7cddfSDavid du Colombier return a;
215219b2ee8SDavid du Colombier }
216