public Promise Play()
 {
     introDeferred = Deferred.Create();
     SpaceTime.QueueAction("GameIntro", PlaySceneInternal);
     SpaceTime.Start("PowerArgsGameIntro");
     return(introDeferred.Promise);
 }
Exemple #2
0
 public Promise Play()
 {
     introDeferred = Deferred.Create();
     SpaceTime.QueueAction(PlaySceneInternal);
     SpaceTime.Start();
     return(introDeferred.Promise);
 }
Exemple #3
0
        public async Task TestSpaceTimeAsynchronousExceptionDoASAPInFinally()
        {
            var message = "Plain old Exception";
            var st      = new SpaceTime(80, 40);

            st.Invoke(async() =>
            {
                try
                {
                    await TaskEx.WhenAny(Task.Delay(100), Task.Delay(10));
                }
                finally
                {
                    throw new Exception(message);
                }
            });
            bool handled = false;

            try
            {
                await st.Start();
            }catch (Exception exc)
            {
                var ex = exc.Clean().Single();
                Assert.AreEqual(message, ex.Message);
                handled = true;
            }
            Assert.IsTrue(handled);
        }
 public Task Play()
 {
     introDeferred = new TaskCompletionSource <bool>();
     SpaceTime.InvokeNextCycle(PlaySceneInternal);
     SpaceTime.Start();
     return(introDeferred.Task);
 }
        private void ListenForCharacterNearRightEdge()
        {
            SpaceTime.Invoke(async() =>
            {
                while (SpaceTime.IsRunning)
                {
                    if (character.Left > Width - 2)
                    {
                        // turn the character around so he now moves to the left
                        character.Velocity.Speed = 8;
                        character.Velocity.Angle = 180;
                        // drop a timed mine
                        var dropper = new TimedMineDropper()
                        {
                            Delay = TimeSpan.FromSeconds(4), AmmoAmount = 1, Holder = character
                        };
                        dropper.Exploded.SubscribeOnce(() => Sound.Play("PowerArgsIntro"));
                        dropper.FireInternal(false);

                        // eventually he will hit the left wall, remove him when that happens
                        character.Velocity.ImpactOccurred.SubscribeForLifetime((i) => character.Lifetime.Dispose(), character.Lifetime);

                        // this watcher has done its job, stop watching the secne
                        break;
                    }
                    await SpaceTime.YieldAsync();
                }
            });
        }
Exemple #6
0
        private void ListenForCharacterNearRightEdge()
        {
            ITimeFunction watcher = null;

            watcher = TimeFunction.Create(() =>
            {
                if (character.Left > Width - 2)
                {
                    // turn the character around so he now moves to the left
                    character.Speed.SpeedX = -8;

                    // drop a timed mine
                    var dropper = new TimedMineDropper()
                    {
                        Delay = TimeSpan.FromSeconds(4), AmmoAmount = 1, Holder = character
                    };
                    dropper.Exploded.SubscribeOnce(() => Sound.Play("PowerArgsIntro"));
                    dropper.FireInternal();

                    // eventually he will hit the left wall, remove him when that happens
                    character.Speed.ImpactOccurred.SubscribeForLifetime((i) => character.Lifetime.Dispose(), character.Lifetime);

                    // this watcher has done its job, stop watching the secne
                    watcher.Lifetime.Dispose();
                }
            });
            SpaceTime.Add(watcher);
        }
Exemple #7
0
        public static Sun SolarPA(SpaceTime spaceTime)

        {
            SPA.SPAData spa = new SPA.SPAData
            {
                Year         = spaceTime.Year,
                Month        = spaceTime.Month,
                Day          = spaceTime.Day,
                Hour         = spaceTime.Hour,
                Minute       = spaceTime.Minute,
                Second       = spaceTime.Second,
                Timezone     = spaceTime.Location.UtcOffset,
                DeltaUt1     = 0,
                DeltaT       = 67,
                Longitude    = spaceTime.Location.Longitude,
                Latitude     = spaceTime.Location.Latitude,
                Elevation    = spaceTime.Location.Elevation,
                Pressure     = 820,
                Temperature  = 11,
                Slope        = 0,
                AzmRotation  = 0,
                AtmosRefract = 0.5667,
                Function     = SPA.CalculationMode.SPA_ALL
            };

            var result = SPA.SPACalculate(ref spa);

            return(new Sun {
                Altitude = 90 - spa.Zenith, Azimuth = spa.Azimuth, Sunrise = spa.Sunrise, Sunset = spa.Sunset
            });
        }
Exemple #8
0
        /***************************************************/
        /**** Public Methods                            ****/
        /***************************************************/

        /*[Description("DailyPath")]
         * [Input("sun", "Sun position")]
         * [Output("SolarVector", "The sun vector calculated position")]
         * public static Circle DailyPath(this SpaceTime spaceTime)
         * {
         *  double[] hours = { 0, 11.9, 12 };
         *  List<Point> sunPositions = new List<Point>();
         *  bool validCircle = false;
         *
         *  foreach (double hour in hours)
         *  {
         *      int h = (int)hour;
         *      int m = (int)(hour - (double)h) * 60;
         *      spaceTime.Hour = h;
         *      spaceTime.Minute = m;
         *      Sun sun = spaceTime.SolarPosition();
         *
         *      Point sunPosition = Geometry.Create.Point(sun.SolarVector());
         *      sunPositions.Add(sunPosition);
         *      if (sunPosition.Z > 0)
         *          validCircle = true;
         *  }
         *
         *  if (validCircle)
         *  {
         *
         *      Circle circle = Geometry.Create.Circle(sunPositions[0], sunPositions[1], sunPositions[2]);
         *      return circle;
         *  }
         *  Circle circlea = new Circle();
         *  return circlea;
         *
         * }
         *
         * public static ICurve DailyPath(SpaceTime spaceTime)
         * {
         *
         *  List<Point> sunPositions = new List<Point>();
         *  bool isCircle = false;
         *
         *  Sun sun = SolarPA(spaceTime);
         *  if (sun.Sunrise < 0)
         *  {
         *      isCircle = true;
         *      sun.Sunrise = 0.1;
         *      sun.Sunset = 23.9;
         *  }
         *  double midday = (sun.Sunset - sun.Sunrise)/ 2 + sun.Sunrise;
         *  double[] hours = { sun.Sunset, midday, sun.Sunrise };
         *
         *  foreach (double hour in hours)
         *  {
         *      TimeSpan time = TimeSpan.FromHours(hour);
         *      spaceTime.Hour = time.Hours;
         *      spaceTime.Minute = time.Minutes;
         *      spaceTime.Second = time.Seconds;
         *      spaceTime.Millisecond = time.Milliseconds;
         *
         *      Sun ssun = SolarPA(spaceTime);
         *
         *      Point sunPosition = Geometry.Create.Point(ssun.SolarVector());
         *      sunPositions.Add(sunPosition);
         *  }
         *
         *  if (isCircle)
         *  {
         *      Circle circle = Geometry.Create.Circle(sunPositions[0], sunPositions[1], sunPositions[2]);
         *      return circle;
         *  }
         *  else
         *  {
         *      Arc arc = Geometry.Create.Arc(sunPositions[0], sunPositions[1], sunPositions[2]);
         *      return arc;
         *  }
         *
         * }
         *
         */
        public static ICurve DailyPath(this SpaceTime spaceTime)
        {
            double[]     hours        = { 0, 11.9, 12 };
            List <Point> sunPositions = new List <Point>();
            bool         validCircle  = false;

            foreach (double hour in hours)
            {
                TimeSpan time = TimeSpan.FromHours(hour);
                spaceTime.Hour        = time.Hours;
                spaceTime.Minute      = time.Minutes;
                spaceTime.Second      = time.Seconds;
                spaceTime.Millisecond = time.Milliseconds;
                Sun sun = SolarPA(spaceTime);

                Point sunPosition = Geometry.Create.Point(sun.SolarVector());
                sunPositions.Add(sunPosition);
                if (sunPosition.Z > 0)
                {
                    validCircle = true;
                }
            }

            if (validCircle)
            {
                Circle circle = Geometry.Create.Circle(sunPositions[0], sunPositions[1], sunPositions[2]);
                return(circle);
            }
            Circle circlea = new Circle();

            return(circlea);
        }
