Пример #1
0
        /**
         * Compute dz/dx and dz/dy at x,y
         */
        static Vector2 compute_derivative(Asphere surface, Vector2 xy)
        {
            /*
             * Let s^2 = x^2 + y^2
             * and,
             * z = f(s) = c*s^2/(1 + (1 - c^2*k*s^2)^(1/2)) + A_4*s^4 + A_6*s^6 + A_8*s^8
             * + A_10*s^10 + A_12*s^12 + A_14*s^14
             *
             * Then,
             * dz/dx = dz/ds * ds/dx
             *
             * Now,
             * dz/ds = c*s/(1 - c^2*k*s^2)^(1/2) + 4*A_4*s^3 + 6*A_6*s^5 + 8*A_8*s^7 +
             * 10*A_10*s^9 + 12*A_12*s^11 + 14*A_14*s^13 and, ds/dx = x/s
             *
             * using
             * E = dz/ds * 1/s = c/(1 - c^2*k*s^2)^(1/2) + 4*A_4*s^2 + 6*A_6*s^4 +
             * 8*A_8*s^6 + 10*A_10*s^8 + 12*A_12*s^10 + 14*A_14*s^12 dz/dx = x*E and
             * dz/dy = y*E
             */
            double s = Math.Sqrt(xy.x() * xy.x() + xy.y() * xy.y());
            double E = compute_derivative(surface, s) / s;

            return(new Vector2(xy.x() * E, xy.y() * E));
        }
Пример #2
0
        /**
         * Compute 4*A_4*s^2 + 6*A_6*s^4 + 8*A_8*s^6 + 10*A_10*s^8 + 12*A_12*s^10 +
         * 14*A_14*s^12 s2 = x^2 + y^2 Used in dz/dy and dz/dx calculations
         */
        static double deform_dz_dxy(Asphere S, double s2)
        {
            double s4  = s2 * s2;
            double s6  = s4 * s2;
            double s8  = s6 * s2;
            double s10 = s8 * s2;
            double s12 = s10 * s2;

            return(4 * S._A4 * s2 + 6 * S._A6 * s4 + 8 * S._A8 * s6
                   + 10 * S._A10 * s8 + 12 * S._A12 * s10 + 14 * S._A14 * s12);
        }
Пример #3
0
        /**
         * Compute z at x,y
         */
        static double compute_Z(Asphere surface, Vector2 xy)
        {
            /* Our formula is:
             * z = f(s) = c*s^2/(1 + (1 - c^2*k*s^2)^(1/2)) + A_4*s^4 + A_6*s^6 + A_8*s^8
             * + A_10*s^10 + + A_12*s^12 + A_14*s^14
             *
             * where s = (x^2 + y^2)^(1/2)
             */
            double s2 = xy.x() * xy.x() + xy.y() * xy.y();

            return(compute_Z(surface, s2));
        }
Пример #4
0
        /**
         * Compute A_4*s^4 + A_6*s^6 + A_8*s^8 + A_10*s^10 + A_12*s^12 + A_14*s^14
         * s2 = x^2 + y^2
         */
        static double deform_sagitta(Asphere S, double s2)
        {
            double s4  = s2 * s2;
            double s6  = s4 * s2;
            double s8  = s6 * s2;
            double s10 = s8 * s2;
            double s12 = s10 * s2;
            double s14 = s12 * s2;

            return(S._A4 * s4 + S._A6 * s6 + S._A8 * s8 + S._A10 * s10
                   + S._A12 * s12 + S._A14 * s14);
        }
Пример #5
0
        /**
         * Compute 4*A_4*s^3 + 6*A_6*s^5 + 8*A_8*s^7 + 10*A_10*s^9 + 12*A_12*s^11 +
         * 14*A_14*s^13 s2 = x^2 + y^2 Used in dz/ds calculation
         */
        static double deform_dz_ds(Asphere S, double s)
        {
            double s2  = s * s;
            double s3  = s2 * s;
            double s5  = s3 * s2;
            double s7  = s5 * s2;
            double s9  = s7 * s2;
            double s11 = s9 * s2;
            double s13 = s11 * s2;

            return(4 * S._A4 * s3 + 6 * S._A6 * s5 + 8 * S._A8 * s7
                   + 10 * S._A10 * s9 + 12 * S._A12 * s11 + 14 * S._A14 * s13);
        }
