コード例 #1
0
ファイル: ComplexLens.cs プロジェクト: bzamecnik/bokehlab
        /// <summary>
        /// Creates a new instance of a complex lens using a definition of
        /// elements.
        /// </summary>
        /// <remarks>
        /// The first and last surfaces have to be spherical. TODO: this is
        /// needed only for simpler sampling. In general planar surfaces or
        /// stops could be sampled too.
        /// </remarks>
        /// <param name="surfaceDefs">List of definitions of spherical or
        /// planar element surfaces or stops. Ordered from front to back.
        /// Must not be empty or null.
        /// </param>
        /// <param name="mediumRefractiveIndex">Index of refraction of medium
        /// outside the lens. It is assumed there is one medium on the scene
        /// side, senzor side and inside the lens.</param>
        /// <returns>The created complex lens instance.</returns>
        public static ComplexLens Create(
            IList<SphericalElementSurfaceDefinition> surfaceDefs,
            double mediumRefractiveIndex,
            double scale)
        {
            var surfaces = new List<ElementSurface>();

            var surfaceDefsReverse = surfaceDefs.Reverse().ToList();
            // scale the lens if needed
            if (Math.Abs(scale - 1.0) > epsilon)
            {
                surfaceDefsReverse = surfaceDefsReverse.Select(surface => surface.Scale(scale)).ToList();
            }
            // thickness of the whole lens (from front to back apex)
            // (without the distance to the senzor - backmost surface def.)
            double lensThickness = surfaceDefsReverse.Skip(1).Sum(def => def.Thickness);
            double elementBasePlaneShiftZ = lensThickness;

            double lastCapHeight = 0;
            double capHeight = 0;

            // definition list is ordered from front to back, working list
            // must be ordered from back to front, so a conversion has to be
            // performed
            int defIndex = 0;
            foreach (var definition in surfaceDefsReverse)
            {
                if (defIndex > 0)
                {
                    elementBasePlaneShiftZ -= definition.Thickness;
                }

                ElementSurface surface = new ElementSurface();
                surface.ApertureRadius = 0.5 * definition.ApertureDiameter;
                if (defIndex + 1 < surfaceDefsReverse.Count)
                {
                    surface.NextRefractiveIndex = surfaceDefsReverse[defIndex + 1].NextRefractiveIndex;
                }
                else
                {
                    surface.NextRefractiveIndex = mediumRefractiveIndex;
                }
                if (definition.CurvatureRadius.HasValue)
                {
                    // spherical surface
                    double radius = definition.CurvatureRadius.Value;
                    // convexity reverses when converting from front-to-back
                    // back-to-front ordering
                    surface.Convex = radius < 0;
                    Sphere sphere = new Sphere()
                    {
                        Radius = Math.Abs(radius)
                    };
                    sphere.Center = Math.Sign(radius) *
                        sphere.GetCapCenter(surface.ApertureRadius, Vector3d.UnitZ);
                    capHeight = Math.Sign(radius) * sphere.GetCapHeight(sphere.Radius, surface.ApertureRadius);
                    elementBasePlaneShiftZ -= lastCapHeight - capHeight;
                    sphere.Center += new Vector3d(0, 0, elementBasePlaneShiftZ);
                    surface.Surface = sphere;
                    surface.SurfaceNormalField = sphere;
                }
                else
                {
                    // planar surface
                    // both media are the same -> circular stop
                    // else -> planar element surface
                    surface.NextRefractiveIndex = definition.NextRefractiveIndex;
                    surface.Convex = true;
                    capHeight = 0;
                    elementBasePlaneShiftZ -= lastCapHeight - capHeight;
                    Circle circle = new Circle()
                    {
                        Radius = 0.5 * definition.ApertureDiameter,
                        Z = elementBasePlaneShiftZ,
                    };

                    surface.Surface = circle;
                    surface.SurfaceNormalField = circle;
                }
                lastCapHeight = capHeight;
                surfaces.Add(surface);
                defIndex++;
            }

            //DEBUG
            //foreach (var surface in surfaces)
            //{
            //    Console.WriteLine("{0}, {1}, {2}", surface.ApertureRadius,
            //        surface.Convex, surface.NextRefractiveIndex);
            //}

            ComplexLens lens = new ComplexLens(surfaces)
            {
                MediumRefractiveIndex = mediumRefractiveIndex
            };
            return lens;
        }