Exemple #9
0
        public async Task TestSpaceTimeAsynchronousExceptionQueueAction()
        {
            using (var lt = new Lifetime())
            {
                var message = "Plain old Exception";
                var st      = new SpaceTime(80, 40);
                st.InvokeNextCycle(async() =>
                {
                    await Task.Yield();
                    throw new Exception(message);
                });
                bool handled = false;

                try
                {
                    await st.Start();
                }catch (Exception exc)
                {
                    var ex = exc.Clean().Single();
                    Assert.AreEqual(message, ex.Message);
                    handled = true;
                }
                Assert.IsTrue(handled);
            }
        }
Exemple #10
0
        public static List <ICurve> HourPath(SpaceTime spaceTime)
        {
            List <ICurve> paths = new List <ICurve>();

            for (int h = 0; h <= 23; ++h)
            {
                List <Point3d> sunPositions = new List <Point3d>();
                for (int m = 1; m <= 12; ++m)
                {
                    spaceTime.Day   = 21;
                    spaceTime.Month = m;
                    spaceTime.Hour  = h;
                    Sun ss = SolarPA(spaceTime);

                    Point   sunPosition   = Geometry.Create.Point(ss.SolarVector());
                    Point3d sunPosition3d = Rhinoceros.Convert.ToRhino(sunPosition);
                    sunPositions.Add(sunPosition3d);
                }
                sunPositions.Add(sunPositions[0]);
                Rhino.Geometry.CurveKnotStyle nnotStyle = Rhino.Geometry.CurveKnotStyle.UniformPeriodic;
                Curve  crv  = Curve.CreateInterpolatedCurve(sunPositions, 3, nnotStyle);
                ICurve crvB = Rhinoceros.Convert.ToBHoM(crv);
                paths.Add(crvB);
            }
            return(paths);
        }
        public static void generateVideoForEvaluation(List <Image> Images, List <DateTime> dateTimeList, MultiObjectTrackingResult ctts, String videoName, String directory)
        {
            List <Image> imagesWithTracks = new List <Image>();

            for (int i = 0; i < Images.Count; i++)
            {
                List <BoundingBox> locations = new List <BoundingBox>();
                List <string>      labels    = new List <string>();
                Dictionary <string, List <bool> > attributes = new Dictionary <string, List <bool> >();
                attributes.Add("occlusion", new List <bool>());

                if (ctts.tracks.Count != 0)
                {
                    foreach (string key in ctts.tracks[0].booleanAttributeTracks.Keys)
                    {
                        if (!attributes.ContainsKey(key))
                        {
                            attributes.Add(key, new List <bool>());
                        }
                    }
                }

                List <int> idx = new List <int>();

                for (int j = 0; j < ctts.tracks.Count; j++)
                {
                    CompressedTrack ct = ctts.tracks[j];
                    SpaceTime       st = ct.getSpaceTimeAt(dateTimeList[i]);

                    BooleanAttribute outofview_attr = ct.getAttributeAt("outofview", dateTimeList[i]);
                    if (st != null && outofview_attr != null && !outofview_attr.value)
                    {
                        BoundingBox l = st.region;
                        locations.Add(l);
                        labels.Add(ctts.tracks[j].label);
                        foreach (string key in attributes.Keys)
                        {
                            attributes[key].Add(ct.getAttributeAt(key, dateTimeList[i]).value);
                        }

                        idx.Add(j);
                    }
                }
                Image new_image = generateTrackImage(Images[i], labels, locations, attributes, idx);
                imagesWithTracks.Add(new_image);
            }

            Console.WriteLine("Saving " + directory + "\\" + videoName);
            FFMpegWrappers.generateVideoFromFrames(imagesWithTracks, videoName, directory);

            //Directory.CreateDirectory(directory + "\\" + videoName);
            //Console.WriteLine("Saving " + directory + "\\" + videoName);
            //for (int i = 0; i < imagesWithTracks.Count; i++)
            //{

            //    imagesWithTracks[i].Save(directory + "\\" + videoName + "\\img" + i.ToString("000") + ".jpg");
            //}
            //Console.WriteLine("done");
        }
Exemple #12
0
        public static DateTime DateTime(this SpaceTime spaceTime)
        {
            if (spaceTime == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot query the date/time of a null space time object.");
                return(System.DateTime.Now);
            }

            return(spaceTime.Time.DateTime());
        }
Exemple #13
0
 private void ListenForEndOfIntro()
 {
     SpaceTime.Add(TimeFunction.Create(() =>
     {
         var remainingCount = SpaceTime.Elements.Where(e => e is FlammableLetter || e is Fire).Count();
         if (remainingCount == 0)
         {
             Cleanup();
         }
     }));
 }