Пример #6
0
        /**
         * Compute dz/ds. For the equation see next function below.
         */
        static double compute_derivative(Asphere surface, double s)
        {
            double s2 = s * s;
            double c  = surface._c; /* curvature = 1/radius */
            double c2 = c * c;
            double K  = surface._k;
            double l  = Math.Sqrt(1 - s2 * K * c2);

            if (l == 0.0)
            {
                // division by zero, really an error
                return(0);
            }
            return((c * s) / l + deform_dz_ds(surface, s));
        }
Пример #7
0
        /**
         * Compute z at s^2, where s^2 = x^2 + y^2
         */
        static double compute_Z(Asphere surface, double s2)
        {
            /* Our formula is:
             * z = f(s) = c*s^2/(1 + (1 - c^2*k*s^2)^(1/2)) + A_4*s^4 + A_6*s^6 + A_8*s^8
             * + A_10*s^10 + + A_12*s^12 + A_14*s^14
             *
             * where s = (x^2 + y^2)^(1/2)
             */
            double c    = surface._c; /* curvature = 1/radius */
            double c2   = c * c;
            double K    = surface._k;
            double l    = Math.Sqrt(1 - s2 * K * c2);
            double temp = 1 + l;

            if (temp == 0.0)
            {
                // division by zero, really an error
                return(0);
            }
            return(c * s2 / temp + deform_sagitta(surface, s2));
        }
Пример #8
0
        static Vector3 compute_normal(Asphere S, Vector3 point)
        {
            /* General ray tracing procedure - Spencer and Murty */
            /* See eq 18, 19 */
            /* Also same as p632 Feder - but z axis swapped with x */
            double s_2  = point.y() * point.y() + point.x() * point.x();
            double temp = Math.Sqrt(1.0 - S._c * S._c * s_2 * S._k);

            if (temp == 0.0)
            {
                return(Vector3.vector3_001);
            }
            if (Double.IsNaN(temp))
            {
                return(null);
            }
            double E  = S._c / temp + deform_dz_dxy(S, s_2); // eq 19
            double y1 = -point.y() * E;                      // eq 18
            double x1 = -point.x() * E;                      // eq 18
            double z1 = 1.0;                                 // eq 18

            // Following is from Goptical - tbc
            return(new Vector3(x1, y1, z1).normalize());
        }
