public BiconvexLens() { RefractiveIndex = Materials.Fixed.GLASS_CROWN_K7; apertureRadius = 2; curvatureRadius = 2.5; backSurface = new Sphere(); frontSurface = new Sphere(); UpdateSpheres(); }
/// <summary> /// Creates and initializes a new instance of a complex lens. /// </summary> /// <param name="surfaces">List of element surfaces, ordered from /// back to front.</param> public ComplexLens(IList<ElementSurface> surfaces) { ElementSurfaces = surfaces; ElementSurface frontSurface = surfaces.LastOrDefault((surface) => surface.Surface is Sphere); frontSphericalSurface = (Sphere)frontSurface.Surface; frontSurfaceSinTheta = frontSphericalSurface.GetCapElevationAngleSine(frontSurface.ApertureRadius); frontSurfaceApertureRadius = frontSurface.ApertureRadius; ElementSurface backSurface = surfaces.FirstOrDefault((surface) => surface.Surface is Sphere); backSphericalSurface = (Sphere)backSurface.Surface; backSurfaceSinTheta = backSphericalSurface.GetCapElevationAngleSine(backSurface.ApertureRadius); backSurfaceApertureRadius = backSurface.ApertureRadius; MediumRefractiveIndex = Materials.Fixed.AIR; frontSurface.NextRefractiveIndex = MediumRefractiveIndex; }
public Window() : base(1280, 720, new GraphicsMode(32, 0, 0, 4), "OpenCAD") { stl = new STL("Models/elephant.stl", Color.Green, STLType.Binary); var s1 = new Sphere {Center = Vect3.Zero, Radius = 4}; var s2 = new Sphere {Center = new Vect3(0,5,0), Radius = 4}; var t1 = new Octree<Voxel>(Vect3.Zero, 32.0); var t2 = new Octree<Voxel>(Vect3.Zero, 32.0); Test2(t1, node => s1.Intersects(node.AABB)); Test(t2, stl.Elements); _tree = t1.Union(t2); //_tree.Test(node => sphere.Intersects(node.AABB),maxLevel); //Test2(t, node => sphere.Intersects(node.AABB)); //t[0].Clear(); //t[0].Clear(); //Test(_tree,stl.Elements); //create from stl //foreach (var tri in stl.Elements) //{ // Intersect(_tree, tri); //} VSync = VSyncMode.On; _camera = new Camera(); Mouse.WheelChanged += (sender, args) => { _camera.View = _camera.View * Mat4.Translate(0, 0, args.DeltaPrecise * -10.0); //_camera.Eye += new Vect3(0, 0, args.DeltaPrecise * -10.0); // Console.WriteLine(_camera.Eye); }; }
public void IntersectSphere() { Sphere sphere = new Sphere() { Radius = 2 }; double biggerSphereFactor = 3; Sampler sampler = new Sampler(); int sampleCount = 64; int sqrtSampleCount = (int)Math.Sqrt(sampleCount); foreach (Vector2d sample in sampler.GenerateJitteredSamples(sqrtSampleCount)) { // shoot rays at the sphere center from a bigger concontric sphere Vector3d unitSphereSample = Sampler.UniformSampleSphereWithEqualArea(sample, -1, 1); Vector3d sourcePos = biggerSphereFactor * sphere.Radius * unitSphereSample; Ray ray = new Ray(sourcePos, sphere.Center - sourcePos); Intersection intersection = sphere.Intersect(ray); Assert.NotNull(intersection); Vector3d intPos = intersection.Position; Console.WriteLine("Black, {0},", ray.ToLine()); Console.WriteLine(String.Format("Red, {0},", intPos.ToPoint())); } }
protected static CSGInnerNode head() { CSGInnerNode root = new CSGInnerNode( SetOperation.Union ); double[] skinColor = new double[] { 1, .8, .65 }; double[] whiteColor = new double[] { 1, 1, 1 }; double[] blackColor = new double[] { 0, 0, 0 }; double[] blueColor = new double[] { 0, 0, 1 }; double[] redColor = new double[] { 1, 0, 0 }; CSGInnerNode hlava = new CSGInnerNode( SetOperation.Difference ); root.InsertChild( hlava, Matrix4d.Identity ); Sphere s = new Sphere(); s.SetAttribute( PropertyName.COLOR, skinColor ); hlava.InsertChild( s, Matrix4d.Scale( 2.3 ) ); // klobouk CSGInnerNode klobouk = new CSGInnerNode( SetOperation.Union ); Cylinder klb = new Cylinder( -0.5, 0.5 ); klb.SetAttribute( PropertyName.COLOR, blackColor ); klobouk.InsertChild( klb, Matrix4d.Scale( 2, 2, 1.4 ) * Matrix4d.RotateX( Math.PI / 2 ) * Matrix4d.CreateTranslation( 0, 0.5, 0 ) ); Cylinder ksilt = new Cylinder( -0.5, 0.5 ); ksilt.SetAttribute( PropertyName.COLOR, blackColor ); klobouk.InsertChild( ksilt, Matrix4d.Scale( 3, 3, .1 ) * Matrix4d.RotateX( Math.PI / 2 ) ); root.InsertChild( klobouk, Matrix4d.CreateTranslation( 0, 1.25, 0 ) ); // levy ocni dulek s = new Sphere(); s.SetAttribute( PropertyName.COLOR, skinColor ); hlava.InsertChild( s, Matrix4d.Scale( 0.7 ) * Matrix4d.CreateTranslation( -0.7, .3, -1.8 ) ); // pravy ocni dulek s = new Sphere(); s.SetAttribute( PropertyName.COLOR, skinColor ); hlava.InsertChild( s, Matrix4d.Scale( 0.7 ) * Matrix4d.CreateTranslation( 0.7, .3, -1.8 ) ); // prave oko CSGInnerNode oko = new CSGInnerNode( SetOperation.Union ); root.InsertChild( oko, Matrix4d.CreateTranslation( 0.70, 0.3, -0.5 ) ); Sphere bulva = new Sphere(); bulva.SetAttribute( PropertyName.COLOR, whiteColor ); oko.InsertChild( bulva, Matrix4d.Scale( 1.3 ) ); Sphere cocka = new Sphere(); cocka.SetAttribute( PropertyName.COLOR, blueColor ); oko.InsertChild( cocka, Matrix4d.Scale( 0.3 ) * Matrix4d.CreateTranslation( 0, 0, -1.2 ) ); // leve oko oko = new CSGInnerNode( SetOperation.Union ); root.InsertChild( oko, Matrix4d.CreateTranslation( -0.70, 0.3, -0.5 ) ); bulva = new Sphere(); bulva.SetAttribute( PropertyName.COLOR, whiteColor ); oko.InsertChild( bulva, Matrix4d.Scale( 1.3 ) ); cocka = new Sphere(); cocka.SetAttribute( PropertyName.COLOR, blueColor ); oko.InsertChild( cocka, Matrix4d.Scale( 0.3 ) * Matrix4d.CreateTranslation( 0, 0, -1.2 ) ); // nos Cylinder nos = new Cylinder( -0.5, 0.5 ); nos.SetAttribute( PropertyName.COLOR, skinColor ); root.InsertChild( nos, Matrix4d.Scale( 0.2, 0.2, 0.6 ) * Matrix4d.CreateTranslation( 0, 0, -2.65 ) ); // usta CSGInnerNode usta = new CSGInnerNode( SetOperation.Xor ); Cylinder horniRet = new Cylinder( -0.5, 0.5 ); horniRet.SetAttribute( PropertyName.COLOR, redColor ); usta.InsertChild( horniRet, Matrix4d.CreateTranslation( 0, -0.3, 0 ) ); Cylinder dolniRet = new Cylinder( -0.5, 0.5 ); dolniRet.SetAttribute( PropertyName.COLOR, redColor ); usta.InsertChild( dolniRet, Matrix4d.CreateTranslation( 0, 0.3, 0 ) ); root.InsertChild( usta, Matrix4d.Scale( 0.7, 0.3, 1 ) * Matrix4d.CreateTranslation( 0, -0.7, -1.85 ) ); // vnitrek ust CSGInnerNode vnitrekUst = new CSGInnerNode( SetOperation.Intersection ); horniRet = new Cylinder( -0.5, 0.5 ); horniRet.SetAttribute( PropertyName.COLOR, blackColor ); vnitrekUst.InsertChild( horniRet, Matrix4d.CreateTranslation( 0, -0.3, 0 ) ); dolniRet = new Cylinder( -0.5, 0.5 ); dolniRet.SetAttribute( PropertyName.COLOR, blackColor ); vnitrekUst.InsertChild( dolniRet, Matrix4d.CreateTranslation( 0, 0.3, 0 ) ); usta.InsertChild( vnitrekUst, Matrix4d.CreateTranslation( 0, 0, 0.1 ) ); return root; }
/// <summary> /// Infinite plane with two spheres on it (one of them is transparent) /// </summary> public static void TwoSpheres( IRayScene sc ) { Debug.Assert( sc != null ); // CSG scene: CSGInnerNode root = new CSGInnerNode( SetOperation.Union ); root.SetAttribute( PropertyName.REFLECTANCE_MODEL, new PhongModel() ); root.SetAttribute( PropertyName.MATERIAL, new PhongMaterial( new double[] { 1.0, 0.8, 0.1 }, 0.1, 0.6, 0.4, 128 ) ); sc.Intersectable = root; // Background color: sc.BackgroundColor = new double[] { 0.0, 0.05, 0.07 }; // Camera: sc.Camera = new StaticCamera( new Vector3d( 0.7, 0.5, -5.0 ), new Vector3d( 0.0, -0.18, 1.0 ), 50.0 ); // Light sources: sc.Sources = new LinkedList<ILightSource>(); sc.Sources.Add( new AmbientLightSource( 0.8 ) ); sc.Sources.Add( new PointLightSource( new Vector3d( -5.0, 4.0, -3.0 ), 1.2 ) ); // --- NODE DEFINITIONS ---------------------------------------------------- // Transparent sphere: Sphere s; s = new Sphere(); PhongMaterial pm = new PhongMaterial( new double[] { 0.0, 0.2, 0.1 }, 0.05, 0.05, 0.1, 128 ); pm.n = 1.6; pm.Kt = 0.9; s.SetAttribute( PropertyName.MATERIAL, pm ); root.InsertChild( s, Matrix4d.Identity ); // Opaque sphere: s = new Sphere(); root.InsertChild( s, Matrix4d.Scale( 1.2 ) * Matrix4d.CreateTranslation( 1.5, 0.2, 2.4 ) ); // Infinite plane with checker: Plane pl = new Plane(); pl.SetAttribute( PropertyName.COLOR, new double[] { 0.3, 0.0, 0.0 } ); pl.SetAttribute( PropertyName.TEXTURE, new CheckerTexture( 0.6, 0.6, new double[] { 1.0, 1.0, 1.0 } ) ); root.InsertChild( pl, Matrix4d.RotateX( -MathHelper.PiOver2 ) * Matrix4d.CreateTranslation( 0.0, -1.0, 0.0 ) ); }
/// <summary> /// Test scene for Toruses by Jan Navratil, (c) 2012 /// </summary> public static void Toroids( IRayScene sc ) { Debug.Assert( sc != null ); // CSG scene: CSGInnerNode root = new CSGInnerNode( SetOperation.Union ); root.SetAttribute( PropertyName.REFLECTANCE_MODEL, new PhongModel() ); root.SetAttribute( PropertyName.MATERIAL, new PhongMaterial( new double[] { 0.5, 0.5, 0.5 }, 0.2, 0.7, 0.2, 16 ) ); sc.Intersectable = root; // Background color: sc.BackgroundColor = new double[] { 0.0, 0.15, 0.2 }; // Camera: sc.Camera = new StaticCamera( new Vector3d( 0.0, 0.0, -10.0 ), new Vector3d( 0.0, -0.04, 1.0 ), 60.0 ); // Light sources: sc.Sources = new LinkedList<ILightSource>(); sc.Sources.Add( new AmbientLightSource( 1.8 ) ); sc.Sources.Add( new PointLightSource( new Vector3d( -5.0, 3.0, -3.0 ), 2.0 ) ); // --- NODE DEFINITIONS ---------------------------------------------------- Sphere s; Torus t; t = new Torus( 2.0, 1.0 ); t.SetAttribute( PropertyName.COLOR, new double[] { 0, 0, 0.7 } ); t.SetAttribute( PropertyName.TEXTURE, new CheckerTexture( 50, 20, new double[] { 0.9, 0.9, 0 } ) ); root.InsertChild( t, Matrix4d.Scale( 0.8 ) * Matrix4d.CreateRotationX( 0.9 ) * Matrix4d.CreateTranslation( 2.7, 0.6, 0.0 ) ); t = new Torus( 1.0, 1.5 ); t.SetAttribute( PropertyName.COLOR, new double[] { 1, 0, 0 } ); t.SetAttribute( PropertyName.TEXTURE, new CheckerTexture( 40, 40, new double[] { 0.8, 1.0, 1.0 } ) ); CSGInnerNode donut = new CSGInnerNode( SetOperation.Difference ); donut.InsertChild( t, Matrix4d.Identity ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 0.5, 0.5, 0.5 } ); s.SetAttribute( PropertyName.TEXTURE, new CheckerTexture( 100, 100, new double[] { 1, 0.5, 0 } ) ); donut.InsertChild( s, Matrix4d.Scale( 3 ) * Matrix4d.CreateTranslation( 0, -3, 0 ) ); root.InsertChild( donut, Matrix4d.CreateRotationX( 0.8 ) * Matrix4d.CreateTranslation( -2.5, 0.0, 0.0 ) ); int number = 14; for ( int i = 0; i < number; i++ ) { t = new Torus( 0.2, 0.01 + 0.185 * i / number ); t.SetAttribute( PropertyName.COLOR, new double[] { 1, 1, 1 } ); root.InsertChild( t, Matrix4d.CreateRotationX( 0.5 * i ) * Matrix4d.CreateTranslation( 10.0 * (1.0 * i / number) - 4.7, -2.5, 0 ) ); } }
/// <summary> /// Hedgehog in the Cage - by Michal Wirth, (c) 2012 /// </summary> public static void HedgehogInTheCage( IRayScene sc ) { Debug.Assert( sc != null ); // CSG scene: CSGInnerNode root = new CSGInnerNode( SetOperation.Union ); root.SetAttribute( PropertyName.REFLECTANCE_MODEL, new PhongModel() ); root.SetAttribute( PropertyName.MATERIAL, new PhongMaterial( new double[] { 0.5, 0.5, 0.5 }, 0.2, 0.6, 0.2, 16 ) ); sc.Intersectable = root; // Background color: sc.BackgroundColor = new double[] { 0.0, 0.05, 0.05 }; // Camera: sc.Camera = new StaticCamera( new Vector3d( 0.0, 2.0, -7.0 ), new Vector3d( 0.0, -0.32, 1.0 ), 40.0 ); // Light sources: sc.Sources = new LinkedList<ILightSource>(); sc.Sources.Add( new AmbientLightSource( 0.8 ) ); sc.Sources.Add( new PointLightSource( new Vector3d( -8.0, 5.0, -3.0 ), 1.0 ) ); // --- NODE DEFINITIONS ---------------------------------------------------- // cage CSGInnerNode cage = new CSGInnerNode( SetOperation.Difference ); cage.SetAttribute( PropertyName.COLOR, new double[] { 0.70, 0.93, 0.20 } ); // cylinder1 CSGInnerNode cylinder1 = new CSGInnerNode( SetOperation.Intersection ); Sphere s = new Sphere(); cylinder1.InsertChild( s, Matrix4d.Scale( 1.0, 1000.0, 1.0 ) ); s = new Sphere(); cylinder1.InsertChild( s, Matrix4d.Scale( 1000.0, 1.5, 1000.0 ) ); cage.InsertChild( cylinder1, Matrix4d.Identity ); // cylinder2 CSGInnerNode cylinder2 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); cylinder2.InsertChild( s, Matrix4d.Scale( 1.0, 1000.0, 1.0 ) ); s = new Sphere(); cylinder2.InsertChild( s, Matrix4d.Scale( 1000.0, 1.5, 1000.0 ) ); cage.InsertChild( cylinder2, Matrix4d.Scale( 0.9 ) ); // holeUpDown Sphere holeUpDown = new Sphere(); cage.InsertChild( holeUpDown, Matrix4d.Scale( 0.5, 1000.0, 0.5 ) ); // hole1 CSGInnerNode hole1 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); hole1.InsertChild( s, Matrix4d.Scale( 1000.0, 1.1, 1000.0 ) ); s = new Sphere(); hole1.InsertChild( s, Matrix4d.Scale( 0.4, 1000.0, 1000.0 ) ); cage.InsertChild( hole1, Matrix4d.Identity ); // hole2 CSGInnerNode hole2 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); hole2.InsertChild( s, Matrix4d.Scale( 1000.0, 1.1, 1000.0 ) ); s = new Sphere(); hole2.InsertChild( s, Matrix4d.Scale( 0.4, 1000.0, 1000.0 ) ); cage.InsertChild( hole2, Matrix4d.RotateY( Math.PI / 3 ) ); // hole3 CSGInnerNode hole3 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); hole3.InsertChild( s, Matrix4d.Scale( 1000.0, 1.1, 1000.0 ) ); s = new Sphere(); hole3.InsertChild( s, Matrix4d.Scale( 0.4, 1000.0, 1000.0 ) ); cage.InsertChild( hole3, Matrix4d.RotateY( Math.PI / -3 ) ); // hedgehog CSGInnerNode hedgehog = new CSGInnerNode( SetOperation.Union ); hedgehog.SetAttribute( PropertyName.COLOR, new double[] { 0.4, 0.05, 0.05 } ); s = new Sphere(); hedgehog.InsertChild( s, Matrix4d.Scale( 0.48 ) ); // spine1 CSGInnerNode spine1 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); spine1.InsertChild( s, Matrix4d.Scale( 0.06, 1000.0, 0.06 ) ); s = new Sphere(); spine1.InsertChild( s, Matrix4d.Scale( 1.2 ) ); hedgehog.InsertChild( spine1, Matrix4d.Identity ); // spine2 CSGInnerNode spine2 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); spine2.InsertChild( s, Matrix4d.Scale( 0.06, 1000.0, 0.06 ) ); s = new Sphere(); spine2.InsertChild( s, Matrix4d.Scale( 1.2 ) * Matrix4d.CreateTranslation( 0.0, 0.1, 0.0 ) ); hedgehog.InsertChild( spine2, Matrix4d.RotateX( Math.PI / -3 ) ); // spine3 CSGInnerNode spine3 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); spine3.InsertChild( s, Matrix4d.Scale( 0.06, 1000.0, 0.06 ) ); s = new Sphere(); spine3.InsertChild( s, Matrix4d.Scale( 1.2 ) * Matrix4d.CreateTranslation( 0.0, -0.25, 0.0 ) ); hedgehog.InsertChild( spine3, Matrix4d.RotateX( Math.PI / -3 ) * Matrix4d.RotateY( Math.PI * -0.4 ) ); // spine4 CSGInnerNode spine4 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); spine4.InsertChild( s, Matrix4d.Scale( 0.06, 1000.0, 0.06 ) ); s = new Sphere(); spine4.InsertChild( s, Matrix4d.Scale( 1.2 ) * Matrix4d.CreateTranslation( 0.0, 0.2, 0.0 ) ); hedgehog.InsertChild( spine4, Matrix4d.RotateX( Math.PI / -3 ) * Matrix4d.RotateY( Math.PI * -0.8 ) ); // spine5 CSGInnerNode spine5 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); spine5.InsertChild( s, Matrix4d.Scale( 0.06, 1000.0, 0.06 ) ); s = new Sphere(); spine5.InsertChild( s, Matrix4d.Scale( 1.2 ) * Matrix4d.CreateTranslation( 0.0, -0.2, 0.0 ) ); hedgehog.InsertChild( spine5, Matrix4d.RotateX( Math.PI / -3 ) * Matrix4d.RotateY( Math.PI * 0.4 ) ); // spine6 CSGInnerNode spine6 = new CSGInnerNode( SetOperation.Intersection ); s = new Sphere(); spine6.InsertChild( s, Matrix4d.Scale( 0.06, 1000.0, 0.06 ) ); s = new Sphere(); spine6.InsertChild( s, Matrix4d.Scale( 1.2 ) * Matrix4d.CreateTranslation( 0.0, -0.25, 0.0 ) ); hedgehog.InsertChild( spine6, Matrix4d.RotateX( Math.PI / -3 ) * Matrix4d.RotateY( Math.PI * 0.8 ) ); // all CSGInnerNode all = new CSGInnerNode( SetOperation.Union ); all.InsertChild( cage, Matrix4d.RotateY( 0.25 ) ); all.InsertChild( hedgehog, Matrix4d.Rotate( new Vector3d( 0.0, 1.0, 1.0 ), 0.1 ) * Matrix4d.CreateTranslation( 0.0, -0.1, 0.0 ) ); root.InsertChild( all, Matrix4d.RotateZ( 0.1 ) ); }
/// <summary> /// Six national flags (in artistic style) - by Jakub Vlcek, (c) 2012 /// </summary> public static void Flags( IRayScene sc ) { Debug.Assert( sc != null ); // CSG scene: CSGInnerNode flags = new CSGInnerNode( SetOperation.Union ); flags.SetAttribute( PropertyName.REFLECTANCE_MODEL, new PhongModel() ); flags.SetAttribute( PropertyName.MATERIAL, new PhongMaterial( new double[] { 0.5, 0.5, 0.5 }, 0.2, 0.7, 0.1, 16 ) ); sc.Intersectable = flags; Sphere s; Cube c; // Background color: sc.BackgroundColor = new double[] { 0.0, 0.05, 0.05 }; // Camera: sc.Camera = new StaticCamera( new Vector3d( 0.0, 0.0, -10.0 ), new Vector3d( 0.0, 0.0, 1.0 ), 60.0 ); // Light sources: sc.Sources = new LinkedList<ILightSource>(); sc.Sources.Add( new AmbientLightSource( 0.8 ) ); sc.Sources.Add( new PointLightSource( new Vector3d( -5.0, 3.0, -3.0 ), 1.0 ) ); sc.Sources.Add( new PointLightSource( new Vector3d( 5.0, 3.0, -3.0 ), 1.0 ) ); // --- NODE DEFINITIONS ---------------------------------------------------- // Latvian flag (intersection, difference and xor): CSGInnerNode latvia = new CSGInnerNode( SetOperation.Intersection ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 0.3, 0.0, 0.0 } ); latvia.InsertChild( c, Matrix4d.Scale( 4.0, 2.0, 0.4 ) * Matrix4d.CreateTranslation( -2.0, -1.0, 0.0 ) ); CSGInnerNode latviaFlag = new CSGInnerNode( SetOperation.Xor ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 0.3, 0.0, 0.0 } ); latviaFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 4.0, 2.0, 2.0 ) ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 1.0, 1.0 } ); latviaFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 4.2, 0.5, 0.5 ) ); latvia.InsertChild( latviaFlag, Matrix4d.Identity ); flags.InsertChild( latvia, Matrix4d.Scale( 0.7 ) * Matrix4d.CreateRotationX( Math.PI / 8 ) * Matrix4d.CreateTranslation( -3.5, 1.5, 0.0 ) ); // Czech flag (difference): CSGInnerNode czech = new CSGInnerNode( SetOperation.Difference ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 0.2, 0.2, 0.2 } ); czech.InsertChild( s, Matrix4d.Identity ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 1.0, 1.0 } ); czech.InsertChild( s, Matrix4d.CreateTranslation( 0.0, 0.8, -1.0 ) ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 0.0, 0.0 } ); czech.InsertChild( s, Matrix4d.CreateTranslation( 0.0, -0.8, -1.1 ) ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 0.0, 0.0, 1.0 } ); czech.InsertChild( s, Matrix4d.CreateTranslation( -1.0, 0.0, -0.8 ) ); flags.InsertChild( czech, Matrix4d.Scale( 1.6, 1.0, 1.0 ) * Matrix4d.CreateRotationY( Math.PI / 8 ) * Matrix4d.CreateTranslation( 4.0, -1.5, 0.0 ) ); // Croatian flag (union, intersection): CSGInnerNode croatianFlag = new CSGInnerNode( SetOperation.Union ); CSGInnerNode croatianSign = new CSGInnerNode( SetOperation.Intersection ); CSGInnerNode checkerBoard = new CSGInnerNode( SetOperation.Union ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 0.0, 0.0 } ); c.SetAttribute( PropertyName.TEXTURE, new CheckerTexture( 10.0, 10.0, new double[] { 1.0, 1.0, 1.0 } ) ); croatianSign.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 2.0, 2.0, 0.4 ) ); CSGInnerNode sign = new CSGInnerNode( SetOperation.Union ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 1.0, 1.0 } ); sign.InsertChild( s, Matrix4d.Identity ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 1.0, 1.0 } ); sign.InsertChild( c, Matrix4d.Scale( 1.8 ) * Matrix4d.CreateTranslation( -0.9, 0.1, -0.9 ) ); croatianSign.InsertChild( sign, Matrix4d.Scale( 0.5, 0.33, 0.5 ) * Matrix4d.CreateTranslation( 0.44, -0.5, 0.0 ) ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 0.0, 0.0 } ); croatianFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 4.0, 0.6, 0.6 ) * Matrix4d.RotateX( Math.PI / 4 ) * Matrix4d.CreateTranslation( 0.5, 1.0, 1.0 ) ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 1.0, 1.0 } ); croatianFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 4.0, 0.6, 0.6 ) * Matrix4d.RotateX( Math.PI / 4 ) * Matrix4d.CreateTranslation( 0.5, 0.3, 1.0 ) ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 0.0, 0.0, 1.0 } ); croatianFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 4.0, 0.6, 0.6 ) * Matrix4d.RotateX( Math.PI / 4 ) * Matrix4d.CreateTranslation( 0.5, -0.4, 1.0 ) ); croatianFlag.InsertChild( croatianSign, Matrix4d.Scale( 0.8 ) * Matrix4d.CreateTranslation( 0.4, 0.5, 0.0 ) ); flags.InsertChild( croatianFlag, Matrix4d.Scale( 0.8 ) * Matrix4d.CreateRotationY( Math.PI / 8 ) * Matrix4d.CreateTranslation( -0.4, 1.5, 1.0 ) ); // Brazilian flag (union): CSGInnerNode brazilianFlag = new CSGInnerNode( SetOperation.Union ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 0.0, 0.8, 0.0 } ); brazilianFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 4.0, 2.0, 0.2 ) ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 1.0, 0.0 } ); brazilianFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.CreateRotationZ( Math.PI / 4 ) * Matrix4d.Scale( 2.0, 1.0, 0.4 ) ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 0.0, 0.0, 1.0 } ); brazilianFlag.InsertChild( s, Matrix4d.Scale( 0.5 ) * Matrix4d.CreateTranslation( 0.0, 0.0, 0.0 ) ); flags.InsertChild( brazilianFlag, Matrix4d.Scale( 0.9 ) * Matrix4d.RotateY( -Math.PI / 8 ) * Matrix4d.CreateTranslation( 0.0, -1.8, 1.0 ) ); // Finnish flag (intersection and difference): CSGInnerNode finlandFlag = new CSGInnerNode( SetOperation.Difference ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 1.0, 1.0 } ); finlandFlag.InsertChild( s, Matrix4d.Scale( 2.0, 1.0, 0.5 ) * Matrix4d.CreateTranslation( 0.0, 0.0, 0.3 ) ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 0.0, 0.0, 1.0 } ); finlandFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 4.2, 0.5, 0.5 ) ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 0.0, 0.0, 1.0 } ); finlandFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 0.5, 4.2, 0.5 ) * Matrix4d.CreateTranslation( -0.5, 0.0, 0.0 ) ); flags.InsertChild( finlandFlag, Matrix4d.Scale( 0.7 ) * Matrix4d.CreateTranslation( 3.5, 1.5, 0.0 ) ); // Cuban flag (union and intersection): CSGInnerNode cubanFlag = new CSGInnerNode( SetOperation.Union ); for ( int i = 0; i < 5; i++ ) { c = new Cube(); if ( i % 2 == 0 ) c.SetAttribute( PropertyName.COLOR, new double[] { 0.0, 0.0, 1.0 } ); else c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 1.0, 1.0 } ); cubanFlag.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 4.0, 0.4, 0.4 ) * Matrix4d.CreateTranslation( new Vector3d( 0.0, 0.0 - i * 0.4, 0.8 - i * 0.2 ) ) ); } CSGInnerNode wedge = new CSGInnerNode( SetOperation.Intersection ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 0.0, 0.0 } ); wedge.InsertChild( c, Matrix4d.CreateTranslation( -0.5, -0.5, -0.5 ) * Matrix4d.Scale( 2.0, 2.0, 2.0 ) * Matrix4d.CreateRotationZ( Math.PI / 4 ) ); c = new Cube(); c.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 0.0, 0.0 } ); wedge.InsertChild( c, Matrix4d.Scale( 4.0 ) * Matrix4d.CreateTranslation( 0.0, -2.0, -2.0 ) ); cubanFlag.InsertChild( wedge, Matrix4d.Scale( 0.7 ) * Matrix4d.CreateTranslation( -2.0001, -0.8, 0.4999 ) ); flags.InsertChild( cubanFlag, Matrix4d.Scale( 0.7 ) * Matrix4d.RotateY( Math.PI / 8 ) * Matrix4d.CreateTranslation( -4.0, -1.0, 0.0 ) ); }
/// <summary> /// Simple scene containing five colored spheres. /// </summary> public static void FiveBalls( IRayScene sc ) { Debug.Assert( sc != null ); // CSG scene: CSGInnerNode root = new CSGInnerNode( SetOperation.Union ); root.SetAttribute( PropertyName.REFLECTANCE_MODEL, new PhongModel() ); root.SetAttribute( PropertyName.MATERIAL, new PhongMaterial( new double[] { 0.5, 0.5, 0.5 }, 0.1, 0.6, 0.3, 16 ) ); sc.Intersectable = root; // Background color: sc.BackgroundColor = new double[] { 0.0, 0.05, 0.05 }; // Camera: sc.Camera = new StaticCamera( new Vector3d( 0.0, 0.0, -10.0 ), new Vector3d( 0.0, 0.0, 1.0 ), 60.0 ); // Light sources: sc.Sources = new LinkedList<ILightSource>(); sc.Sources.Add( new AmbientLightSource( 0.8 ) ); sc.Sources.Add( new PointLightSource( new Vector3d( -5.0, 3.0, -3.0 ), 1.0 ) ); // --- NODE DEFINITIONS ---------------------------------------------------- // sphere 1: Sphere s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 0.6, 0.0 } ); root.InsertChild( s, Matrix4d.Identity ); // sphere 2: s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 0.2, 0.9, 0.5 } ); root.InsertChild( s, Matrix4d.CreateTranslation( -2.2, 0.0, 0.0 ) ); // sphere 3: s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 0.1, 0.3, 1.0 } ); root.InsertChild( s, Matrix4d.CreateTranslation( -4.4, 0.0, 0.0 ) ); // sphere 4: s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1.0, 0.2, 0.2 } ); root.InsertChild( s, Matrix4d.CreateTranslation( 2.2, 0.0, 0.0 ) ); // sphere 5: s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 0.1, 0.4, 0.0 } ); s.SetAttribute( PropertyName.TEXTURE, new CheckerTexture( 80.0, 40.0, new double[] { 1.0, 0.8, 0.2 } ) ); root.InsertChild( s, Matrix4d.CreateTranslation( 4.4, 0.0, 0.0 ) ); }
protected static CSGInnerNode test6Spheres( SetOperation op ) { // scene: CSGInnerNode root = new CSGInnerNode( op ); Sphere s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1, 0.3, 1 } ); root.InsertChild( s, Matrix4d.Scale( 2 ) ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 0.5, 0.8, 0.2 } ); root.InsertChild( s, Matrix4d.CreateTranslation( 0, 0, -2 ) ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1, 0.3, 0 } ); root.InsertChild( s, Matrix4d.CreateTranslation( 0, 1, -0.5 ) ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1, 0.3, 0 } ); root.InsertChild( s, Matrix4d.CreateTranslation( 1, 0, -0.5 ) ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1, 0.3, 0 } ); root.InsertChild( s, Matrix4d.CreateTranslation( 0, -1, -0.5 ) ); s = new Sphere(); s.SetAttribute( PropertyName.COLOR, new double[] { 1, 0.3, 0 } ); root.InsertChild( s, Matrix4d.CreateTranslation( -1, 0, -0.5 ) ); return root; }
/// <summary> /// Read collision file from file<para/> /// Чтение файлов коллизий из файла /// </summary> /// <param name="filename">File name<para/>Имя файла</param> public CollisionFile(string filename) { if (!File.Exists(filename)) { throw new FileNotFoundException("[CollisionFile] File not found: "+Path.GetFileName(filename), filename); } // Opening reader // Открытие ридера Collisions = new List<Group>(); BinaryReader f = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read), Encoding.ASCII); // Read all the models // Чтение всех моделей while (f.BaseStream.Position<f.BaseStream.Length-1) { // Reading header // Чтение заголовка string header = new string(f.ReadChars(4)); if (header != "COLL") { throw new Exception("[CollisionFile] Unknown collision format: "+header); } f.BaseStream.Position += 4; // Creating new group // Создание новой группы Group c = new Group(); // Reading collision head // Чтение оглавления файла c.Name = f.ReadVCString(22).ToLower(); c.ID = f.ReadUInt16(); // Reading bounds // Чтение габаритов c.BoundsRadius = f.ReadSingle(); c.BoundsCenter = f.ReadVCVector(); c.BoundsMin = f.ReadVCVector(); c.BoundsMax = f.ReadVCVector(); // Reading objects // Чтение объектов int numSpheres = f.ReadInt32(); if (numSpheres>0) { // Spheres // Сферы c.Spheres = new Sphere[numSpheres]; for (int i = 0; i < numSpheres; i++) { Sphere s = new Sphere(); s.Radius = f.ReadSingle(); s.Center = f.ReadVCVector(); s.ReadParams(f); c.Spheres[i] = s; } } // Skip unknown index // Пропуск неизвестного числа f.BaseStream.Position += 4; int numBoxes = f.ReadInt32(); if (numBoxes>0) { // Boxes // Боксы c.Boxes = new Box[numBoxes]; for (int i = 0; i < numBoxes; i++) { Box b = new Box(); b.Min = f.ReadVCVector(); b.Max = f.ReadVCVector(); b.ReadParams(f); c.Boxes[i] = b; } } int numVerts = f.ReadInt32(); if (numVerts>0) { // Vertices and triangles // Вершины и треугольники c.Vertices = new Vector3[numVerts]; for (int i = 0; i < numVerts; i++) { c.Vertices[i] = f.ReadVCVector(); } // Reading trimeshes // Чтение тримешей int indexCount = f.ReadInt32(); List<int>[] indices = new List<int>[SurfaceMaterialsCount]; int meshCount = 0; for (int i = 0; i < indexCount; i++) { // Reading single tri // Чтение треугольника int v0 = f.ReadInt32(); int v1 = f.ReadInt32(); int v2 = f.ReadInt32(); int mat = f.ReadByte(); f.BaseStream.Position += 3; // Determining surf // Поиск поверхности if (indices[mat]==null) { indices[mat] = new List<int>(); meshCount++; } indices[mat].AddRange(new int[]{ v0, v1, v2 }); } // Storing trimeshes // Сохранение тримешей c.Meshes = new Trimesh[meshCount]; int p = 0; for (int i = 0; i < indices.Length; i++) { if (indices[i]!=null) { c.Meshes[p] = new Trimesh() { Flags = 0, Material = (byte)i, Indices = indices[i].ToArray() }; p++; } } }else{ // Skip indices - they are empty // Пропуск индексов - они пустые f.BaseStream.Position += 4; } // Store mesh // Сохранение меша if (c.Spheres != null || c.Boxes != null || c.Meshes !=null) { Collisions.Add(c); } // Give prior to main thread // Отдаём предпочтение основному потоку System.Threading.Thread.Sleep(0); } // Closing reader // Закрытие потока f.Close(); }
public LensRayTransferFunction.Parameters ConvertSurfaceRayToParameters( Ray ray, Vector3d canonicalNormal, double surfaceSinTheta, Sphere sphericalSurface, ElementSurface surface) { //Console.WriteLine("ray->parameters"); // - convert origin // *- transform to hemispherical coordinates // - find out if it is on the surface // *- scale with respect to the spherical cap // *- normalize Vector3d unitSpherePos = (ray.Origin - sphericalSurface.Center) * sphericalSurface.RadiusInv; unitSpherePos.Z *= canonicalNormal.Z; //Console.WriteLine("unit sphere position: {0}", unitSpherePos); Vector2d originParametric = Sampler.SampleSphereWithUniformSpacingInverse( unitSpherePos, surfaceSinTheta, 1); // - convert direction // *- transform from camera space to local frame // *- compute normal at origin //Console.WriteLine("ray origin: {0}", ray.Origin); Vector3d normalLocal = surface.SurfaceNormalField.GetNormal(ray.Origin); normalLocal.Normalize(); // TODO: check if it is unnecessary //Console.WriteLine("local normal: {0}", normalLocal); // *- create rotation quaternion from canonical normal to local // normal Vector3d direction = ray.Direction; //Console.WriteLine("local direction: {0}", direction); if (surface.Convex) { direction = -direction; } Vector3d rotationAxis = Vector3d.Cross(canonicalNormal, normalLocal); //Console.WriteLine("rotation axis: {0}", rotationAxis); if (rotationAxis.Length > 0) { double angle = Math.Acos(Vector3d.Dot(normalLocal, canonicalNormal)); //Console.WriteLine("angle: {0}", angle); double positionPhi = originParametric.Y; // first transformed to the frame of the local normal //Console.WriteLine("position phi: {0}", positionPhi); Matrix4d rotMatrix = Matrix4d.CreateFromAxisAngle(rotationAxis, -angle); // then rotate the local direction around Z using the position phi rotMatrix = rotMatrix * Matrix4d.CreateRotationZ(2 * Math.PI * -positionPhi); direction = Vector3d.Transform(direction, rotMatrix); } //Console.WriteLine("abs. direction: {0}", direction); // *- transform to hemispherical coordinates // - find out if it is within the local hemisphere double sinTheta = direction.Z / canonicalNormal.Z; double dirTheta = Math.Asin(sinTheta); double cosTheta = Math.Sqrt(1 - sinTheta * sinTheta); double dirPhi = Math.Atan2(direction.Y, direction.X); if (dirPhi < 0) { // map [-PI; PI] to [0; 2*PI] dirPhi += 2 * Math.PI; } // *- normalize Vector2d directionParametric = new Vector2d( dirTheta / (0.5 * Math.PI), dirPhi / (2 * Math.PI)); //Console.WriteLine("position parameters: {0}", new Vector2d( // originParametric.X, originParametric.Y)); return new LensRayTransferFunction.Parameters( originParametric.X, originParametric.Y, directionParametric.X, directionParametric.Y); }
/// <summary> /// Convert a ray with origin at the back or front lens surface from /// its parametric representation. /// </summary> /// <param name="position">Position on lens surface in parameteric /// representation (normalized hemispherical coordinates).</param> /// <param name="direction">Direction of the ray with respect to the /// local frame in parameteric representation (normalized hemispherical /// coordinates). /// </param> /// <param name="canonicalNormal">Normal of the lens surface /// hemisphere (typically (0,0,1) for the back surface or (0,0,-1) for /// the front surface).</param> /// <param name="surfaceSinTheta">Sine of the surface spherical cap /// theta angle.</param> /// <param name="sphericalSurface">Lens surface represented as a /// sphere.</param> /// <param name="surface">Lens surface with its normal field.</param> /// <returns>Ray corresponding to its parametric representation. /// </returns> public Ray ConvertParametersToSurfaceRay( LensRayTransferFunction.Parameters parameters, Vector3d canonicalNormal, double surfaceSinTheta, Sphere sphericalSurface, ElementSurface surface) { //Console.WriteLine("parameters->ray"); //Console.WriteLine("position parameters: {0}", parameters.Position); // uniform spacing sampling for LRTF sampling Vector3d unitSpherePos = Sampler.SampleSphereWithUniformSpacing( parameters.Position, surfaceSinTheta, 1); //Console.WriteLine("unit sphere position: {0}", unitSpherePos); unitSpherePos.Z *= canonicalNormal.Z; Vector3d lensPos = sphericalSurface.Center + sphericalSurface.Radius * unitSpherePos; //Console.WriteLine("ray origin: {0}", lensPos); // - get normal N at P Vector3d normalLocal = surface.SurfaceNormalField.GetNormal(lensPos); // - compute direction D from spherical coordinates (wrt normal Z = (0,0,+/-1)) double theta = 0.5 * Math.PI * parameters.DirectionTheta; double phi = 2 * Math.PI * parameters.DirectionPhi; double cosTheta = Math.Cos(theta); Vector3d directionZ = new Vector3d( Math.Cos(phi) * cosTheta, Math.Sin(phi) * cosTheta, Math.Sin(theta) * canonicalNormal.Z); // - rotate D from Z to N frame // - using a (normalized) quaternion Q // - N and Z should be assumed to be already normalized // - more efficient method: Efficiently building a matrix to // rotate one vector to another [moller1999] normalLocal.Normalize(); // TODO: check if it is unnecessary //Console.WriteLine("abs. direction: {0}", directionZ); //Console.WriteLine("local normal: {0}", normalLocal); Vector3d rotationAxis = Vector3d.Cross(canonicalNormal, normalLocal); //Console.WriteLine("rotation axis: {0}", rotationAxis); Vector3d rotatedDir = directionZ; if (rotationAxis.Length > 0) { double angle = Math.Acos(Vector3d.Dot(canonicalNormal, normalLocal)); //Console.WriteLine("angle: {0}", angle); // first the local direction must be rotated around using the position phi! //Console.WriteLine("position phi: {0}", parameters.PositionPhi); Matrix4d rotMatrix = Matrix4d.CreateRotationZ(2 * Math.PI * parameters.PositionPhi); // only then can be transformed to the frame of the local normal rotMatrix = rotMatrix * Matrix4d.CreateFromAxisAngle(rotationAxis, angle); rotatedDir = Vector3d.Transform(directionZ, rotMatrix); } if (surface.Convex) { rotatedDir = -rotatedDir; } //Console.WriteLine("local direction: {0}", rotatedDir); Ray result = new Ray(lensPos, rotatedDir); return result; }
public static ComplexLens CreateBiconvexLens( double curvatureRadius, double apertureRadius, double thickness) { var surfaces = new List<ComplexLens.ElementSurface>(); Sphere backSphere = new Sphere() { Radius = curvatureRadius, }; backSphere.Center = backSphere.GetCapCenter(apertureRadius, -Vector3d.UnitZ); backSphere.Center += new Vector3d(0, 0, thickness); surfaces.Add(new ComplexLens.ElementSurface() { ApertureRadius = apertureRadius, NextRefractiveIndex = Materials.Fixed.GLASS_CROWN_K7, Surface = backSphere, SurfaceNormalField = backSphere, Convex = true }); Sphere frontSphere = new Sphere() { Radius = curvatureRadius, }; frontSphere.Center = frontSphere.GetCapCenter(apertureRadius, Vector3d.UnitZ); surfaces.Add(new ComplexLens.ElementSurface() { ApertureRadius = apertureRadius, Surface = frontSphere, SurfaceNormalField = frontSphere, Convex = false }); ComplexLens lens = new ComplexLens(surfaces); return lens; }
/// <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; }