Exemple #14
0
            public double getMetric(CompressedTrack t1, CompressedTrack t2, int fps)
            {
                TimeSpan dt = new TimeSpan(0, 0, 0, 0, (int)Math.Floor(1000.0 / fps));

                DateTime startTime1 = t1.startTime;
                DateTime startTime2 = t2.startTime;

                DateTime endTime1 = t1.endTime;
                DateTime endTime2 = t2.endTime;

                //is there any overlap at all?
                if (startTime1 > endTime2 || startTime2 > endTime1)
                {
                    return(0);
                }

                //find overlap times

                DateTime commonStartTime = startTime1;

                if (startTime2 > startTime1)
                {
                    commonStartTime = startTime2;
                }
                DateTime commonEndTime = endTime1;

                if (endTime2 < endTime1)
                {
                    commonEndTime = endTime2;
                }

                if (commonEndTime - commonStartTime < dt)
                {
                    return(0);
                }

                //now compute the integral

                double sum = 0;

                for (DateTime t = commonStartTime; t <= commonEndTime; t += dt)
                {
                    SpaceTime l1      = t1.getSpaceTimeAt(t);
                    SpaceTime l2      = t2.getSpaceTimeAt(t);
                    double    overlap = BoundingBox.ComputeOverlapAreaFraction(l1.region, l2.region);
                    sum += (overlap * dt.Milliseconds); //pixel-sec
                }
                TimeSpan deltat1 = endTime1 - startTime1;
                TimeSpan deltat2 = endTime2 - startTime2;
                double   max_ms  = Math.Max((double)deltat1.TotalMilliseconds, (double)deltat2.TotalMilliseconds);

                return(sum / max_ms);
            }
Exemple #15
0
        public static List <ICurve> MounthPaths(SpaceTime spaceTime)
        {
            List <ICurve> paths = new List <ICurve>();

            for (int m = 1; m <= 12; ++m)
            {
                spaceTime.Day   = 21;
                spaceTime.Month = m;
                ICurve path = DailyPath(spaceTime);
                paths.Add(path);
            }
            return(paths);
        }
 private void ListenForEndOfIntro()
 {
     SpaceTime.Invoke(async() =>
     {
         while (SpaceTime.IsRunning)
         {
             var remainingCount = SpaceTime.Elements.Where(e => e is FlammableLetter || e is Fire).Count();
             if (remainingCount == 0)
             {
                 Cleanup();
                 await SpaceTime.YieldAsync();
             }
         }
     });
 }
Exemple #17
0
        private void PlaySceneInternal()
        {
            // reveal the PowerArgs logo
            factory.InitializeScene(level).ForEach(e => SpaceTime.Add(e));
            // create the character
            character = new MainCharacter();
            // he starts a few pixels from the right edge
            character.MoveTo(Width - 7, 0);
            // he moves to the right
            character.Speed.SpeedX = 5;
            // he drops a timed mine and turns around when he gets near the right edge
            ListenForCharacterNearRightEdge();

            SpaceTime.Add(character);

            ListenForEndOfIntro();
        }
Exemple #18
0
        public static List <ICurve> MounthPaths(Location location)
        {
            List <ICurve> paths = new List <ICurve>();

            for (int m = 1; m <= 12; ++m)
            {
                SpaceTime spaceTime = new SpaceTime
                {
                    Location = location,
                    Day      = 21,
                    Year     = 2020,
                    Month    = m,
                };
                ICurve path = DailyPath(spaceTime);
                paths.Add(path);
            }
            return(paths);
        }
Exemple #19
0
        public async Task TestSpaceTimeSynchronousException()
        {
            var message = "Plain old Exception";
            var st      = new SpaceTime(80, 40);

            st.Invoke(() => throw new Exception(message));
            bool handled = false;

            try
            {
                await st.Start();
            }
            catch (Exception exc)
            {
                var ex = exc.Clean().Single();
                Assert.AreEqual(message, ex.Message);
                handled = true;
            }
            Assert.IsTrue(handled);
        }
        public void Cleanup()
        {
            if (SpaceTime.IsRunning == false)
            {
                return;
            }

            SpaceTime.Invoke(async() =>
            {
                if (introDeferred.Task.IsFulfilled())
                {
                    return;
                }

                SpaceTime.Elements.ToList().ForEach(e => e.Lifetime.Dispose());
                introDeferred.SetResult(true);
                SpaceTime.Stop();
                this.Dispose();
            });
        }
Exemple #21
0
        /***************************************************/
        /**** Public Methods                            ****/
        /***************************************************/

        public static AnalysisPeriod AnalysisPeriod(SpaceTime spaceTimeStart, SpaceTime spaceTimeEnd)
        {
            //DateTime startDateTime = Convert.ToDateTime(spaceTimeStart);
            //DateTime endDateTime = Convert.ToDateTime(spaceTimeEnd);
            DateTime   startDateTime = new DateTime(spaceTimeStart.Year, spaceTimeStart.Month, spaceTimeStart.Day, spaceTimeStart.Hour, spaceTimeStart.Minute, spaceTimeStart.Second, spaceTimeStart.Millisecond);
            DateTime   endDateTime   = new DateTime(spaceTimeEnd.Year, spaceTimeEnd.Month, spaceTimeEnd.Day, spaceTimeEnd.Hour, spaceTimeEnd.Minute, spaceTimeEnd.Second, spaceTimeEnd.Millisecond);
            PeriodType periodType;

            TimeSpan period = endDateTime - startDateTime;

            if (period.TotalHours < 0)
            {
                spaceTimeEnd = spaceTimeStart;
            }

            if (period.TotalHours >= 1)
            {
                if (period.TotalHours > 24)
                {
                    periodType = PeriodType.Period;
                }
                else
                {
                    periodType = PeriodType.Day;
                }
            }
            else
            {
                periodType = PeriodType.Point;
            }


            AnalysisPeriod analysisPeriod = new AnalysisPeriod
            {
                StartTime = spaceTimeStart,
                EndTime   = spaceTimeEnd,
                Type      = periodType
            };

            return(analysisPeriod);
        }
Exemple #22
0
        public void Cleanup()
        {
            if (SpaceTime.IsRunning == false)
            {
                return;
            }

            SpaceTime.QueueAction(() =>
            {
                if (introDeferred.IsFulfilled)
                {
                    return;
                }

                SpaceTime.Elements.ToList().ForEach(e => e.Lifetime.Dispose());
                SpaceTime.Stop()
                .Then(introDeferred.Resolve)
                .Fail((ex => introDeferred.Reject(ex)))
                .Finally((p) => this.Dispose());
            });
        }
Exemple #23
0
 void Rewind()
 {
     if (frame < 0)
     {
         if (frame == gameobject.GetComponent <TimeBody>().frame)
         {
             gameobject.GetComponent <forces>().stopRewind();
             GameObject.Find("speedSlider").GetComponent <time>().updateTimeScale(0f);
         }
         else
         {
             transform.position = new Vector3(-15, 0, -15);
         }
     }
     else
     {
         SpaceTime point = points[frame];
         transform.position = point.position;
         transform.rotation = point.rotation;
     }
 }