Пример #9
0
        /* computes intersection using Feder's equations - code is taken from
         * https://github.com/dibyendumajumdar/ray.
         * Note that Feder's paper uses x-axis rather than z-axis as the
         * optical axis, so below we switch from x to z.
         */
        public static Vector3Pair compute_intersection(Vector3 origin, Vector3 direction, Asphere S)
        {
            /* direction (X,Y,Z) is the vector along the ray to the surface */
            /* origin (x,y,z) is the vector form of the vertex of the surface */

            /*
             * NOTE: variable 't' was
             * used by Feder as the vertex separation between previous
             * surface and this surface. In the new scheme, in which rays
             * are transformed to the coordinate system of the surface
             * before tracing, 't' is _zero_. It is still present in this
             * code to enable comparison with the Feder paper; the
             * optimizing compiler will eliminate it from the
             * expressions. */
            /* Feder paper equation (1) */
            double t = 0;
            double e = (t * origin.z()) - origin.dot(direction);
            /* Feder paper equation (2) */
            double M_1x = origin.z() + e * direction.z() - t;
            /* Feder paper equation (3) */
            double M_1_2 = origin.dot(origin) - (e * e) + (t * t) - (2.0 * t * origin.z());
            double r_1_2 = 1.0 / (S._c * S._c);

            if (M_1_2 > r_1_2)
            {
                M_1_2 = r_1_2; /* SPECIAL RULE! 96-01-22 */
            }
            /* Feder paper equation (4) */
            double xi_1 = Math.Sqrt((direction.z() * direction.z())
                                    - S._c * (S._c * M_1_2 - 2.0 * M_1x));

            if (Double.IsNaN(xi_1))
            { /* NaN! reject this ray! */
                Console.Write("Nan value\n");
                return(null);
            }
            /* Feder paper equation (5) */
            double L = e + (S._c * M_1_2 - 2.0 * M_1x) / (direction.z() + xi_1);

            /* Get intercept with new (spherical) surface: */
            double[] delta_length = new double[3];
            for (int k = 0; k < 3; k++)
            {
                delta_length[k] = -origin.v(k);
            }
            Vector3 result = origin.plus(direction.times(L));

            result = result.z(result.z() - t);
            Vector3 N = Vector3.vector3_0;

            /* Now (result) has x1, y1, z1 */

            /*
             * The ray has been traced to the osculating sphere with
             * curvature c1. Now we will iterate to get the intercept with
             * the nearby aspheric surface. Suppose the (rotationally
             * symmetric) aspheric is given by $$x = f(y,z)$$, and is a
             * function of $y^2 + z^2$ only. For a spherical surface, one
             * has $$x = r - (r^2 - s^2)^{1\over2}$$, where $s^2 = y^2 +
             * z^2$. For a general surface one may add deformation terms
             * to this expression and obtain $$x = c s^2 / (1 + (1 - c^2
             * s^2)^{1\over2})) + (A_2 s^2 + A_4 s^4 + ...) = f$$.  The
             * equation is expressed in this form in order to avoid
             * indeterminacy as c approaches zero, and in order to
             * represent surfaces that are nearly spherical. Near-spheres
             * cannot be handled well by a power series alone, especially
             * in the neighborhood of $s = 1 / c$.
             *
             * In this implementation we include a term for the numerical
             * eccentricity so that we can trace any pure conic section
             * without using the $A_i$ terms.
             */
            const int TOLMAX    = 10;
            double    tolerance = 1e-15;
            int       j         = 0;
            double    delta     = 0.0;

            do
            {
                /* Get square of radius of intercept: */
                /* Feder equation s^2 = x^2 + y^2, section E */
                double s_2 = result.y() * result.y() + result.x() * result.x();

                /*
                 * Get the point on aspheric which is at the same radius as
                 * the intercept of the ray. Then compute a tangent plane to
                 * the aspheric at this point and find where it intersects
                 * the ray.  This point will lie very close to the aspheric
                 * surface.  The first step is to compute the z-coordinate
                 * on the aspheric surface using $\overline{z}_0 = f(x_0,
                 * y_0)$.
                 */
                /* (1 - k*c^2*s^2)^(1/2) - part of equation (12) */
                double temp = Math.Sqrt(1.0 - S._c * S._c * s_2 * S._k);
                if (Double.IsNaN(temp) || (1.0 + temp) == 0.0)
                {
                    Console.Write("Nan or zero divide value\n");
                    return(null);
                }
                /* Feder equation (12) */

                /* But using c*s^2/[1 + (1 - k*c^2*s^2)^(1/2)] + aspheric A_2*s^2 +
                 * A_4*s^4 + ... */
                double x_bar_0 = (S._c * s_2) / (1.0 + temp) + deform_sagitta(S, s_2);
                delta = Math.Abs(result.z() - x_bar_0);

                /* Get the direction numbers for the normal to the
                 * aspheric: */
                /* Feder equation (13), l */
                double z1 = temp;
                temp = S._c + N.z() * deform_dz_dxy(S, s_2);
                /* Feder equation (14), m */
                double y1 = -result.y() * temp;
                /* Feder equation (15), n */
                double x1 = -result.x() * temp;
                N = new Vector3(x1, y1, z1);

                /* Get the distance from aspheric point to ray intercept */
                double G_0 = N.z() * (x_bar_0 - result.z()) / (direction.dot(N));

                /* and compute new estimate of intercept point: */
                result = result.plus(direction.times(G_0));
            }while ((delta > tolerance) && (++j < TOLMAX));
            if (j >= TOLMAX)
            {
                Console.Write(string.Format("rayTrace: delta=%g, reached %d iterations!?!\n", delta, j));
                return(null);
            }
            return(new Vector3Pair(result, N));
        }