コード例 #1
0
ファイル: World.cs プロジェクト: pema99/RayOptics
 public static void Draw(SpriteBatch spriteBatch)
 {
     foreach (SingleRay Ray in SingleRays)
     {
         Ray.Draw(spriteBatch);
     }
     foreach (Mirror Mirror in Mirrors)
     {
         Mirror.Draw(spriteBatch);
     }
     foreach (GlassPolygon GlassPolygon in GlassPolygons)
     {
         GlassPolygon.Draw(spriteBatch);
     }
 }
コード例 #2
0
ファイル: World.cs プロジェクト: pema99/RayOptics
        public static void Update(GameTime gameTime)
        {
            foreach (SingleRay Ray in SingleRays)
            {
                Ray.Update(gameTime);
            }
            foreach (Mirror Mirror in Mirrors)
            {
                Mirror.Update(gameTime);
            }
            foreach (GlassPolygon GlassPolygon in GlassPolygons)
            {
                GlassPolygon.Update(gameTime);
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                SingleRays[0].Angle -= 0.01;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Left))
            {
                SingleRays[0].Angle += 0.01;
            }
        }
コード例 #3
0
ファイル: SingleRay.cs プロジェクト: pema99/RayOptics
        public void Propagate(Vector Position, Vector Direction, Manipulator PreviousObject, bool InMaterial)
        {
            List <Tuple <Vector, Manipulator> > Hits = new List <Tuple <Vector, Manipulator> >();
            Vector Vector = Direction * Config.RayLength;

            //Raycast to all Mirrors
            foreach (Mirror Mirror in World.Mirrors)
            {
                if (Mirror == PreviousObject)
                {
                    continue;
                }

                double T = MathUtil.Cross(Position - Mirror.A, Vector) / MathUtil.Cross(Mirror.B - Mirror.A, Vector);
                double U = MathUtil.Cross(Position - Mirror.A, Mirror.B - Mirror.A) / MathUtil.Cross(Mirror.B - Mirror.A, Vector);

                Vector Hit = Mirror.A + (Mirror.B - Mirror.A) * T;

                if (MathUtil.Cross(Mirror.B - Mirror.A, Vector) != 0 && 0 <= T && T <= 1 && 0 <= U && U <= 1)
                {
                    Hits.Add(Tuple.Create(Hit, (Manipulator)Mirror));
                }
            }

            //Raycast to all GlassPolygons
            foreach (GlassPolygon GlassPolygon in World.GlassPolygons)
            {
                foreach (GlassPane GlassPane in GlassPolygon.Edges)
                {
                    if (GlassPane == PreviousObject)
                    {
                        continue;
                    }

                    double T = MathUtil.Cross(Position - GlassPane.A, Vector) / MathUtil.Cross(GlassPane.B - GlassPane.A, Vector);
                    double U = MathUtil.Cross(Position - GlassPane.A, GlassPane.B - GlassPane.A) / MathUtil.Cross(GlassPane.B - GlassPane.A, Vector);

                    Vector Hit = GlassPane.A + (GlassPane.B - GlassPane.A) * T;

                    if (MathUtil.Cross(GlassPane.B - GlassPane.A, Vector) != 0 && 0 <= T && T <= 1 && 0 <= U && U <= 1)
                    {
                        Hits.Add(Tuple.Create(Hit, (Manipulator)GlassPane));
                    }
                }
            }

            //If not hits, continue ray
            if (Hits.Count == 0)
            {
                Segments.Add(new RaySegment(Position, Position + Vector));
            }

            //If any hits, find closest one and handle it
            else
            {
                Tuple <Vector, Manipulator> Closest = Hits.OrderBy(x => (x.Item1 - Position).Magnitude).First();

                //If hit Mirror, reflection
                if (Closest.Item2 is Mirror)
                {
                    Mirror Hit    = Closest.Item2 as Mirror;
                    Vector Normal = new Vector((Hit.B.Y - Hit.A.Y), -(Hit.B.X - Hit.A.X));
                    Normal = Normal.Normalized;

                    Vector Reflection = Direction - 2 * (Direction.X * Normal.X + Direction.Y * Normal.Y) * Normal;

                    Segments.Add(new RaySegment(Position, Closest.Item1));
                    Propagate(Closest.Item1, Reflection, Hit, InMaterial);
                    return;
                }

                //If hit GlassPane, refraction
                if (Closest.Item2 is GlassPane)
                {
                    GlassPane Hit    = Closest.Item2 as GlassPane;
                    Vector    Normal = new Vector((Hit.B.Y - Hit.A.Y), -(Hit.B.X - Hit.A.X));
                    Normal = Normal.Normalized;

                    //Handle going in and out of materials
                    double OutAngle = 0;
                    double IndexA   = 0;
                    double IndexB   = 0;
                    if (InMaterial)
                    {
                        IndexA = Hit.RefractiveIndex;
                        IndexB = 1;
                    }
                    else
                    {
                        IndexA = 1;
                        IndexB = Hit.RefractiveIndex;
                    }

                    //If flipped
                    if (MathUtil.Dot(Normal, Direction) < 0)
                    {
                        Normal.X = -Normal.X;
                        Normal.Y = -Normal.Y;

                        double InAngle =
                            Math.Acos(MathUtil.Dot(Closest.Item1 - Position, Normal)
                                      / MathUtil.Magnitude(Closest.Item1 - Position)
                                      * MathUtil.Magnitude(Normal));

                        double SinValue = Math.Sin(InAngle) * IndexA / IndexB;

                        //Total inner reflection
                        if (SinValue > 1)
                        {
                            Vector Reflection = Direction - 2 * (Direction.X * Normal.X + Direction.Y * Normal.Y) * Normal;
                            OutAngle = Math.Atan2(Reflection.Y, Reflection.X);
                        }
                        //Refraction
                        else
                        {
                            InMaterial = !InMaterial;
                            OutAngle   = Math.Asin(SinValue);

                            if (MathUtil.Dot(Hit.B - Hit.A, Closest.Item1 - Position) > 0)
                            {
                                OutAngle = Math.Atan2(Normal.Y, Normal.X) - OutAngle;
                            }
                            else
                            {
                                OutAngle += Math.Atan2(Normal.Y, Normal.X);
                            }
                        }
                    }
                    else
                    {
                        double InAngle =
                            Math.Acos(MathUtil.Dot(Closest.Item1 - Position, Normal)
                                      / MathUtil.Magnitude(Closest.Item1 - Position)
                                      * MathUtil.Magnitude(Normal));

                        double SinValue = Math.Sin(InAngle) * IndexA / IndexB;
                        //Total inner reflection
                        if (SinValue > 1)
                        {
                            Vector Reflection = Direction - 2 * (Direction.X * Normal.X + Direction.Y * Normal.Y) * Normal;
                            OutAngle = Math.Atan2(Reflection.Y, Reflection.X);
                        }
                        //Refraction
                        else
                        {
                            InMaterial = !InMaterial;
                            OutAngle   = Math.Asin(SinValue);
                            if (MathUtil.Dot(Hit.B - Hit.A, Closest.Item1 - Position) > 0)
                            {
                                OutAngle += Math.Atan2(Normal.Y, Normal.X);
                            }
                            else
                            {
                                OutAngle = Math.Atan2(Normal.Y, Normal.X) - OutAngle;
                            }
                        }
                    }

                    Segments.Add(new RaySegment(Position, Closest.Item1));
                    Propagate(Closest.Item1, new Vector(Math.Cos(OutAngle), Math.Sin(OutAngle)), Hit, InMaterial);
                }
            }
        }