Exemple #24
0
        public void TestTimePerf()
        {
            var t   = new SpaceTime(80, 30, TimeSpan.FromSeconds(.05));
            var now = TimeSpan.Zero;

            t.Invoke(async() =>
            {
                for (var i = 0; i < 10000; i++)
                {
                    t.Add(new DummyFunction());
                }

                while (t.Now < TimeSpan.FromSeconds(100000))
                {
                    Assert.AreEqual(now, t.Now);
                    now = now.Add(t.Increment);
                    await t.YieldAsync();
                }
                t.Stop();
            });

            t.Start().Wait();
        }
Exemple #25
0
        public void TestCalculateLineOfSightRightToLeft()
        {
            var spaceTime = new SpaceTime(100, 100);

            spaceTime.QueueAction(() =>
            {
                var from  = PowerArgs.Cli.Physics.Rectangular.Create(10, 0, 1, 1);
                var to    = PowerArgs.Cli.Physics.Rectangular.Create(0, 0, 1, 1);
                var route = from.CalculateLineOfSight(to, 1);

                Assert.AreEqual(9, route.Steps.Count);
                Assert.AreEqual(0, route.Obstacles.Count);

                for (var i = 0; i < route.Steps.Count; i++)
                {
                    Assert.AreEqual(0, route.Steps[i].Top);      // make sure I'm travelling horizontally
                    Assert.AreEqual(9 - i, route.Steps[i].Left); // make sure I moved by 1 towards the target
                }

                spaceTime.Stop();
            });

            spaceTime.Start().Wait();
        }
Exemple #26
0
 public static DateTime DateTime(this SpaceTime spaceTime)
 {
     return(new DateTime(spaceTime.Year, spaceTime.Month, spaceTime.Day, spaceTime.Hour, spaceTime.Minute, spaceTime.Second, spaceTime.Millisecond));
 }
Exemple #27
0
            public double getMetric(CompressedTrack t1, CompressedTrack t2, int fps)
            {
                TimeSpan dt = new TimeSpan(0, 0, 0, 0, (int)Math.Floor(1000.0 / fps));

                DateTime startTime1 = t1.startTime;
                DateTime startTime2 = t2.startTime;

                DateTime endTime1 = t1.endTime;
                DateTime endTime2 = t2.endTime;

                //is there any overlap at all?
                if (startTime1 > endTime2 || startTime2 > endTime1)
                {
                    return(0);
                }

                //find overlap times

                DateTime commonStartTime = startTime1;

                if (startTime2 > startTime1)
                {
                    commonStartTime = startTime2;
                }
                DateTime commonEndTime = endTime1;

                if (endTime2 < endTime1)
                {
                    commonEndTime = endTime2;
                }

                if (commonEndTime - commonStartTime < dt)
                {
                    return(0);
                }

                //now compute the integral

                double IntersectionVolume = 0;

                for (DateTime t = commonStartTime; t <= commonEndTime; t += dt)
                {
                    SpaceTime l1      = t1.getSpaceTimeAt(t);
                    SpaceTime l2      = t2.getSpaceTimeAt(t);
                    double    overlap = BoundingBox.ComputeOverlapArea(l1.region, l2.region);
                    IntersectionVolume += (overlap * dt.Milliseconds);
                }

                double UnionVolume = 0;

                for (DateTime t = startTime1; t <= endTime1; t += dt)
                {
                    SpaceTime l1 = t1.getSpaceTimeAt(t);
                    UnionVolume += (l1.region.ComputeArea() * dt.Milliseconds);
                }
                for (DateTime t = startTime2; t <= endTime2; t += dt)
                {
                    SpaceTime l2 = t2.getSpaceTimeAt(t);
                    UnionVolume += (l2.region.ComputeArea() * dt.Milliseconds);
                }
                UnionVolume -= IntersectionVolume;

                return(IntersectionVolume / UnionVolume);
            }
Exemple #28
0
 void Record()
 {
     points[frame] = new SpaceTime(Arbies.velocity, transform.position, transform.rotation);
 }
Exemple #29
0
 public static DateTime DateTime(this SpaceTime spaceTime)
 {
     return(spaceTime.Time.DateTime());
 }
