Download: raytrace.zip
raytrace.c
/* raytrace.c * * Example raytrace program */ #include <stdio.h> #include <math.h> typedef struct { double p[3]; /* starting point */ double k[3]; /* direction of propagation */ double n; /* index of refraction */ double q; /* distance parameter */ double gcosi; /* incident k dot normal */ double gcosr; /* refracted k dot normal */ double norm[3]; /* surface unit normal */ int error; /* error flag */ } RAY; typedef struct { double cv; /* curvature */ double th; /* axial thickness */ double n; /* index of refraction */ } SURF; int nsurf = 5; SURF surf[] = { {0.0, 1e20, 1.0}, {0.0289603,9.0,1.67}, {-0.0454959,2.5,1.728}, {-0.0046592,43.55158,1.0}, {0.0, 0.0, 1.0} }; int raytrace(RAY *start, RAY data[]); int trace(RAY *in, RAY *out, SURF *surf); int print_ray(RAY *ray); void print_vector(double v[3]); double dot(double a[3], double b[3]); void vnorm(double v[3], double norm); int main() { int i, iret; RAY ray[5], enp[1], *obj; obj = ray; /* define object point */ obj->p[0] = 0.0; obj->p[1] = 0.0; obj->p[2] = 0.0; /* define entrance pupil aim point */ enp->p[0] = 0.0; enp->p[1] = 12.5; enp->p[2] = 0.0; /* calculate ray optical direction cosines */ for (i=0; i<3; i++) obj->k[i] = enp->p[i] - obj->p[i]; obj->k[2] += surf->th; vnorm(obj->k,surf->n); for (i=0; i<3; i++) enp->k[i] = obj->k[i]; enp->n = surf->n; printf("object point: "); print_vector(obj->p); raytrace(enp,ray); for (i=1; i<nsurf; i++) { printf("\nSurface %d\n",i); iret = print_ray(ray+i); if (iret<0) break; } return 0; } /* * Trace ray through optical system */ int raytrace(RAY *start, RAY data[]) { int k, image, iret; RAY *in, *out; SURF *sp; sp = surf+1; start->q = 0.0; in = start; out = data+1; image = nsurf-1; for (k=1; k<=image; k++) { iret = trace(in, out, sp++); if (iret<0) return iret; /* set pointers for next set of rays */ in = out++; } return 0; } /* * Calculate surface intersection and direction of refraction */ int trace(RAY *in, RAY *out, SURF *surf) { int i; double rni, rno, cv, q; double A,B,C,D; double root, power; rni = in->n; rno = surf->n; cv = surf->cv; /* * Transfer to coordinates of current surface. * on input, in->q should be axial distance to current surface * on output, in->q will be oblique distance to current surface */ out->p[0] = in->p[0]; out->p[1] = in->p[1]; out->p[2] = in->p[2] - in->q; /* intersect current surface */ if (cv) { A = cv*rni*rni; B = in->k[2]-cv*dot(in->k,out->p); C = cv*dot(out->p,out->p)-2.0*out->p[2]; D = B*B-A*C; if (D<0.0) { out->error = -1; /* missed surface */ return out->error; } D = sqrt(D); q = C/(B+(B>0? D: -D)); } else { if (in->k[2]==0.0) { out->error = -1; /* ray parallel to plane */ return out->error; } q = -out->p[2]/in->k[2]; } in->q = q; out->q = surf->th; /* calculate point of intersection */ for (i=0; i<3; i++) out->p[i] += q * in->k[i]; /* calculate surface normal */ for (i=0; i<3; i++) out->norm[i] = -cv*out->p[i]; out->norm[2] += 1.0; /* refract ray into surface */ out->gcosi = dot(in->k,out->norm); root = out->gcosi*out->gcosi + (rno+rni)*(rno - rni); if (root<0.0) { out->error = -2; /* total internal reflection */ return out->error; } root = sqrt(root); out->gcosr = (out->gcosi>0.0? root: -root); power = out->gcosr - out->gcosi; for (i=0; i<3; i++) out->k[i] = in->k[i] + power*out->norm[i]; out->n = rno; out->error = 0; return out->error; } /* * print ray data */ int print_ray(RAY *ray) { if (ray->error==-1) { printf("MISSED SURFACE\n"); return ray->error; } printf("surface intersection "); print_vector(ray->p); if (ray->error==0) { printf("optical direction cosines "); print_vector(ray->k); } printf("surface normal "); print_vector(ray->norm); printf("q %12.6f gcosi %12.6f gcosr %12.6f\n", ray->q,ray->gcosi,ray->gcosr); if (ray->error==-2) { printf("TOTAL INTERNAL REFLECTION\n"); return ray->error; } return ray->error; } /* * print vector data */ void print_vector(double v[3]) { printf("%12.6f %12.6f %12.6f\n",v[0],v[1],v[2]); } /* * vector dot product */ double dot(double a[3], double b[3]) { return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; } /* * normalize vector length to specified value. */ void vnorm(double v[3], double norm) { int i; double vn; vn = v[0]*v[0]+v[1]*v[1]+v[2]*v[2]; if (vn==0.0) return; vn = norm/sqrt(vn); for (i=0; i<3; i++) v[i] *= vn; }
object point: 0.000000 0.000000 0.000000 Surface 1 surface intersection 0.000000 12.500000 2.341943 optical direction cosines 0.000000 -0.252721 1.650767 surface normal -0.000000 -0.362004 0.932177 q 1.862227 gcosi 0.932177 gcosr 1.630292 Surface 2 surface intersection 0.000000 12.029377 -3.583954 optical direction cosines 0.000000 -0.210644 1.715113 surface normal 0.000000 0.547287 0.836945 q 3.373122 gcosi 1.243290 gcosr 1.320172 Surface 3 surface intersection 0.000000 11.318849 -0.298668 optical direction cosines 0.000000 -0.250087 0.968223 surface normal 0.000000 0.052737 0.998608 q 45.289397 gcosi 1.701618 gcosr 0.953687 Surface 4 surface intersection 0.000000 -0.007461 0.000000 optical direction cosines 0.000000 -0.250087 0.968223 surface normal -0.000000 0.000000 1.000000 q 0.000000 gcosi 0.968223 gcosr 0.968223
Maintained by John Loomis, updated Wed Apr 25 13:47:11 2007