Exemple #30
0
        public static Sun SolarPosition(this SpaceTime spaceTime)
        {
            double   latitude  = spaceTime.Location.Latitude;
            double   longitude = spaceTime.Location.Longitude;
            double   utcOffset = spaceTime.Location.UtcOffset;
            DateTime dt        = spaceTime.DateTime();

            double[][][] R_TERMS = new double[][][]
            {
                new double[][]
                {
                    new double[] { 100013989.0, 0, 0 },
                    new double[] { 1670700.0, 3.0984635, 6283.07585 },
                    new double[] { 13956.0, 3.05525, 12566.1517 },
                    new double[] { 3084.0, 5.1985, 77713.7715 },
                    new double[] { 1628.0, 1.1739, 5753.3849 },
                    new double[] { 1576.0, 2.8469, 7860.4194 },
                    new double[] { 925.0, 5.453, 11506.77 },
                    new double[] { 542.0, 4.564, 3930.21 },
                    new double[] { 472.0, 3.661, 5884.927 },
                    new double[] { 346.0, 0.964, 5507.553 },
                    new double[] { 329.0, 5.9, 5223.694 },
                    new double[] { 307.0, 0.299, 5573.143 },
                    new double[] { 243.0, 4.273, 11790.629 },
                    new double[] { 212.0, 5.847, 1577.344 },
                    new double[] { 186.0, 5.022, 10977.079 },
                    new double[] { 175.0, 3.012, 18849.228 },
                    new double[] { 110.0, 5.055, 5486.778 },
                    new double[] { 98, 0.89, 6069.78 },
                    new double[] { 86, 5.69, 15720.84 },
                    new double[] { 86, 1.27, 161000.69 },
                    new double[] { 65, 0.27, 17260.15 },
                    new double[] { 63, 0.92, 529.69 },
                    new double[] { 57, 2.01, 83996.85 },
                    new double[] { 56, 5.24, 71430.7 },
                    new double[] { 49, 3.25, 2544.31 },
                    new double[] { 47, 2.58, 775.52 },
                    new double[] { 45, 5.54, 9437.76 },
                    new double[] { 43, 6.01, 6275.96 },
                    new double[] { 39, 5.36, 4694 },
                    new double[] { 38, 2.39, 8827.39 },
                    new double[] { 37, 0.83, 19651.05 },
                    new double[] { 37, 4.9, 12139.55 },
                    new double[] { 36, 1.67, 12036.46 },
                    new double[] { 35, 1.84, 2942.46 },
                    new double[] { 33, 0.24, 7084.9 },
                    new double[] { 32, 0.18, 5088.63 },
                    new double[] { 32, 1.78, 398.15 },
                    new double[] { 28, 1.21, 6286.6 },
                    new double[] { 28, 1.9, 6279.55 },
                    new double[] { 26, 4.59, 10447.39 }
                },
                new double[][]
                {
                    new double[] { 103019.0, 1.10749, 6283.07585 },
                    new double[] { 1721.0, 1.0644, 12566.1517 },
                    new double[] { 702.0, 3.142, 0 },
                    new double[] { 32, 1.02, 18849.23 },
                    new double[] { 31, 2.84, 5507.55 },
                    new double[] { 25, 1.32, 5223.69 },
                    new double[] { 18, 1.42, 1577.34 },
                    new double[] { 10, 5.91, 10977.08 },
                    new double[] { 9, 1.42, 6275.96 },
                    new double[] { 9, 0.27, 5486.78 }
                },
                new double[][]
                {
                    new double[] { 4359.0, 5.7846, 6283.0758 },
                    new double[] { 124.0, 5.579, 12566.152 },
                    new double[] { 12, 3.14, 0 },
                    new double[] { 9, 3.63, 77713.77 },
                    new double[] { 6, 1.87, 5573.14 },
                    new double[] { 3, 5.47, 18849.23 }
                },
                new double[][]
                {
                    new double[] { 145.0, 4.273, 6283.076 },
                    new double[] { 7, 3.92, 12566.15 }
                },
                new double[][]
                {
                    new double[] { 4, 2.56, 6283.08 }
                }
            };
            int[]   r_subcount = { 40, 10, 6, 2, 1 };
            int[][] Y_TERMS    = new int[][]
            {
                new int[] { 0, 0, 0, 0, 1 },
                new int[] { -2, 0, 0, 2, 2 },
                new int[] { 0, 0, 0, 2, 2 },
                new int[] { 0, 0, 0, 0, 2 },
                new int[] { 0, 1, 0, 0, 0 },
                new int[] { 0, 0, 1, 0, 0 },
                new int[] { -2, 1, 0, 2, 2 },
                new int[] { 0, 0, 0, 2, 1 },
                new int[] { 0, 0, 1, 2, 2 },
                new int[] { -2, -1, 0, 2, 2 },
                new int[] { -2, 0, 1, 0, 0 },
                new int[] { -2, 0, 0, 2, 1 },
                new int[] { 0, 0, -1, 2, 2 },
                new int[] { 2, 0, 0, 0, 0 },
                new int[] { 0, 0, 1, 0, 1 },
                new int[] { 2, 0, -1, 2, 2 },
                new int[] { 0, 0, -1, 0, 1 },
                new int[] { 0, 0, 1, 2, 1 },
                new int[] { -2, 0, 2, 0, 0 },
                new int[] { 0, 0, -2, 2, 1 },
                new int[] { 2, 0, 0, 2, 2 },
                new int[] { 0, 0, 2, 2, 2 },
                new int[] { 0, 0, 2, 0, 0 },
                new int[] { -2, 0, 1, 2, 2 },
                new int[] { 0, 0, 0, 2, 0 },
                new int[] { -2, 0, 0, 2, 0 },
                new int[] { 0, 0, -1, 2, 1 },
                new int[] { 0, 2, 0, 0, 0 },
                new int[] { 2, 0, -1, 0, 1 },
                new int[] { -2, 2, 0, 2, 2 },
                new int[] { 0, 1, 0, 0, 1 },
                new int[] { -2, 0, 1, 0, 1 },
                new int[] { 0, -1, 0, 0, 1 },
                new int[] { 0, 0, 2, -2, 0 },
                new int[] { 2, 0, -1, 2, 1 },
                new int[] { 2, 0, 1, 2, 2 },
                new int[] { 0, 1, 0, 2, 2 },
                new int[] { -2, 1, 1, 0, 0 },
                new int[] { 0, -1, 0, 2, 2 },
                new int[] { 2, 0, 0, 2, 1 },
                new int[] { 2, 0, 1, 0, 0 },
                new int[] { -2, 0, 2, 2, 2 },
                new int[] { -2, 0, 1, 2, 1 },
                new int[] { 2, 0, -2, 0, 1 },
                new int[] { 2, 0, 0, 0, 1 },
                new int[] { 0, -1, 1, 0, 0 },
                new int[] { -2, -1, 0, 2, 1 },
                new int[] { -2, 0, 0, 0, 1 },
                new int[] { 0, 0, 2, 2, 1 },
                new int[] { -2, 0, 2, 0, 1 },
                new int[] { -2, 1, 0, 2, 1 },
                new int[] { 0, 0, 1, -2, 0 },
                new int[] { -1, 0, 1, 0, 0 },
                new int[] { -2, 1, 0, 0, 0 },
                new int[] { 1, 0, 0, 0, 0 },
                new int[] { 0, 0, 1, 2, 0 },
                new int[] { 0, 0, -2, 2, 2 },
                new int[] { -1, -1, 1, 0, 0 },
                new int[] { 0, 1, 1, 0, 0 },
                new int[] { 0, -1, 1, 2, 2 },
                new int[] { 2, -1, -1, 2, 2 },
                new int[] { 0, 0, 3, 2, 2 },
                new int[] { 2, -1, 0, 2, 2 },
            };
            double[][] PE_TERMS = new double[][]
            {
                new double[] { -171996, -174.2, 92025, 8.9 },
                new double[] { -13187, -1.6, 5736, -3.1 },
                new double[] { -2274, -0.2, 977, -0.5 },
                new double[] { 2062, 0.2, -895, 0.5 },
                new double[] { 1426, -3.4, 54, -0.1 },
                new double[] { 712, 0.1, -7, 0 },
                new double[] { -517, 1.2, 224, -0.6 },
                new double[] { -386, -0.4, 200, 0 },
                new double[] { -301, 0, 129, -0.1 },
                new double[] { 217, -0.5, -95, 0.3 },
                new double[] { -158, 0, 0, 0 },
                new double[] { 129, 0.1, -70, 0 },
                new double[] { 123, 0, -53, 0 },
                new double[] { 63, 0, 0, 0 },
                new double[] { 63, 0.1, -33, 0 },
                new double[] { -59, 0, 26, 0 },
                new double[] { -58, -0.1, 32, 0 },
                new double[] { -51, 0, 27, 0 },
                new double[] { 48, 0, 0, 0 },
                new double[] { 46, 0, -24, 0 },
                new double[] { -38, 0, 16, 0 },
                new double[] { -31, 0, 13, 0 },
                new double[] { 29, 0, 0, 0 },
                new double[] { 29, 0, -12, 0 },
                new double[] { 26, 0, 0, 0 },
                new double[] { -22, 0, 0, 0 },
                new double[] { 21, 0, -10, 0 },
                new double[] { 17, -0.1, 0, 0 },
                new double[] { 16, 0, -8, 0 },
                new double[] { -16, 0.1, 7, 0 },
                new double[] { -15, 0, 9, 0 },
                new double[] { -13, 0, 7, 0 },
                new double[] { -12, 0, 6, 0 },
                new double[] { 11, 0, 0, 0 },
                new double[] { -10, 0, 5, 0 },
                new double[] { -8, 0, 3, 0 },
                new double[] { 7, 0, -3, 0 },
                new double[] { -7, 0, 0, 0 },
                new double[] { -7, 0, 3, 0 },
                new double[] { -7, 0, 3, 0 },
                new double[] { 6, 0, 0, 0 },
                new double[] { 6, 0, -3, 0 },
                new double[] { 6, 0, -3, 0 },
                new double[] { -6, 0, 3, 0 },
                new double[] { -6, 0, 3, 0 },
                new double[] { 5, 0, 0, 0 },
                new double[] { -5, 0, 3, 0 },
                new double[] { -5, 0, 3, 0 },
                new double[] { -5, 0, 3, 0 },
                new double[] { 4, 0, 0, 0 },
                new double[] { 4, 0, 0, 0 },
                new double[] { 4, 0, 0, 0 },
                new double[] { -4, 0, 0, 0 },
                new double[] { -4, 0, 0, 0 },
                new double[] { -4, 0, 0, 0 },
                new double[] { 3, 0, 0, 0 },
                new double[] { -3, 0, 0, 0 },
                new double[] { -3, 0, 0, 0 },
                new double[] { -3, 0, 0, 0 },
                new double[] { -3, 0, 0, 0 },
                new double[] { -3, 0, 0, 0 },
                new double[] { -3, 0, 0, 0 },
                new double[] { -3, 0, 0, 0 },
            };
            double[][][] L_TERMS = new double[][][]
            {
                new double[][]
                {
                    new double[] { 175347046.0, 0, 0 },
                    new double[] { 3341656.0, 4.6692568, 6283.07585 },
                    new double[] { 34894.0, 4.6261, 12566.1517 },
                    new double[] { 3497.0, 2.7441, 5753.3849 },
                    new double[] { 3418.0, 2.8289, 3.5231 },
                    new double[] { 3136.0, 3.6277, 77713.7715 },
                    new double[] { 2676.0, 4.4181, 7860.4194 },
                    new double[] { 2343.0, 6.1352, 3930.2097 },
                    new double[] { 1324.0, 0.7425, 11506.7698 },
                    new double[] { 1273.0, 2.0371, 529.691 },
                    new double[] { 1199.0, 1.1096, 1577.3435 },
                    new double[] { 990, 5.233, 5884.927 },
                    new double[] { 902, 2.045, 26.298 },
                    new double[] { 857, 3.508, 398.149 },
                    new double[] { 780, 1.179, 5223.694 },
                    new double[] { 753, 2.533, 5507.553 },
                    new double[] { 505, 4.583, 18849.228 },
                    new double[] { 492, 4.205, 775.523 },
                    new double[] { 357, 2.92, 0.067 },
                    new double[] { 317, 5.849, 11790.629 },
                    new double[] { 284, 1.899, 796.298 },
                    new double[] { 271, 0.315, 10977.079 },
                    new double[] { 243, 0.345, 5486.778 },
                    new double[] { 206, 4.806, 2544.314 },
                    new double[] { 205, 1.869, 5573.143 },
                    new double[] { 202, 2.458, 6069.777 },
                    new double[] { 156, 0.833, 213.299 },
                    new double[] { 132, 3.411, 2942.463 },
                    new double[] { 126, 1.083, 20.775 },
                    new double[] { 115, 0.645, 0.98 },
                    new double[] { 103, 0.636, 4694.003 },
                    new double[] { 102, 0.976, 15720.839 },
                    new double[] { 102, 4.267, 7.114 },
                    new double[] { 99, 6.21, 2146.17 },
                    new double[] { 98, 0.68, 155.42 },
                    new double[] { 86, 5.98, 161000.69 },
                    new double[] { 85, 1.3, 6275.96 },
                    new double[] { 85, 3.67, 71430.7 },
                    new double[] { 80, 1.81, 17260.15 },
                    new double[] { 79, 3.04, 12036.46 },
                    new double[] { 75, 1.76, 5088.63 },
                    new double[] { 74, 3.5, 3154.69 },
                    new double[] { 74, 4.68, 801.82 },
                    new double[] { 70, 0.83, 9437.76 },
                    new double[] { 62, 3.98, 8827.39 },
                    new double[] { 61, 1.82, 7084.9 },
                    new double[] { 57, 2.78, 6286.6 },
                    new double[] { 56, 4.39, 14143.5 },
                    new double[] { 56, 3.47, 6279.55 },
                    new double[] { 52, 0.19, 12139.55 },
                    new double[] { 52, 1.33, 1748.02 },
                    new double[] { 51, 0.28, 5856.48 },
                    new double[] { 49, 0.49, 1194.45 },
                    new double[] { 41, 5.37, 8429.24 },
                    new double[] { 41, 2.4, 19651.05 },
                    new double[] { 39, 6.17, 10447.39 },
                    new double[] { 37, 6.04, 10213.29 },
                    new double[] { 37, 2.57, 1059.38 },
                    new double[] { 36, 1.71, 2352.87 },
                    new double[] { 36, 1.78, 6812.77 },
                    new double[] { 33, 0.59, 17789.85 },
                    new double[] { 30, 0.44, 83996.85 },
                    new double[] { 30, 2.74, 1349.87 },
                    new double[] { 25, 3.16, 4690.48 }
                },
                new double[][]
                {
                    new double[] { 628331966747.0, 0, 0 },
                    new double[] { 206059.0, 2.678235, 6283.07585 },
                    new double[] { 4303.0, 2.6351, 12566.1517 },
                    new double[] { 425.0, 1.59, 3.523 },
                    new double[] { 119.0, 5.796, 26.298 },
                    new double[] { 109.0, 2.966, 1577.344 },
                    new double[] { 93, 2.59, 18849.23 },
                    new double[] { 72, 1.14, 529.69 },
                    new double[] { 68, 1.87, 398.15 },
                    new double[] { 67, 4.41, 5507.55 },
                    new double[] { 59, 2.89, 5223.69 },
                    new double[] { 56, 2.17, 155.42 },
                    new double[] { 45, 0.4, 796.3 },
                    new double[] { 36, 0.47, 775.52 },
                    new double[] { 29, 2.65, 7.11 },
                    new double[] { 21, 5.34, 0.98 },
                    new double[] { 19, 1.85, 5486.78 },
                    new double[] { 19, 4.97, 213.3 },
                    new double[] { 17, 2.99, 6275.96 },
                    new double[] { 16, 0.03, 2544.31 },
                    new double[] { 16, 1.43, 2146.17 },
                    new double[] { 15, 1.21, 10977.08 },
                    new double[] { 12, 2.83, 1748.02 },
                    new double[] { 12, 3.26, 5088.63 },
                    new double[] { 12, 5.27, 1194.45 },
                    new double[] { 12, 2.08, 4694 },
                    new double[] { 11, 0.77, 553.57 },
                    new double[] { 10, 1.3, 6286.6 },
                    new double[] { 10, 4.24, 1349.87 },
                    new double[] { 9, 2.7, 242.73 },
                    new double[] { 9, 5.64, 951.72 },
                    new double[] { 8, 5.3, 2352.87 },
                    new double[] { 6, 2.65, 9437.76 },
                    new double[] { 6, 4.67, 4690.48 }
                },
                new double[][]
                {
                    new double[] { 52919.0, 0, 0 },
                    new double[] { 8720.0, 1.0721, 6283.0758 },
                    new double[] { 309.0, 0.867, 12566.152 },
                    new double[] { 27, 0.05, 3.52 },
                    new double[] { 16, 5.19, 26.3 },
                    new double[] { 16, 3.68, 155.42 },
                    new double[] { 10, 0.76, 18849.23 },
                    new double[] { 9, 2.06, 77713.77 },
                    new double[] { 7, 0.83, 775.52 },
                    new double[] { 5, 4.66, 1577.34 },
                    new double[] { 4, 1.03, 7.11 },
                    new double[] { 4, 3.44, 5573.14 },
                    new double[] { 3, 5.14, 796.3 },
                    new double[] { 3, 6.05, 5507.55 },
                    new double[] { 3, 1.19, 242.73 },
                    new double[] { 3, 6.12, 529.69 },
                    new double[] { 3, 0.31, 398.15 },
                    new double[] { 3, 2.28, 553.57 },
                    new double[] { 2, 4.38, 5223.69 },
                    new double[] { 2, 3.75, 0.98 }
                },
                new double[][]
                {
                    new double[] { 289.0, 5.844, 6283.076 },
                    new double[] { 35, 0, 0 },
                    new double[] { 17, 5.49, 12566.15 },
                    new double[] { 3, 5.2, 155.42 },
                    new double[] { 1, 4.72, 3.52 },
                    new double[] { 1, 5.3, 18849.23 },
                    new double[] { 1, 5.97, 242.73 }
                },
                new double[][]
                {
                    new double[] { 114.0, 3.142, 0 },
                    new double[] { 8, 4.13, 6283.08 },
                    new double[] { 1, 3.84, 12566.15 }
                },
                new double[][]
                {
                    new double[] { 1, 3.14, 0 }
                }
            };
            int[]        l_subcount = { 64, 34, 20, 7, 3, 1 };
            double[][][] B_TERMS    = new double[][][]
            {
                new double[][]
                {
                    new double[] { 280.0, 3.199, 84334.662 },
                    new double[] { 102.0, 5.422, 5507.553 },
                    new double[] { 80, 3.88, 5223.69 },
                    new double[] { 44, 3.7, 2352.87 },
                    new double[] { 32, 4, 1577.34 }
                },
                new double[][]
                {
                    new double[] { 9, 3.9, 5507.55 },
                    new double[] { 6, 1.73, 5223.69 }
                }
            };
            int[] b_subcount = { 5, 2 };

            double PI = 3.1415926535897932384626433832795028841971;

            double julianDay                = JulianDay(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, utcOffset);
            double julianCentury            = (julianDay - 2451545.0) / 36525.0;
            double julianEphemerisDay       = julianDay; // / 86400.0;
            double julianEphemerisCentury   = (julianEphemerisDay - 2451545.0) / 36525.0;
            double julianEphemerisMillenium = (julianEphemerisCentury / 10.0);

            //EarthRadiusVector
            double[] sum = new double[5];
            for (int x2 = 0; x2 < 5; x2++)
            {
                double s = 0;
                for (int y2 = 0; y2 < r_subcount[x2]; y2++)
                {
                    s += R_TERMS[x2][y2][0] * Math.Cos(R_TERMS[x2][y2][1] + R_TERMS[x2][y2][2] * julianEphemerisMillenium);
                }
                sum[x2] = s;
            }
            //Earth Values
            double R = 0;

            for (int x3 = 0; x3 < 5; x3++)
            {
                R += sum[x3] * Math.Pow(julianEphemerisMillenium, x3);
            }
            R /= 1.0e8;

            double[] meanTerms = new double[5];
            meanTerms[0] = ThirdOrderPolynomial(1.0 / 189474.0, -0.0019142, 445267.11148, 297.85036, julianEphemerisCentury); //MeanElongationMoonSun
            meanTerms[1] = ThirdOrderPolynomial(-1.0 / 300000.0, -0.0001603, 35999.05034, 357.52772, julianEphemerisCentury); //MeanAnomalySun
            meanTerms[2] = ThirdOrderPolynomial(1.0 / 56250.0, 0.0086972, 477198.867398, 134.96298, julianEphemerisCentury);  //MeanAnomalyMoon
            meanTerms[3] = ThirdOrderPolynomial(1.0 / 327270.0, -0.0036825, 483202.017538, 93.27191, julianEphemerisCentury); //ArgumentLatitudeMoon
            meanTerms[4] = ThirdOrderPolynomial(1.0 / 450000.0, 0.0020708, -1934.136261, 125.04452, julianEphemerisCentury);  //AscendingLongitudeMoon

            //Nutation Longitude and Obliquity
            double delPsi     = 0;
            double delEpsilon = 0;

            for (int x4 = 0; x4 < 63; x4++)
            {
                double xyTermSummation = 0;
                for (int y3 = 0; y3 < meanTerms.Length; y3++)
                {
                    xyTermSummation += meanTerms[y3] * Y_TERMS[x4][y3];
                }
                xyTermSummation = Convert.ToRadians(xyTermSummation, PI);
                delPsi         += (PE_TERMS[x4][0] + julianEphemerisCentury * PE_TERMS[x4][1]) * Math.Sin(xyTermSummation);
                delEpsilon     += (PE_TERMS[x4][2] + julianEphemerisCentury * PE_TERMS[x4][3]) * Math.Cos(xyTermSummation);
            }
            delPsi     /= 36000000.0;
            delEpsilon /= 36000000.0;

            double u        = julianEphemerisMillenium / 10;
            double epsilon0 = 84381.448 + u * (-4680.93 + u * (-1.55 + u * (1999.25 + u * (-51.38 + u * (-249.67 + u * (-39.05 + u * (7.12 + u * (27.87 + u * (5.79 + u * 2.45))))))))); //EclipticMeanObliquity
            double epsilon  = delEpsilon + epsilon0 / 3600.0;                                                                                                                            //EclipticTrueObliquity

            //Greenwich Mean Sidereal Time
            double nu0 = 280.46061837 + 360.98564736629 * (julianDay - 2451545.0) + julianCentury * julianCentury * (0.000387933 - julianCentury / 38710000.0);

            nu0 /= 360;
            double limit = 360 * (nu0 - Math.Floor(nu0));

            if (limit < 0)
            {
                limit += 360;
            }
            nu0 = limit;

            double nu = nu0 + delPsi * Math.Cos(Convert.ToRadians(epsilon, PI)); //Greenwich Sidereal Time

            //EarthHeliocentricLongitude
            double l = 0;

            double[] sum2 = new double[6];
            for (int x5 = 0; x5 < sum2.Length; x5++)
            {
                for (int y5 = 0; y5 < l_subcount[x5]; y5++)
                {
                    sum2[x5] += L_TERMS[x5][y5][0] * Math.Cos(L_TERMS[x5][y5][1] + L_TERMS[x5][y5][2] * julianEphemerisMillenium);
                }
            }
            for (int x6 = 0; x6 < sum2.Length; x6++)
            {
                l += sum2[x6] * Math.Pow(julianEphemerisMillenium, x6);
            }
            l    /= 1.0e8;
            l     = Convert.ToDegrees(l, PI);
            l    /= 360;
            limit = 360 * (l - Math.Floor(l));
            if (limit < 0)
            {
                limit += 360;
            }
            l = limit;

            //EarthHeliocentricLatitude
            double b = 0;

            sum2 = new double[2];
            for (int x7 = 0; x7 < sum2.Length; x7++)
            {
                for (int y7 = 0; y7 < b_subcount[x7]; y7++)
                {
                    sum2[x7] += B_TERMS[x7][y7][0] * Math.Cos(B_TERMS[x7][y7][1] + B_TERMS[x7][y7][2] * julianEphemerisMillenium);
                }
            }
            for (int x8 = 0; x8 < sum2.Length; x8++)
            {
                b += sum2[x8] * Math.Pow(julianEphemerisMillenium, x8);
            }
            b /= 1.0e8;
            b  = Convert.ToDegrees(b, PI);

            //GeocentricLongitude
            double theta = l + 180;

            if (theta >= 360)
            {
                theta -= 360;
            }

            //GeocentricLatitude
            double beta = -b;

            double delTau = -20.4898 / (3600.0 * R); //AberrationCorrection

            double lamba = theta + delPsi + delTau;  //ApparentSunLongitude

            //GeocentricRightAscension
            double alpha = Convert.ToDegrees(Math.Atan2(Math.Sin(Convert.ToRadians(lamba, PI)) * Math.Cos(Convert.ToRadians(epsilon, PI) - Math.Tan(Convert.ToRadians(beta, PI)) * Math.Sin(Convert.ToRadians(epsilon, PI))), Math.Cos(Convert.ToRadians(lamba, PI))), PI);

            alpha /= 360;
            limit  = 360 * (alpha - Math.Floor(alpha));
            if (limit < 0)
            {
                limit += 360;
            }
            alpha = limit;

            double delta = Convert.ToDegrees(Math.Asin(Math.Sin(Convert.ToRadians(beta, PI)) * Math.Cos(Convert.ToRadians(epsilon, PI)) + Math.Cos(Convert.ToRadians(beta, PI)) * Math.Sin(Convert.ToRadians(epsilon, PI) * Math.Sin(Convert.ToRadians(lamba, PI)))), PI); //GeocentricDeclination

            //Observe Hour Angle
            double H = nu + longitude - alpha;

            H    /= 360;
            limit = 360 * (H - Math.Floor(H));
            if (limit < 0)
            {
                limit += 360;
            }
            H = limit;

            double xi = 8.794 / (3600.0 * R); //SunEquatorialHorizontalParallax

            //RightAscensionParallaxAndTopocentricDec
            double latRad   = Convert.ToRadians(latitude, PI);
            double xiRad    = Convert.ToRadians(xi, PI);
            double hRad     = Convert.ToRadians(H, PI);
            double deltaRad = Convert.ToRadians(delta, PI);
            double u2       = Math.Atan(0.99664719 * Math.Tan(latRad));
            double y        = 0.99664719 * Math.Sin(u2) * Math.Sin(latRad) / 6378140.0;
            double x        = Math.Cos(u2) * Math.Cos(latRad) / 6378140.0;

            var deltaAlphaRad = Math.Atan2(-x * Math.Sin(xiRad) * Math.Sin(hRad),
                                           Math.Cos(deltaRad) - x * Math.Sin(xiRad) * Math.Cos(hRad));

            double deltaPrime = Convert.ToDegrees(Math.Atan2((Math.Sin(deltaRad) - y * Math.Sin(xiRad)) * Math.Cos(deltaAlphaRad), Math.Cos(deltaRad) - x * Math.Sin(xiRad) * Math.Cos(hRad)), PI);
            double deltaAlpha = Convert.ToDegrees(deltaAlphaRad, PI);

            double hPrime = H - deltaAlpha; //TopocentricLocalHourAngle

            //TopocentricAzimuthAngleAstro
            double azimuthAstro = Convert.ToDegrees(Math.Atan2(Math.Sin(Convert.ToRadians(hPrime, PI)), Math.Cos(Convert.ToRadians(hPrime, PI)) * Math.Sin(Convert.ToRadians(latitude, PI)) - Math.Tan(Convert.ToRadians(deltaPrime, PI)) * Math.Cos(Convert.ToRadians(latitude, PI))), PI);

            azimuthAstro /= 360;
            limit         = 360 * (azimuthAstro - Math.Floor(azimuthAstro));
            if (limit < 0)
            {
                limit += 360;
            }
            azimuthAstro = limit;

            //TopocentricAzimuthAngle
            double azimuth = azimuthAstro + 180;

            azimuth /= 360;
            limit    = 360 * (azimuth - Math.Floor(azimuth));
            if (limit < 0)
            {
                limit += 360;
            }
            azimuth = limit;

            double e0 = Convert.ToDegrees(Math.Asin(Math.Sin(latRad) * Math.Sin(Convert.ToRadians(deltaPrime, PI)) + Math.Cos(latRad) * Math.Cos(Convert.ToRadians(deltaPrime, PI)) * Math.Cos(Convert.ToRadians(hPrime, PI))), PI); //TopocentricElevationAngle

            double zenith = 90.0 - e0;

            return(new Sun {
                Altitude = (90 - zenith), Azimuth = azimuth
            });
        }