diff --git a/CoordinateSharp/Celestial.Assistant.cs b/CoordinateSharp/Celestial.Assistant.cs
index f2cbfa4..b1e7493 100644
--- a/CoordinateSharp/Celestial.Assistant.cs
+++ b/CoordinateSharp/Celestial.Assistant.cs
@@ -2,1316 +2,1157 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
-namespace CoordinateSharp
-{
- internal partial class MeeusTables
- {
-
- ///
- /// Returns Moon Periodic Value Er
- ///
- /// Moon's mean elongation
- /// Sun's mean anomaly
- /// Moon's mean anomaly
- /// Moon's argument of latitude
- /// Dynamic time
- /// Er
- public static double Moon_Periodic_Er(double D, double M, double N, double F, double T)
- {
- //Table 47A contains 60 lines to sum
- double[] values = new double[] { D, M, N, F };
- double sum = 0;
- for (int x = 0; x < 60; x++)
- {
- sum += Get_Table47A_Values(values, x, T, false);
- }
- return sum;
- }
- ///
- /// Returns Moon Periodic Value El
- ///
- /// Moon's mean longitude
- /// Moon's mean elongation
- /// Sun's mean anomaly
- /// Moon's mean anomaly
- /// Moon's argument of latitude
- /// Dynamic time
- /// El
- public static double Moon_Periodic_El(double L, double D, double M, double N, double F, double T)
- {
- //Table 47A contains 60 lines to sum
- double[] values = new double[] { D, M, N, F };
- double sum = 0;
- for (int x = 0; x < 60; x++)
- {
- sum += Get_Table47A_Values(values, x, T, true);
- }
+namespace CoordinateSharp {
+ internal partial class MeeusTables {
- //Planetary adjustments
- double A1 = 119.75 + 131.849 * T;
- double A2 = 53.09 + 479264.290 * T;
-
- //Normalize 0-360 degree number
- A1 %= 360;
- if (A1 < 0) { A1 += 360; }
- A2 %= 360;
- if (A2 < 0) { A2 += 360; }
-
- //Convert DMF to radians
- A1 = A1 * Math.PI / 180;
- A2 = A2 * Math.PI / 180;
-
- //L TO RADIANS
- L %= 360;
- if (L < 0) { L += 360; }
-
- //Convert DMF to radians
- L = L * Math.PI / 180;
-
- sum += 3958 * Math.Sin(A1);
- sum += 1962 * Math.Sin(L - F);
- sum += 318 * Math.Sin(A2);
-
- return sum;
- }
- ///
- /// Returns Moon Periodic Value Eb
- ///
- /// Moon's mean longitude
- /// Moon's mean elongation
- /// Sun's mean anomaly
- /// Moon's mean anomaly
- /// Moon's argument of latitude
- /// Dynamic time
- /// Eb
- public static double Moon_Periodic_Eb(double L, double D, double M, double N, double F, double T)
- {
- //Table 47B contains 60 lines to sum
- double[] values = new double[] { D, M, N, F };
- double sum = 0;
- for (int x = 0; x < 60; x++)
- {
- sum += Get_Table47B_Values(values, x, T);
- }
-
- //Planetary adjustments
- double A1 = 119.75 + 131.849 * T;
- double A3 = 313.45 + 481266.484 * T;
-
- //Normalize 0-360 degree number
- A1 %= 360;
- if (A1 < 0) { A1 += 360; }
- A3 %= 360;
- if (A3 < 0) { A3 += 360; }
-
- //Convert DMF to radians
- A1 = A1 * Math.PI / 180;
- A3 = A3 * Math.PI / 180;
-
- //L TO RADIANS
- L %= 360;
- if (L < 0) { L += 360; }
-
- //Convert DMF to radians
- L = L * Math.PI / 180;
-
- sum += -2235 * Math.Sin(L);
- sum += 382 * Math.Sin(A3);
- sum += 175 * Math.Sin(A1 - F);
- sum += 175 * Math.Sin(A1 + F);
- sum += 127 * Math.Sin(L - M);
- sum += -115 * Math.Sin(L + M);
-
- return sum;
- }
- //Ch 50
- ///
- /// Sum of Apogee Terms from Jean Meeus Astronomical Algorithms Table 50.A
- ///
- /// Moom's mean elongation at time JDE
- /// Sun's mean anomaly
- /// Moon's arguement f latitude
- /// Time in Julian centuries since epoch 2000
- /// double
- public static double ApogeeTermsA(double D, double M, double F, double T)
- {
- double sum;
-
- sum = Math.Sin(2 * D) * 0.4392;
- sum += Math.Sin(4 * D) * 0.0684;
- sum += Math.Sin(M) * .0456 - 0.00011 * T;
- sum += Math.Sin(2 * D - M) * .0426 - 0.00011 * T;
- sum += Math.Sin(2 * F) * .0212;
- sum += Math.Sin(D) * -0.0189;
- sum += Math.Sin(6 * D) * .0144;
- sum += Math.Sin(4 * D - M) * .0113;
- sum += Math.Sin(2 * D + 2 * F) * .0047;
- sum += Math.Sin(D + M) * .0036;
- sum += Math.Sin(8 * D) * .0035;
- sum += Math.Sin(6 * D - M) * .0034;
- sum += Math.Sin(2 * D - 2 * F) * -0.0034;
- sum += Math.Sin(2 * D - 2 * M) * .0022;
- sum += Math.Sin(3 * D) * -.0017;
- sum += Math.Sin(4 * D + 2 * F) * 0.0013;
-
- sum += Math.Sin(8 * D - M) * .0011;
- sum += Math.Sin(4 * D - 2 * M) * .0010;
- sum += Math.Sin(10 * D) * .0009;
- sum += Math.Sin(3 * D + M) * .0007;
- sum += Math.Sin(2 * M) * .0006;
- sum += Math.Sin(2 * D + M) * .0005;
- sum += Math.Sin(2 * D + 2 * M) * .0005;
- sum += Math.Sin(6 * D + 2 * F) * .0004;
- sum += Math.Sin(6 * D - 2 * M) * .0004;
- sum += Math.Sin(10 * D - M) * .0004;
- sum += Math.Sin(5 * D) * -0.0004;
- sum += Math.Sin(4 * D - 2 * F) * -0.0004;
- sum += Math.Sin(2 * F + M) * .0003;
- sum += Math.Sin(12 * D) * .0003;
- sum += Math.Sin(2 * D + 2 * F - M) * 0.0003;
- sum += Math.Sin(D - M) * -0.0003;
- return sum;
- }
- ///
- /// Sum of Perigee Terms from Jean Meeus Astronomical Algorithms Table 50.A
- ///
- /// Moom's mean elongation at time JDE
- /// Sun's mean anomaly
- /// Moon's arguement f latitude
- /// Time in Julian centuries since epoch 2000
- /// double
- public static double PerigeeTermsA(double D, double M, double F, double T)
- {
- double sum;
-
- sum = Math.Sin(2 * D) * -1.6769;
- sum += Math.Sin(4 * D) * .4589;
- sum += Math.Sin(6 * D) * -.1856;
- sum += Math.Sin(8 * D) * .0883;
- sum += Math.Sin(2 * D - M) * -.0773 + .00019 * T;
- sum += Math.Sin(M) * .0502 - .00013 * T;
- sum += Math.Sin(10 * D) * -.0460;
- sum += Math.Sin(4 * D - M) * .0422 - .00011 * T;
- sum += Math.Sin(6 * D - M) * -.0256;
- sum += Math.Sin(12 * D) * .0253;
- sum += Math.Sin(D) * .0237;
- sum += Math.Sin(8 * D - M) * .0162;
- sum += Math.Sin(14 * D) * -.0145;
- sum += Math.Sin(2 * F) * .0129;
- sum += Math.Sin(3 * D) * -.0112;
- sum += Math.Sin(10 * D - M) * -.0104;
- sum += Math.Sin(16 * D) * .0086;
- sum += Math.Sin(12 * D - M) * .0069;
- sum += Math.Sin(5 * D) * .0066;
- sum += Math.Sin(2 * D + 2 * F) * -.0053;
- sum += Math.Sin(18 * D) * -.0052;
- sum += Math.Sin(14 * D - M) * -.0046;
- sum += Math.Sin(7 * D) * -.0041;
- sum += Math.Sin(2 * D + M) * .0040;
- sum += Math.Sin(20 * D) * .0032;
- sum += Math.Sin(D + M) * -.0032;
- sum += Math.Sin(16 * D - M) * .0031;
- sum += Math.Sin(4 * D + M) * -.0029;
- sum += Math.Sin(9 * D) * .0027;
- sum += Math.Sin(4 * D + 2 * F) * .0027;
-
- sum += Math.Sin(2 * D - 2 * M) * -.0027;
- sum += Math.Sin(4 * D - 2 * M) * .0024;
- sum += Math.Sin(6 * D - 2 * M) * -.0021;
- sum += Math.Sin(22 * D) * -.0021;
- sum += Math.Sin(18 * D - M) * -.0021;
- sum += Math.Sin(6 * D + M) * .0019;
- sum += Math.Sin(11 * D) * -.0018;
- sum += Math.Sin(8 * D + M) * -.0014;
- sum += Math.Sin(4 * D - 2 * F) * -.0014;
- sum += Math.Sin(6 * D + 2 * F) * -.0014;
- sum += Math.Sin(3 * D + M) * .0014;
- sum += Math.Sin(5 * D + M) * -.0014;
- sum += Math.Sin(13 * D) * .0013;
- sum += Math.Sin(20 * D - M) * .0013;
- sum += Math.Sin(3 * D + 2 * M) * .0011;
- sum += Math.Sin(4 * D + 2 * F - 2 * M) * -.0011;
- sum += Math.Sin(D + 2 * M) * -.0010;
- sum += Math.Sin(22 * D - M) * -.0009;
- sum += Math.Sin(4 * F) * -.0008;
- sum += Math.Sin(6 * D - 2 * F) * .0008;
- sum += Math.Sin(2 * D - 2 * F + M) * .0008;
- sum += Math.Sin(2 * M) * .0007;
- sum += Math.Sin(2 * F - M) * .0007;
- sum += Math.Sin(2 * D + 4 * F) * .0007;
- sum += Math.Sin(2 * F - 2 * M) * -.0006;
- sum += Math.Sin(2 * D - 2 * F + 2 * M) * -.0006;
- sum += Math.Sin(24 * D) * .0006;
- sum += Math.Sin(4 * D - 4 * F) * .0005;
- sum += Math.Sin(2 * D + 2 * M) * .0005;
- sum += Math.Sin(D - M) * -.0004;
-
- return sum;
- }
- ///
- /// Sum of Apogee Terms from Jean Meeus Astronomical Algorithms Table 50.B
- ///
- /// Moom's mean elongation at time JDE
- /// Sun's mean anomaly
- /// Moon's arguement f latitude
- /// Time in Julian centuries since epoch 2000
- /// double
- public static double ApogeeTermsB(double D, double M, double F, double T)
- {
- double sum = 3245.251;
-
- sum += Math.Cos(2 * D) * -9.147;
- sum += Math.Cos(D) * -.841;
- sum += Math.Cos(2 * F) * .697;
- sum += Math.Cos(M) * -0.656 + .0016 * T;
- sum += Math.Cos(4 * D) * .355;
- sum += Math.Cos(2 * D - M) * .159;
- sum += Math.Cos(D + M) * .127;
- sum += Math.Cos(4 * D - M) * .065;
-
- sum += Math.Cos(6 * D) * .052;
- sum += Math.Cos(2 * D + M) * .043;
- sum += Math.Cos(2 * D + 2 * F) * .031;
- sum += Math.Cos(2 * D - 2 * F) * -.023;
- sum += Math.Cos(2 * D - 2 * M) * .022;
- sum += Math.Cos(2 * D + 2 * M) * .019;
- sum += Math.Cos(2 * M) * -.016;
- sum += Math.Cos(6 * D - M) * .014;
- sum += Math.Cos(8 * D) * .010;
-
- return sum;
- }
- ///
- /// Sum of Perigee Terms from Jean Meeus Astronomical Algorithms Table 50.B
- ///
- /// Moom's mean elongation at time JDE
- /// Sun's mean anomaly
- /// Moon's arguement f latitude
- /// Time in Julian centuries since epoch 2000
- /// double
- public static double PerigeeTermsB(double D, double M, double F, double T)
- {
- //Sum of Perigee Terms from Jean Meeus Astronomical Algorithms Table 50.B
- double sum = 3629.215;
-
- sum += Math.Cos(2 * D) * 63.224;
- sum += Math.Cos(4 * D) * -6.990;
- sum += Math.Cos(2 * D - M) * 2.834 - .0071 * T;
- sum += Math.Cos(6 * D) * 1.927;
- sum += Math.Cos(D) * -1.263;
- sum += Math.Cos(8 * D) * -.702;
- sum += Math.Cos(M) * .696 - .0017 * T;
- sum += Math.Cos(2 * F) * -.690;
- sum += Math.Cos(4 * D - M) * -.629 + .0016 * T;
- sum += Math.Cos(2 * D - 2 * F) * -.392;
- sum += Math.Cos(10 * D) * .297;
- sum += Math.Cos(6 * D - M) * .260;
- sum += Math.Cos(3 * D) * .201;
- sum += Math.Cos(2 * D + M) * -.161;
- sum += Math.Cos(D + M) * .157;
- sum += Math.Cos(12 * D) * -.138;
- sum += Math.Cos(8 * D - M) * -.127;
- sum += Math.Cos(2 * D + 2 * F) * .104;
- sum += Math.Cos(2 * D - 2 * M) * .104;
- sum += Math.Cos(5 * D) * -.079;
- sum += Math.Cos(14 * D) * .068;
-
- sum += Math.Cos(10 * D - M) * .067;
- sum += Math.Cos(4 * D + M) * .054;
- sum += Math.Cos(12 * D - M) * -.038;
- sum += Math.Cos(4 * D - 2 * M) * -.038;
- sum += Math.Cos(7 * D) * .037;
- sum += Math.Cos(4 * D + 2 * F) * -.037;
- sum += Math.Cos(16 * D) * -.035;
- sum += Math.Cos(3 * D + M) * -.030;
- sum += Math.Cos(D - M) * .029;
- sum += Math.Cos(6 * D + M) * -.025;
- sum += Math.Cos(2 * M) * .023;
- sum += Math.Cos(14 * D - M) * .023;
- sum += Math.Cos(2 * D + 2 * M) * -.023;
- sum += Math.Cos(6 * D - 2 * M) * .022;
- sum += Math.Cos(2 * D - 2 * F - M) * -.021;
- sum += Math.Cos(9 * D) * -.020;
- sum += Math.Cos(18 * D) * .019;
- sum += Math.Cos(6 * D + 2 * F) * .017;
- sum += Math.Cos(2 * F - M) * .014;
- sum += Math.Cos(16 * D - M) * -.014;
- sum += Math.Cos(4 * D - 2 * F) * .013;
- sum += Math.Cos(8 * D + M) * .012;
- sum += Math.Cos(11 * D) * .011;
- sum += Math.Cos(5 * D + M) * .010;
- sum += Math.Cos(20 * D) * -.010;
-
- return sum;
- }
+ ///
+ /// Returns Moon Periodic Value Er
+ ///
+ /// Moon's mean elongation
+ /// Sun's mean anomaly
+ /// Moon's mean anomaly
+ /// Moon's argument of latitude
+ /// Dynamic time
+ /// Er
+ public static Double Moon_Periodic_Er(Double D, Double M, Double N, Double F, Double T) {
+ //Table 47A contains 60 lines to sum
+ Double[] values = new Double[] { D, M, N, F };
+ Double sum = 0;
+ for (Int32 x = 0; x < 60; x++) {
+ sum += Get_Table47A_Values(values, x, T, false);
+ }
+ return sum;
}
- internal class MeeusFormulas
- {
- public static double Get_Sidereal_Time(double JD)
- {
- //Ch. 12
- //T = Dynamic Time
- //Oo = mean sidereal time at Greenwich at 0h UT
- double T = (JD - 2451545) / 36525;
- double Oo = 280.46061837 + 360.98564736629 * (JD - 2451545) +
+ ///
+ /// Returns Moon Periodic Value El
+ ///
+ /// Moon's mean longitude
+ /// Moon's mean elongation
+ /// Sun's mean anomaly
+ /// Moon's mean anomaly
+ /// Moon's argument of latitude
+ /// Dynamic time
+ /// El
+ public static Double Moon_Periodic_El(Double L, Double D, Double M, Double N, Double F, Double T) {
+ //Table 47A contains 60 lines to sum
+ Double[] values = new Double[] { D, M, N, F };
+ Double sum = 0;
+ for (Int32 x = 0; x < 60; x++) {
+ sum += Get_Table47A_Values(values, x, T, true);
+ }
+
+ //Planetary adjustments
+ Double A1 = 119.75 + 131.849 * T;
+ Double A2 = 53.09 + 479264.290 * T;
+
+ //Normalize 0-360 degree number
+ A1 %= 360;
+ if (A1 < 0) { A1 += 360; }
+ A2 %= 360;
+ if (A2 < 0) { A2 += 360; }
+
+ //Convert DMF to radians
+ A1 = A1 * Math.PI / 180;
+ A2 = A2 * Math.PI / 180;
+
+ //L TO RADIANS
+ L %= 360;
+ if (L < 0) { L += 360; }
+
+ //Convert DMF to radians
+ L = L * Math.PI / 180;
+
+ sum += 3958 * Math.Sin(A1);
+ sum += 1962 * Math.Sin(L - F);
+ sum += 318 * Math.Sin(A2);
+
+ return sum;
+ }
+ ///
+ /// Returns Moon Periodic Value Eb
+ ///
+ /// Moon's mean longitude
+ /// Moon's mean elongation
+ /// Sun's mean anomaly
+ /// Moon's mean anomaly
+ /// Moon's argument of latitude
+ /// Dynamic time
+ /// Eb
+ public static Double Moon_Periodic_Eb(Double L, Double D, Double M, Double N, Double F, Double T) {
+ //Table 47B contains 60 lines to sum
+ Double[] values = new Double[] { D, M, N, F };
+ Double sum = 0;
+ for (Int32 x = 0; x < 60; x++) {
+ sum += Get_Table47B_Values(values, x, T);
+ }
+
+ //Planetary adjustments
+ Double A1 = 119.75 + 131.849 * T;
+ Double A3 = 313.45 + 481266.484 * T;
+
+ //Normalize 0-360 degree number
+ A1 %= 360;
+ if (A1 < 0) { A1 += 360; }
+ A3 %= 360;
+ if (A3 < 0) { A3 += 360; }
+
+ //Convert DMF to radians
+ A1 = A1 * Math.PI / 180;
+ A3 = A3 * Math.PI / 180;
+
+ //L TO RADIANS
+ L %= 360;
+ if (L < 0) { L += 360; }
+
+ //Convert DMF to radians
+ L = L * Math.PI / 180;
+
+ sum += -2235 * Math.Sin(L);
+ sum += 382 * Math.Sin(A3);
+ sum += 175 * Math.Sin(A1 - F);
+ sum += 175 * Math.Sin(A1 + F);
+ sum += 127 * Math.Sin(L - M);
+ sum += -115 * Math.Sin(L + M);
+
+ return sum;
+ }
+ //Ch 50
+ ///
+ /// Sum of Apogee Terms from Jean Meeus Astronomical Algorithms Table 50.A
+ ///
+ /// Moom's mean elongation at time JDE
+ /// Sun's mean anomaly
+ /// Moon's arguement f latitude
+ /// Time in Julian centuries since epoch 2000
+ /// double
+ public static Double ApogeeTermsA(Double D, Double M, Double F, Double T) {
+ Double sum;
+
+ sum = Math.Sin(2 * D) * 0.4392;
+ sum += Math.Sin(4 * D) * 0.0684;
+ sum += Math.Sin(M) * .0456 - 0.00011 * T;
+ sum += Math.Sin(2 * D - M) * .0426 - 0.00011 * T;
+ sum += Math.Sin(2 * F) * .0212;
+ sum += Math.Sin(D) * -0.0189;
+ sum += Math.Sin(6 * D) * .0144;
+ sum += Math.Sin(4 * D - M) * .0113;
+ sum += Math.Sin(2 * D + 2 * F) * .0047;
+ sum += Math.Sin(D + M) * .0036;
+ sum += Math.Sin(8 * D) * .0035;
+ sum += Math.Sin(6 * D - M) * .0034;
+ sum += Math.Sin(2 * D - 2 * F) * -0.0034;
+ sum += Math.Sin(2 * D - 2 * M) * .0022;
+ sum += Math.Sin(3 * D) * -.0017;
+ sum += Math.Sin(4 * D + 2 * F) * 0.0013;
+
+ sum += Math.Sin(8 * D - M) * .0011;
+ sum += Math.Sin(4 * D - 2 * M) * .0010;
+ sum += Math.Sin(10 * D) * .0009;
+ sum += Math.Sin(3 * D + M) * .0007;
+ sum += Math.Sin(2 * M) * .0006;
+ sum += Math.Sin(2 * D + M) * .0005;
+ sum += Math.Sin(2 * D + 2 * M) * .0005;
+ sum += Math.Sin(6 * D + 2 * F) * .0004;
+ sum += Math.Sin(6 * D - 2 * M) * .0004;
+ sum += Math.Sin(10 * D - M) * .0004;
+ sum += Math.Sin(5 * D) * -0.0004;
+ sum += Math.Sin(4 * D - 2 * F) * -0.0004;
+ sum += Math.Sin(2 * F + M) * .0003;
+ sum += Math.Sin(12 * D) * .0003;
+ sum += Math.Sin(2 * D + 2 * F - M) * 0.0003;
+ sum += Math.Sin(D - M) * -0.0003;
+ return sum;
+ }
+ ///
+ /// Sum of Perigee Terms from Jean Meeus Astronomical Algorithms Table 50.A
+ ///
+ /// Moom's mean elongation at time JDE
+ /// Sun's mean anomaly
+ /// Moon's arguement f latitude
+ /// Time in Julian centuries since epoch 2000
+ /// double
+ public static Double PerigeeTermsA(Double D, Double M, Double F, Double T) {
+ Double sum;
+
+ sum = Math.Sin(2 * D) * -1.6769;
+ sum += Math.Sin(4 * D) * .4589;
+ sum += Math.Sin(6 * D) * -.1856;
+ sum += Math.Sin(8 * D) * .0883;
+ sum += Math.Sin(2 * D - M) * -.0773 + .00019 * T;
+ sum += Math.Sin(M) * .0502 - .00013 * T;
+ sum += Math.Sin(10 * D) * -.0460;
+ sum += Math.Sin(4 * D - M) * .0422 - .00011 * T;
+ sum += Math.Sin(6 * D - M) * -.0256;
+ sum += Math.Sin(12 * D) * .0253;
+ sum += Math.Sin(D) * .0237;
+ sum += Math.Sin(8 * D - M) * .0162;
+ sum += Math.Sin(14 * D) * -.0145;
+ sum += Math.Sin(2 * F) * .0129;
+ sum += Math.Sin(3 * D) * -.0112;
+ sum += Math.Sin(10 * D - M) * -.0104;
+ sum += Math.Sin(16 * D) * .0086;
+ sum += Math.Sin(12 * D - M) * .0069;
+ sum += Math.Sin(5 * D) * .0066;
+ sum += Math.Sin(2 * D + 2 * F) * -.0053;
+ sum += Math.Sin(18 * D) * -.0052;
+ sum += Math.Sin(14 * D - M) * -.0046;
+ sum += Math.Sin(7 * D) * -.0041;
+ sum += Math.Sin(2 * D + M) * .0040;
+ sum += Math.Sin(20 * D) * .0032;
+ sum += Math.Sin(D + M) * -.0032;
+ sum += Math.Sin(16 * D - M) * .0031;
+ sum += Math.Sin(4 * D + M) * -.0029;
+ sum += Math.Sin(9 * D) * .0027;
+ sum += Math.Sin(4 * D + 2 * F) * .0027;
+
+ sum += Math.Sin(2 * D - 2 * M) * -.0027;
+ sum += Math.Sin(4 * D - 2 * M) * .0024;
+ sum += Math.Sin(6 * D - 2 * M) * -.0021;
+ sum += Math.Sin(22 * D) * -.0021;
+ sum += Math.Sin(18 * D - M) * -.0021;
+ sum += Math.Sin(6 * D + M) * .0019;
+ sum += Math.Sin(11 * D) * -.0018;
+ sum += Math.Sin(8 * D + M) * -.0014;
+ sum += Math.Sin(4 * D - 2 * F) * -.0014;
+ sum += Math.Sin(6 * D + 2 * F) * -.0014;
+ sum += Math.Sin(3 * D + M) * .0014;
+ sum += Math.Sin(5 * D + M) * -.0014;
+ sum += Math.Sin(13 * D) * .0013;
+ sum += Math.Sin(20 * D - M) * .0013;
+ sum += Math.Sin(3 * D + 2 * M) * .0011;
+ sum += Math.Sin(4 * D + 2 * F - 2 * M) * -.0011;
+ sum += Math.Sin(D + 2 * M) * -.0010;
+ sum += Math.Sin(22 * D - M) * -.0009;
+ sum += Math.Sin(4 * F) * -.0008;
+ sum += Math.Sin(6 * D - 2 * F) * .0008;
+ sum += Math.Sin(2 * D - 2 * F + M) * .0008;
+ sum += Math.Sin(2 * M) * .0007;
+ sum += Math.Sin(2 * F - M) * .0007;
+ sum += Math.Sin(2 * D + 4 * F) * .0007;
+ sum += Math.Sin(2 * F - 2 * M) * -.0006;
+ sum += Math.Sin(2 * D - 2 * F + 2 * M) * -.0006;
+ sum += Math.Sin(24 * D) * .0006;
+ sum += Math.Sin(4 * D - 4 * F) * .0005;
+ sum += Math.Sin(2 * D + 2 * M) * .0005;
+ sum += Math.Sin(D - M) * -.0004;
+
+ return sum;
+ }
+ ///
+ /// Sum of Apogee Terms from Jean Meeus Astronomical Algorithms Table 50.B
+ ///
+ /// Moom's mean elongation at time JDE
+ /// Sun's mean anomaly
+ /// Moon's arguement f latitude
+ /// Time in Julian centuries since epoch 2000
+ /// double
+ public static Double ApogeeTermsB(Double D, Double M, Double F, Double T) {
+ Double sum = 3245.251;
+
+ sum += Math.Cos(2 * D) * -9.147;
+ sum += Math.Cos(D) * -.841;
+ sum += Math.Cos(2 * F) * .697;
+ sum += Math.Cos(M) * -0.656 + .0016 * T;
+ sum += Math.Cos(4 * D) * .355;
+ sum += Math.Cos(2 * D - M) * .159;
+ sum += Math.Cos(D + M) * .127;
+ sum += Math.Cos(4 * D - M) * .065;
+
+ sum += Math.Cos(6 * D) * .052;
+ sum += Math.Cos(2 * D + M) * .043;
+ sum += Math.Cos(2 * D + 2 * F) * .031;
+ sum += Math.Cos(2 * D - 2 * F) * -.023;
+ sum += Math.Cos(2 * D - 2 * M) * .022;
+ sum += Math.Cos(2 * D + 2 * M) * .019;
+ sum += Math.Cos(2 * M) * -.016;
+ sum += Math.Cos(6 * D - M) * .014;
+ sum += Math.Cos(8 * D) * .010;
+
+ return sum;
+ }
+ ///
+ /// Sum of Perigee Terms from Jean Meeus Astronomical Algorithms Table 50.B
+ ///
+ /// Moom's mean elongation at time JDE
+ /// Sun's mean anomaly
+ /// Moon's arguement f latitude
+ /// Time in Julian centuries since epoch 2000
+ /// double
+ public static Double PerigeeTermsB(Double D, Double M, Double F, Double T) {
+ //Sum of Perigee Terms from Jean Meeus Astronomical Algorithms Table 50.B
+ Double sum = 3629.215;
+
+ sum += Math.Cos(2 * D) * 63.224;
+ sum += Math.Cos(4 * D) * -6.990;
+ sum += Math.Cos(2 * D - M) * 2.834 - .0071 * T;
+ sum += Math.Cos(6 * D) * 1.927;
+ sum += Math.Cos(D) * -1.263;
+ sum += Math.Cos(8 * D) * -.702;
+ sum += Math.Cos(M) * .696 - .0017 * T;
+ sum += Math.Cos(2 * F) * -.690;
+ sum += Math.Cos(4 * D - M) * -.629 + .0016 * T;
+ sum += Math.Cos(2 * D - 2 * F) * -.392;
+ sum += Math.Cos(10 * D) * .297;
+ sum += Math.Cos(6 * D - M) * .260;
+ sum += Math.Cos(3 * D) * .201;
+ sum += Math.Cos(2 * D + M) * -.161;
+ sum += Math.Cos(D + M) * .157;
+ sum += Math.Cos(12 * D) * -.138;
+ sum += Math.Cos(8 * D - M) * -.127;
+ sum += Math.Cos(2 * D + 2 * F) * .104;
+ sum += Math.Cos(2 * D - 2 * M) * .104;
+ sum += Math.Cos(5 * D) * -.079;
+ sum += Math.Cos(14 * D) * .068;
+
+ sum += Math.Cos(10 * D - M) * .067;
+ sum += Math.Cos(4 * D + M) * .054;
+ sum += Math.Cos(12 * D - M) * -.038;
+ sum += Math.Cos(4 * D - 2 * M) * -.038;
+ sum += Math.Cos(7 * D) * .037;
+ sum += Math.Cos(4 * D + 2 * F) * -.037;
+ sum += Math.Cos(16 * D) * -.035;
+ sum += Math.Cos(3 * D + M) * -.030;
+ sum += Math.Cos(D - M) * .029;
+ sum += Math.Cos(6 * D + M) * -.025;
+ sum += Math.Cos(2 * M) * .023;
+ sum += Math.Cos(14 * D - M) * .023;
+ sum += Math.Cos(2 * D + 2 * M) * -.023;
+ sum += Math.Cos(6 * D - 2 * M) * .022;
+ sum += Math.Cos(2 * D - 2 * F - M) * -.021;
+ sum += Math.Cos(9 * D) * -.020;
+ sum += Math.Cos(18 * D) * .019;
+ sum += Math.Cos(6 * D + 2 * F) * .017;
+ sum += Math.Cos(2 * F - M) * .014;
+ sum += Math.Cos(16 * D - M) * -.014;
+ sum += Math.Cos(4 * D - 2 * F) * .013;
+ sum += Math.Cos(8 * D + M) * .012;
+ sum += Math.Cos(11 * D) * .011;
+ sum += Math.Cos(5 * D + M) * .010;
+ sum += Math.Cos(20 * D) * -.010;
+
+ return sum;
+ }
+
+ }
+ internal class MeeusFormulas {
+ public static Double Get_Sidereal_Time(Double JD) {
+ //Ch. 12
+ //T = Dynamic Time
+ //Oo = mean sidereal time at Greenwich at 0h UT
+ Double T = (JD - 2451545) / 36525;
+ Double Oo = 280.46061837 + 360.98564736629 * (JD - 2451545) +
.000387933 * Math.Pow(T, 2) - Math.Pow(T, 3) / 38710000;
- return Oo;
- }
+ return Oo;
}
+ }
+ ///
+ /// Used to display a celestial condition for a specified date.
+ ///
+ [Serializable]
+ public enum CelestialStatus {
///
- /// Used to display a celestial condition for a specified date.
+ /// Celestial body rises and sets on the set day.
///
- [Serializable]
- public enum CelestialStatus
- {
- ///
- /// Celestial body rises and sets on the set day.
- ///
- RiseAndSet,
- ///
- /// Celestial body is down all day
- ///
- DownAllDay,
- ///
- /// Celestial body is up all day
- ///
- UpAllDay,
- ///
- /// Celestial body rises, but does not set on the set day
- ///
- NoRise,
- ///
- /// Celestial body sets, but does not rise on the set day
- ///
- NoSet
- }
+ RiseAndSet,
///
- /// moon perigee or apogee indicator
+ /// Celestial body is down all day
///
- internal enum MoonDistanceType
- {
- ///
- /// Moon's perigee
- ///
- Perigee,
- ///
- /// Moon's apogee
- ///
- Apogee
- }
+ DownAllDay,
///
- /// Moon Illumination Information
+ /// Celestial body is up all day
///
- [Serializable]
- public class MoonIllum
- {
+ UpAllDay,
+ ///
+ /// Celestial body rises, but does not set on the set day
+ ///
+ NoRise,
+ ///
+ /// Celestial body sets, but does not rise on the set day
+ ///
+ NoSet
+ }
+ ///
+ /// moon perigee or apogee indicator
+ ///
+ internal enum MoonDistanceType {
+ ///
+ /// Moon's perigee
+ ///
+ Perigee,
+ ///
+ /// Moon's apogee
+ ///
+ Apogee
+ }
+ ///
+ /// Moon Illumination Information
+ ///
+ [Serializable]
+ public class MoonIllum {
- ///
- /// Moon's fraction
- ///
- public double Fraction { get; internal set; }
- ///
- /// Moon's Angle
- ///
- public double Angle { get; internal set; }
- ///
- /// Moon's phase
- ///
- public double Phase { get; internal set; }
- ///
- /// Moon's phase name for the specified day
- ///
- public string PhaseName { get; internal set; }
+ ///
+ /// Moon's fraction
+ ///
+ public Double Fraction { get; internal set; }
+ ///
+ /// Moon's Angle
+ ///
+ public Double Angle { get; internal set; }
+ ///
+ /// Moon's phase
+ ///
+ public Double Phase { get; internal set; }
+ ///
+ /// Moon's phase name for the specified day
+ ///
+ public String PhaseName { get; internal set; }
+
+ }
+ ///
+ /// Stores Perigee or Apogee values
+ ///
+ [Serializable]
+ public class PerigeeApogee {
+
+ ///
+ /// Initializes a Perigee or Apogee object
+ ///
+ /// Date of Event
+ /// Horizontal Parallax
+ /// Distance
+ public PerigeeApogee(DateTime d, Double p, Distance dist) {
+ this.Date = d;
+ this.HorizontalParallax = p;
+ this.Distance = dist;
+ }
+
+ ///
+ /// Date of event.
+ ///
+ public DateTime Date { get; }
+ ///
+ /// Horizontal Parallax.
+ ///
+ public Double HorizontalParallax { get; }
+ ///
+ /// Moon's distance at event.
+ ///
+ public Distance Distance { get; }
+
+ internal void Convert_To_Local_Time(Double offset) {
+ FieldInfo[] fields = typeof(PerigeeApogee).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
+ foreach (FieldInfo field in fields) {
+ if (field.FieldType == typeof(DateTime)) {
+ DateTime d = (DateTime)field.GetValue(this);
+ if (d > new DateTime()) {
+ d = d.AddHours(offset);
+ field.SetValue(this, d);
+ }
+ }
+ }
+ }
+
+ }
+ ///
+ /// Julian date conversions
+ ///
+ public class JulianConversions {
+ //1.1.3.1
+ private static readonly Double J1970 = 2440588, J2000 = 2451545;
+
+ ///
+ /// Returns JD.
+ /// Meeus Ch 7.
+ ///
+ /// DateTime
+ /// JDE
+ public static Double GetJulian(DateTime d) {
+ Double y = d.Year;
+ Double m = d.Month;
+ Double dy = d.Day + d.TimeOfDay.TotalHours / 24;
+
+ //If month is Jan or Feb add 12 to month and reduce year by 1.
+ if (m <= 2) { m += 12; y -= 1; }
+
+ Double A = (Int32)(d.Year / 100.0);
+ Double B = 0;
+
+ //Gregorian Start Date
+ if (d >= new DateTime(1582, 10, 15)) {
+ B = 2 - A + (Int32)(A / 4.0);
+ }
+ Double JD = (Int32)(365.25 * (y + 4716)) + (Int32)(30.6001 * (m + 1)) + dy + B - 1524.5;
+ return JD;
+ }
+ ///
+ /// Returns JD from epoch 2000.
+ /// Meeus Ch 7.
+ ///
+ /// DateTime
+ /// JDE
+ public static Double GetJulian_Epoch2000(DateTime d) => GetJulian(d) - J2000;
+ ///
+ /// Returns JD from epoch 1970.
+ /// Meeus Ch 7.
+ ///
+ /// DateTime
+ /// JDE
+ public static Double GetJulian_Epoch1970(DateTime d) => GetJulian(d) - J1970;
+
+ ///
+ /// Returns date from Julian
+ /// Meeus ch. 7
+ ///
+ /// Julian
+ /// DateTime
+ public static DateTime? GetDate_FromJulian(Double j) {
+ if (Double.IsNaN(j)) { return null; } //No Event Occured
+
+ j += .5;
+ Double Z = Math.Floor(j);
+ Double F = j - Z;
+ Double A = Z;
+ if (Z >= 2299161) {
+ Double a = (Int32)((Z - 1867216.25) / 36524.25);
+ A = Z + 1 + a - (Int32)(a / 4.0);
+ }
+ Double B = A + 1524;
+ Double C = (Int32)((B - 122.1) / 365.25);
+ Double D = (Int32)(365.25 * C);
+ Double E = (Int32)((B - D) / 30.6001);
+
+ Double day = B - D - (Int32)(30.6001 * E) + F;
+
+ //Month is E-1 if month is < 14 or E-13 if month is 14 or 15
+ Double month = E - 1;
+ if (E > 13) { month -= 12; }
+
+ //year is C-4716 if month>2 and C-4715 if month is 1 or 2
+ Double year = C - 4715;
+ if (month > 2) {
+ year -= 1;
+ }
+
+ Double hours = day - Math.Floor(day);
+ hours *= 24;
+ Double minutes = hours - Math.Floor(hours);
+ minutes *= 60;
+ Double seconds = minutes - Math.Floor(minutes);
+ seconds *= 60;
+
+ day = Math.Floor(day);
+ hours = Math.Floor(hours);
+ minutes = Math.Floor(minutes);
+
+ DateTime? date = new DateTime?(new DateTime((Int32)year, (Int32)month, (Int32)day, (Int32)hours, (Int32)minutes, (Int32)seconds));
+ return date;
+ }
+ ///
+ /// Returns date from Julian based on epoch 2000
+ /// Meeus ch. 7
+ ///
+ /// Julian
+ /// DateTime
+ public static DateTime? GetDate_FromJulian_Epoch2000(Double j) => GetDate_FromJulian(j + J2000);
+ ///
+ /// Returns date from Julian based on epoch 1970
+ /// Meeus ch. 7
+ ///
+ /// Julian
+ /// DateTime
+ public static DateTime? GetDate_FromJulian_Epoch1970(Double j) => GetDate_FromJulian(j + J1970);
+ }
+ ///
+ /// Contains last and next perigee
+ ///
+ [Serializable]
+ public class Perigee {
+
+ ///
+ /// Initializes an Perigee object.
+ ///
+ ///
+ ///
+ public Perigee(PerigeeApogee last, PerigeeApogee next) {
+ this.LastPerigee = last;
+ this.NextPerigee = next;
+ }
+
+ ///
+ /// Last perigee
+ ///
+ public PerigeeApogee LastPerigee { get; }
+ ///
+ /// Next perigee
+ ///
+ public PerigeeApogee NextPerigee { get; }
+
+ internal void ConvertTo_Local_Time(Double offset) {
+ this.LastPerigee.Convert_To_Local_Time(offset);
+ this.NextPerigee.Convert_To_Local_Time(offset);
+ }
+
+ }
+ ///
+ /// Contains last and next apogee
+ ///
+ [Serializable]
+ public class Apogee {
+
+ ///
+ /// Initializes an Apogee object.
+ ///
+ ///
+ ///
+ public Apogee(PerigeeApogee last, PerigeeApogee next) {
+ this.LastApogee = last;
+ this.NextApogee = next;
+ }
+
+ ///
+ /// Last apogee
+ ///
+ public PerigeeApogee LastApogee { get; }
+ ///
+ /// Next apogee
+ ///
+ public PerigeeApogee NextApogee { get; }
+
+ internal void ConvertTo_Local_Time(Double offset) {
+ this.LastApogee.Convert_To_Local_Time(offset);
+ this.NextApogee.Convert_To_Local_Time(offset);
+ }
+ }
+ ///
+ /// Astrological Signs
+ ///
+ [Serializable]
+ public class AstrologicalSigns {
+ ///
+ /// Astrological Zodiac Sign
+ ///
+ public String MoonName { get; internal set; }
+ ///
+ /// Astrological Moon Sign
+ ///
+ public String MoonSign { get; internal set; }
+ ///
+ /// Astrological Zodiac Sign
+ ///
+ public String ZodiacSign { get; internal set; }
+ }
+ ///
+ /// Additional Solar Time Information
+ ///
+ [Serializable]
+ public class AdditionalSolarTimes {
+ ///
+ /// Create an AdditionalSolarTimes object.
+ ///
+ public AdditionalSolarTimes() {
+ //Set dates to avoid null errors. If year return 1900 event did not occur.
+ this.CivilDawn = new DateTime();
+ this.CivilDusk = new DateTime();
+ this.NauticalDawn = new DateTime();
+ this.NauticalDusk = new DateTime();
}
///
- /// Stores Perigee or Apogee values
+ /// Returns Civil Dawn Time
///
- [Serializable]
- public class PerigeeApogee
- {
- private DateTime date;
- private double horizontalParallax;
- private Distance distance;
+ public DateTime? CivilDawn { get; internal set; }
+ ///
+ /// Returns Civil Dusk Time
+ ///
+ public DateTime? CivilDusk { get; internal set; }
+ ///
+ /// Returns Nautical Dawn Time
+ ///
+ public DateTime? NauticalDawn { get; internal set; }
+ ///
+ /// Returns Nautical Dusk Time
+ ///
+ public DateTime? NauticalDusk { get; internal set; }
+ ///
+ /// Returns Astronomical Dawn Time
+ ///
+ public DateTime? AstronomicalDawn { get; internal set; }
+ ///
+ /// Returns Astronomical Dusk Time
+ ///
+ public DateTime? AstronomicalDusk { get; internal set; }
- ///
- /// Initializes a Perigee or Apogee object
- ///
- /// Date of Event
- /// Horizontal Parallax
- /// Distance
- public PerigeeApogee(DateTime d, double p, Distance dist)
- {
- date = d;
- horizontalParallax = p;
- distance = dist;
- }
+ ///
+ /// Returns the time when the bottom of the solar disc touches the horizon after sunrise
+ ///
+ public DateTime? SunriseBottomDisc { get; internal set; }
+ ///
+ /// Returns the time when the bottom of the solar disc touches the horizon before sunset
+ ///
+ public DateTime? SunsetBottomDisc { get; internal set; }
- ///
- /// Date of event.
- ///
- public DateTime Date
- {
- get { return date; }
- }
- ///
- /// Horizontal Parallax.
- ///
- public double HorizontalParallax
- {
- get { return horizontalParallax; }
- }
- ///
- /// Moon's distance at event.
- ///
- public Distance Distance
- {
- get { return distance; }
- }
-
- internal void Convert_To_Local_Time(double offset)
- {
- FieldInfo[] fields = typeof(PerigeeApogee).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
- foreach (FieldInfo field in fields)
- {
- if (field.FieldType == typeof(DateTime))
- {
- DateTime d = (DateTime)field.GetValue(this);
- if (d > new DateTime())
- {
- d = d.AddHours(offset);
- field.SetValue(this, d);
- }
- }
+ internal void Convert_To_Local_Time(Double offset) {
+ FieldInfo[] fields = typeof(AdditionalSolarTimes).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
+ foreach (FieldInfo field in fields) {
+ if (field.FieldType == typeof(DateTime?)) {
+ DateTime? d = (DateTime?)field.GetValue(this);
+ if (d.HasValue) {
+ if (d > new DateTime()) {
+ d = d.Value.AddHours(offset);
+ field.SetValue(this, d);
}
+ }
}
-
+ }
+ }
+ }
+ ///
+ /// Class containing solar eclipse information
+ ///
+ [Serializable]
+ public class SolarEclipse {
+ ///
+ /// Initialize a SolarEclipse object
+ ///
+ public SolarEclipse() {
+ this.LastEclipse = new SolarEclipseDetails();
+ this.NextEclipse = new SolarEclipseDetails();
}
///
- /// Julian date conversions
+ /// Details about the previous solar eclipse
///
- public class JulianConversions
- {
- //1.1.3.1
- private static double J1970 = 2440588, J2000 = 2451545;
+ public SolarEclipseDetails LastEclipse { get; internal set; }
+ ///
+ /// Details about the next solar eclipse
+ ///
+ public SolarEclipseDetails NextEclipse { get; internal set; }
- ///
- /// Returns JD.
- /// Meeus Ch 7.
- ///
- /// DateTime
- /// JDE
- public static double GetJulian(DateTime d)
- {
- double y = d.Year;
- double m = d.Month;
- double dy = d.Day + (d.TimeOfDay.TotalHours / 24);
-
- //If month is Jan or Feb add 12 to month and reduce year by 1.
- if(m <= 2) { m += 12; y -= 1; }
-
- double A = (int)(d.Year / 100.0);
- double B = 0;
-
- //Gregorian Start Date
- if(d >= new DateTime(1582,10,15))
- {
- B = 2 - A + (int)(A / 4.0);
- }
- double JD = (int)(365.25 * (y + 4716)) + (int)(30.6001 * (m + 1)) + dy + B - 1524.5;
- return JD;
- }
- ///
- /// Returns JD from epoch 2000.
- /// Meeus Ch 7.
- ///
- /// DateTime
- /// JDE
- public static double GetJulian_Epoch2000(DateTime d)
- {
- return GetJulian(d) - J2000;
- }
- ///
- /// Returns JD from epoch 1970.
- /// Meeus Ch 7.
- ///
- /// DateTime
- /// JDE
- public static double GetJulian_Epoch1970(DateTime d)
- {
- return GetJulian(d) - J1970;
- }
-
- ///
- /// Returns date from Julian
- /// Meeus ch. 7
- ///
- /// Julian
- /// DateTime
- public static DateTime? GetDate_FromJulian(double j)
- {
- if (Double.IsNaN(j)) { return null; } //No Event Occured
-
- j = j + .5;
- double Z = Math.Floor(j);
- double F = j - Z;
- double A = Z;
- if (Z >= 2299161)
- {
- double a = (int)((Z - 1867216.25) / 36524.25);
- A = Z + 1 + a - (int)(a / 4.0);
- }
- double B = A + 1524;
- double C = (int)((B - 122.1) / 365.25);
- double D = (int)(365.25 * C);
- double E = (int)((B - D) / 30.6001);
-
- double day = B - D - (int)(30.6001 * E) + F;
-
- //Month is E-1 if month is < 14 or E-13 if month is 14 or 15
- double month = E-1;
- if (E > 13) { month -= 12; }
-
- //year is C-4716 if month>2 and C-4715 if month is 1 or 2
- double year = C - 4715;
- if(month >2)
- {
- year -= 1;
- }
-
- double hours = day - Math.Floor(day);
- hours *= 24;
- double minutes = hours - Math.Floor(hours);
- minutes *= 60;
- double seconds = minutes - Math.Floor(minutes);
- seconds *= 60;
-
- day = Math.Floor(day);
- hours = Math.Floor(hours);
- minutes = Math.Floor(minutes);
-
- DateTime? date = new DateTime?(new DateTime((int)year, (int)month, (int)day, (int)hours, (int)minutes, (int)seconds));
- return date;
- }
- ///
- /// Returns date from Julian based on epoch 2000
- /// Meeus ch. 7
- ///
- /// Julian
- /// DateTime
- public static DateTime? GetDate_FromJulian_Epoch2000(double j)
- {
- return GetDate_FromJulian(j+J2000);
- }
- ///
- /// Returns date from Julian based on epoch 1970
- /// Meeus ch. 7
- ///
- /// Julian
- /// DateTime
- public static DateTime? GetDate_FromJulian_Epoch1970(double j)
- {
- return GetDate_FromJulian(j + J1970);
- }
+ internal void ConvertTo_LocalTime(Double offset) {
+ this.LastEclipse.Convert_To_Local_Time(offset);
+ this.NextEclipse.Convert_To_Local_Time(offset);
+ }
+ }
+ ///
+ /// Class containing lunar eclipse information
+ ///
+ [Serializable]
+ public class LunarEclipse {
+ ///
+ /// Initialize a LunarEclipse object
+ ///
+ public LunarEclipse() {
+ this.LastEclipse = new LunarEclipseDetails();
+ this.NextEclipse = new LunarEclipseDetails();
}
///
- /// Contains last and next perigee
+ /// Details about the previous lunar eclipse
///
- [Serializable]
- public class Perigee
- {
- private PerigeeApogee lastPerigee;
- private PerigeeApogee nextPerigee;
+ public LunarEclipseDetails LastEclipse { get; internal set; }
+ ///
+ /// Details about the next lunar eclipse
+ ///
+ public LunarEclipseDetails NextEclipse { get; internal set; }
- ///
- /// Initializes an Perigee object.
- ///
- ///
- ///
- public Perigee(PerigeeApogee last, PerigeeApogee next)
- {
- lastPerigee = last;
- nextPerigee = next;
+ internal void ConvertTo_LocalTime(Double offset) {
+ this.LastEclipse.Convert_To_Local_Time(offset);
+ this.NextEclipse.Convert_To_Local_Time(offset);
+ }
+ }
+ ///
+ /// Class containing specific solar eclipse information
+ ///
+ [Serializable]
+ public class SolarEclipseDetails {
+
+ ///
+ /// Initialize a SolarEclipseDetails object
+ ///
+ /// Solar Eclipse String Values
+ public SolarEclipseDetails(List values) {
+ //Eclipse has value
+ this.HasEclipseData = true;
+ //Set Eclipse Date
+ this.Date = Convert.ToDateTime(values[0]);
+
+ switch (values[1]) {
+ case "P":
+ this.Type = SolarEclipseType.Partial;
+ break;
+ case "A":
+ this.Type = SolarEclipseType.Annular;
+ break;
+ case "T":
+ this.Type = SolarEclipseType.Total;
+ break;
+ default:
+ break;
+ }
+ //Eclipse start
+ if (TimeSpan.TryParse(values[2], out TimeSpan ts)) {
+ this.PartialEclispeBegin = this.Date.Add(ts);
+ }
+ //A or T start
+ if (TimeSpan.TryParse(values[4], out ts)) {
+ this.AorTEclipseBegin = this.Date.Add(ts);
+ }
+ //Maximum Eclipse
+ if (TimeSpan.TryParse(values[5], out ts)) {
+ this.MaximumEclipse = this.Date.Add(ts);
+ }
+ //A or T ends
+ if (TimeSpan.TryParse(values[8], out ts)) {
+ this.AorTEclipseEnd = this.Date.Add(ts);
+ }
+ //Eclipse end
+ if (TimeSpan.TryParse(values[9], out ts)) {
+ this.PartialEclispeEnd = this.Date.Add(ts);
+ }
+ //A or T Duration
+ if (values[13] != "-") {
+ String s = values[13].Replace("m", ":").Replace("s", "");
+ String[] ns = s.Split(':');
+ Int32 secs = 0;
+
+ _ = Int32.TryParse(ns[0], out Int32 mins);
+ if (ns.Count() > 0) {
+ _ = Int32.TryParse(ns[1], out secs);
}
- ///
- /// Last perigee
- ///
- public PerigeeApogee LastPerigee { get { return lastPerigee; } }
- ///
- /// Next perigee
- ///
- public PerigeeApogee NextPerigee { get { return nextPerigee; } }
-
- internal void ConvertTo_Local_Time(double offset)
- {
- LastPerigee.Convert_To_Local_Time(offset);
- NextPerigee.Convert_To_Local_Time(offset);
- }
+ TimeSpan time = new TimeSpan(0, mins, secs);
+ this.AorTDuration = time;
+ } else {
+ this.AorTDuration = new TimeSpan();
+ }
+ this.Adjust_Dates();//Adjust dates if required (needed when eclipse crosses into next day).
}
///
- /// Contains last and next apogee
+ /// Initialize an empty SolarEclipseDetails object
///
- [Serializable]
- public class Apogee
- {
- private PerigeeApogee lastApogee;
- private PerigeeApogee nextApogee;
+ public SolarEclipseDetails() => this.HasEclipseData = false;
+ ///
+ /// JS Eclipse Calc formulas didn't account for Z time calculation.
+ /// Iterate through and adjust Z dates where eclipse is passed midnight.
+ ///
+ private void Adjust_Dates() {
+ //Load array in reverse event order
+ DateTime[] dateArray = new DateTime[] { this.PartialEclispeBegin, this.AorTEclipseBegin, this.MaximumEclipse, this.AorTEclipseEnd, this.PartialEclispeEnd };
+ DateTime baseTime = this.PartialEclispeEnd;
+ Boolean multiDay = false; //used to detrmine if eclipse crossed into next Z day
- ///
- /// Initializes an Apogee object.
- ///
- ///
- ///
- public Apogee(PerigeeApogee last, PerigeeApogee next)
- {
- lastApogee = last;
- nextApogee = next;
- }
-
- ///
- /// Last apogee
- ///
- public PerigeeApogee LastApogee { get { return lastApogee; } }
- ///
- /// Next apogee
- ///
- public PerigeeApogee NextApogee { get { return nextApogee; } }
-
- internal void ConvertTo_Local_Time(double offset)
- {
- LastApogee.Convert_To_Local_Time(offset);
- NextApogee.Convert_To_Local_Time(offset);
+ for (Int32 x = 4; x >= 0; x--) {
+ DateTime d = dateArray[x];
+ //Check if date exist
+ if (d > new DateTime()) {
+
+ //Adjust if time is less than then baseTime.
+ if (d > baseTime) {
+ switch (x) {
+ case 3:
+ this.AorTEclipseEnd = this.AorTEclipseEnd.AddDays(-1);
+ break;
+ case 2:
+ this.MaximumEclipse = this.MaximumEclipse.AddDays(-1);
+ break;
+ case 1:
+ this.AorTEclipseBegin = this.AorTEclipseBegin.AddDays(-1);
+ break;
+ case 0:
+ this.PartialEclispeBegin = this.PartialEclispeBegin.AddDays(-1);
+ break;
+ default:
+ break;
+ }
+
+ multiDay = true;//Set true to change base date value.
+ }
}
+ }
+ if (multiDay) {
+ this.Date = this.Date.AddDays(-1); //Shave day off base date if multiday.
+ }
}
///
- /// Astrological Signs
+ /// Determine if the SolarEclipseDetails object has been populated
///
- [Serializable]
- public class AstrologicalSigns
- {
- ///
- /// Astrological Zodiac Sign
- ///
- public string MoonName { get; internal set; }
- ///
- /// Astrological Moon Sign
- ///
- public string MoonSign { get; internal set; }
- ///
- /// Astrological Zodiac Sign
- ///
- public string ZodiacSign { get; internal set; }
- }
+ public Boolean HasEclipseData { get; }
///
- /// Additional Solar Time Information
+ /// Date of solar eclipse
///
- [Serializable]
- public class AdditionalSolarTimes
- {
- ///
- /// Create an AdditionalSolarTimes object.
- ///
- public AdditionalSolarTimes()
- {
- //Set dates to avoid null errors. If year return 1900 event did not occur.
- CivilDawn = new DateTime();
- CivilDusk = new DateTime();
- NauticalDawn = new DateTime();
- NauticalDusk = new DateTime();
-
- }
- ///
- /// Returns Civil Dawn Time
- ///
- public DateTime? CivilDawn { get; internal set; }
- ///
- /// Returns Civil Dusk Time
- ///
- public DateTime? CivilDusk { get; internal set; }
- ///
- /// Returns Nautical Dawn Time
- ///
- public DateTime? NauticalDawn { get; internal set; }
- ///
- /// Returns Nautical Dusk Time
- ///
- public DateTime? NauticalDusk { get; internal set; }
- ///
- /// Returns Astronomical Dawn Time
- ///
- public DateTime? AstronomicalDawn { get; internal set; }
- ///
- /// Returns Astronomical Dusk Time
- ///
- public DateTime? AstronomicalDusk { get; internal set; }
-
- ///
- /// Returns the time when the bottom of the solar disc touches the horizon after sunrise
- ///
- public DateTime? SunriseBottomDisc{ get; internal set; }
- ///
- /// Returns the time when the bottom of the solar disc touches the horizon before sunset
- ///
- public DateTime? SunsetBottomDisc { get; internal set; }
-
- internal void Convert_To_Local_Time(double offset)
- {
- FieldInfo[] fields = typeof(AdditionalSolarTimes).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
- foreach (FieldInfo field in fields)
- {
- if (field.FieldType == typeof(DateTime?))
- {
- DateTime? d = (DateTime?)field.GetValue(this);
- if (d.HasValue)
- {
- if (d > new DateTime())
- {
- d = d.Value.AddHours(offset);
- field.SetValue(this, d);
- }
- }
- }
- }
- }
- }
- ///
- /// Class containing solar eclipse information
- ///
- [Serializable]
- public class SolarEclipse
- {
- ///
- /// Initialize a SolarEclipse object
- ///
- public SolarEclipse()
- {
- LastEclipse = new SolarEclipseDetails();
- NextEclipse = new SolarEclipseDetails();
- }
- ///
- /// Details about the previous solar eclipse
- ///
- public SolarEclipseDetails LastEclipse { get; internal set; }
- ///
- /// Details about the next solar eclipse
- ///
- public SolarEclipseDetails NextEclipse { get; internal set; }
-
- internal void ConvertTo_LocalTime(double offset)
- {
- LastEclipse.Convert_To_Local_Time(offset);
- NextEclipse.Convert_To_Local_Time(offset);
- }
- }
- ///
- /// Class containing lunar eclipse information
- ///
- [Serializable]
- public class LunarEclipse
- {
- ///
- /// Initialize a LunarEclipse object
- ///
- public LunarEclipse()
- {
- LastEclipse = new LunarEclipseDetails();
- NextEclipse = new LunarEclipseDetails();
- }
- ///
- /// Details about the previous lunar eclipse
- ///
- public LunarEclipseDetails LastEclipse { get; internal set; }
- ///
- /// Details about the next lunar eclipse
- ///
- public LunarEclipseDetails NextEclipse { get; internal set; }
-
- internal void ConvertTo_LocalTime(double offset)
- {
- LastEclipse.Convert_To_Local_Time(offset);
- NextEclipse.Convert_To_Local_Time(offset);
- }
- }
- ///
- /// Class containing specific solar eclipse information
- ///
- [Serializable]
- public class SolarEclipseDetails
- {
- private DateTime date;
- private SolarEclipseType type;
- private DateTime partialEclispeBegin;
- private DateTime aorTEclipseBegin;
- private DateTime maximumEclipse;
- private DateTime aorTEclipseEnd;
- private DateTime partialEclispeEnd;
- private TimeSpan aorTDuration;
- private bool hasEclipseData;
-
- ///
- /// Initialize a SolarEclipseDetails object
- ///
- /// Solar Eclipse String Values
- public SolarEclipseDetails(List values)
- {
- //Eclipse has value
- hasEclipseData = true;
- //Set Eclipse Date
- date = Convert.ToDateTime(values[0]);
-
- switch (values[1])
- {
- case "P":
- type = SolarEclipseType.Partial;
- break;
- case "A":
- type = SolarEclipseType.Annular;
- break;
- case "T":
- type = SolarEclipseType.Total;
- break;
- default:
- break;
- }
- TimeSpan ts;
- //Eclipse start
- if (TimeSpan.TryParse(values[2], out ts))
- {
- partialEclispeBegin = date.Add(ts);
- }
- //A or T start
- if (TimeSpan.TryParse(values[4], out ts))
- {
- aorTEclipseBegin = date.Add(ts);
- }
- //Maximum Eclipse
- if (TimeSpan.TryParse(values[5], out ts))
- {
- maximumEclipse = date.Add(ts);
- }
- //A or T ends
- if (TimeSpan.TryParse(values[8], out ts))
- {
- aorTEclipseEnd = date.Add(ts);
- }
- //Eclipse end
- if (TimeSpan.TryParse(values[9], out ts))
- {
- partialEclispeEnd = date.Add(ts);
- }
- //A or T Duration
- if (values[13] != "-")
- {
- string s = values[13].Replace("m", ":").Replace("s", "");
- string[] ns = s.Split(':');
- int mins = 0;
- int secs = 0;
-
- int.TryParse(ns[0], out mins);
- if (ns.Count() > 0)
- {
- int.TryParse(ns[1], out secs);
- }
-
- TimeSpan time = new TimeSpan(0, mins, secs);
-
- aorTDuration = time;
- }
- else
- {
- aorTDuration = new TimeSpan();
- }
- Adjust_Dates();//Adjust dates if required (needed when eclipse crosses into next day).
- }
- ///
- /// Initialize an empty SolarEclipseDetails object
- ///
- public SolarEclipseDetails()
- {
- hasEclipseData = false;
- }
- ///
- /// JS Eclipse Calc formulas didn't account for Z time calculation.
- /// Iterate through and adjust Z dates where eclipse is passed midnight.
- ///
- private void Adjust_Dates()
- {
- //Load array in reverse event order
- DateTime[] dateArray = new DateTime[] { partialEclispeBegin, aorTEclipseBegin, maximumEclipse, aorTEclipseEnd, partialEclispeEnd };
- DateTime baseTime = partialEclispeEnd;
- bool multiDay = false; //used to detrmine if eclipse crossed into next Z day
-
- for (int x = 4; x >= 0; x--)
- {
- DateTime d = dateArray[x];
- //Check if date exist
- if (d > new DateTime())
- {
-
- //Adjust if time is less than then baseTime.
- if (d > baseTime)
- {
- switch (x)
- {
- case 3:
- aorTEclipseEnd = aorTEclipseEnd.AddDays(-1);
- break;
- case 2:
- maximumEclipse = maximumEclipse.AddDays(-1);
- break;
- case 1:
- aorTEclipseBegin = aorTEclipseBegin.AddDays(-1);
- break;
- case 0:
- partialEclispeBegin = partialEclispeBegin.AddDays(-1);
- break;
- default:
- break;
- }
-
- multiDay = true;//Set true to change base date value.
- }
- }
- }
- if (multiDay)
- {
- this.date = this.date.AddDays(-1); //Shave day off base date if multiday.
- }
- }
- ///
- /// Determine if the SolarEclipseDetails object has been populated
- ///
- public bool HasEclipseData { get { return hasEclipseData; } }
- ///
- /// Date of solar eclipse
- ///
- public DateTime Date { get { return date; } }
- ///
- /// Solar eclipse type
- ///
- public SolarEclipseType Type { get { return type; } }
- ///
- /// DateTime when the partial eclipse begins
- ///
- public DateTime PartialEclispeBegin { get { return partialEclispeBegin; } }
- ///
- /// DateTime when an Annular or Total eclipse begins (if applicable)
- ///
- public DateTime AorTEclipseBegin { get { return aorTEclipseBegin; } }
- ///
- /// DateTime when eclipse is at Maximum
- ///
- public DateTime MaximumEclipse { get { return maximumEclipse; } }
-
- ///
- /// DateTime when the Annular or Total eclipse ends (if applicable)
- ///
- public DateTime AorTEclipseEnd { get { return aorTEclipseEnd; } }
- ///
- /// DateTime when the partial elipse ends
- ///
- public DateTime PartialEclispeEnd { get { return partialEclispeEnd; } }
- ///
- /// Duration of Annular or Total eclipse (if applicable)
- ///
- public TimeSpan AorTDuration { get { return aorTDuration; } }
- ///
- /// Solat eclipse default string
- ///
- /// Solar eclipse base date string
- public override string ToString()
- {
- return date.ToString("dd-MMM-yyyy");
- }
-
- internal void Convert_To_Local_Time(double offset)
- {
- FieldInfo[] fields = typeof(SolarEclipseDetails).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
- foreach (FieldInfo field in fields)
- {
- if (field.FieldType == typeof(DateTime))
- {
- DateTime d = (DateTime)field.GetValue(this);
- if (d > new DateTime())
- {
- d = d.AddHours(offset);
- field.SetValue(this, d);
- }
- }
- }
-
- date = partialEclispeBegin.Date;
- }
- }
- ///
- /// Class containing specific lunar eclipse information
- ///
- [Serializable]
- public class LunarEclipseDetails
- {
- private DateTime date;
- private LunarEclipseType type;
- private DateTime penumbralEclipseBegin;
- private DateTime partialEclispeBegin;
- private DateTime totalEclipseBegin;
- private DateTime midEclipse;
- private DateTime totalEclipseEnd;
- private DateTime partialEclispeEnd;
- private DateTime penumbralEclipseEnd;
-
- private bool hasEclipseData;
-
- ///
- /// Initialize a LunarEclipseDetails object
- ///
- /// Lunar Eclipse String Values
- public LunarEclipseDetails(List values)
- {
- //Eclipse has value
- hasEclipseData = true;
- //Set Eclipse Date
- date = Convert.ToDateTime(values[0]);
- switch (values[1])
- {
- case "T":
- type = LunarEclipseType.Total;
- break;
- case "P":
- type = LunarEclipseType.Partial;
- break;
- case "N":
- type = LunarEclipseType.Penumbral;
- break;
- default:
- break;
- }
- TimeSpan ts;
- //Penumbral Eclipse start
- if (TimeSpan.TryParse(values[4], out ts))
- {
- penumbralEclipseBegin = date.Add(ts);
- }
- //PartialEclipse start
- if (TimeSpan.TryParse(values[6], out ts))
- {
- partialEclispeBegin = date.Add(ts);
- }
- //Total start
- if (TimeSpan.TryParse(values[8], out ts))
- {
- totalEclipseBegin = date.Add(ts);
- }
- //Mid Eclipse
- if (TimeSpan.TryParse(values[10], out ts))
- {
- midEclipse = date.Add(ts);
- }
- //Total ends
- if (TimeSpan.TryParse(values[12], out ts))
- {
- totalEclipseEnd = date.Add(ts);
- }
- //Partial Eclipse end
- if (TimeSpan.TryParse(values[14], out ts))
- {
- partialEclispeEnd = date.Add(ts);
- }
- //Penumbral Eclipse end
- if (TimeSpan.TryParse(values[16], out ts))
- {
- penumbralEclipseEnd = date.Add(ts);
- }
- Adjust_Dates();
- }
- ///
- /// Initialize an empty LunarEclipseDetails object
- ///
- public LunarEclipseDetails()
- {
- hasEclipseData = false;
- }
- ///
- /// JS Eclipse Calc formulas didn't account for Z time calculation.
- /// Iterate through and adjust Z dates where eclipse is passed midnight.
- ///
- private void Adjust_Dates()
- {
- //Load array in squential order.
- DateTime[] dateArray = new DateTime[] { penumbralEclipseBegin, partialEclispeBegin, totalEclipseBegin, midEclipse, totalEclipseEnd, partialEclispeEnd, penumbralEclipseEnd };
- DateTime baseTime = partialEclispeEnd;
- bool multiDay = false; //used to detrmine if eclipse crossed into next Z day
- baseTime = penumbralEclipseBegin;
- for (int x = 0; x < dateArray.Count(); x++)
- {
- DateTime d = dateArray[x];
- //Check if date exist
- if (d > new DateTime())
- {
- if (d < baseTime)
- {
- multiDay = true;
- }
- }
- baseTime = dateArray[x];
- if (multiDay == true)
- {
- switch (x)
- {
- case 1:
- partialEclispeBegin = partialEclispeBegin.AddDays(1);
- break;
- case 2:
- totalEclipseBegin = totalEclipseBegin.AddDays(1);
- break;
- case 3:
- midEclipse = midEclipse.AddDays(1);
- break;
- case 4:
- totalEclipseEnd = totalEclipseEnd.AddDays(1);
- break;
- case 5:
- partialEclispeEnd = partialEclispeEnd.AddDays(1);
- break;
- case 6:
- penumbralEclipseEnd = penumbralEclipseEnd.AddDays(1);
- break;
- default:
- break;
- }
- }
- }
- }
-
- ///
- /// Determine if the LunarEclipseDetails object has been populated
- ///
- public bool HasEclipseData { get { return hasEclipseData; } }
- ///
- /// Date of lunar eclipse
- ///
- public DateTime Date { get { return date; } }
- ///
- /// Lunar eclipse type
- ///
- public LunarEclipseType Type { get { return type; } }
- ///
- /// DateTime when the penumbral eclipse begins
- ///
- public DateTime PenumbralEclipseBegin { get { return penumbralEclipseBegin; } }
- ///
- /// DateTime when the partial eclipse begins (if applicable)
- ///
- public DateTime PartialEclispeBegin { get { return partialEclispeBegin; } }
- ///
- /// DateTime when Total eclipse begins (if applicable)
- ///
- public DateTime TotalEclipseBegin { get { return totalEclipseBegin; } }
- ///
- /// DateTime when eclipse is at Mid
- ///
- public DateTime MidEclipse { get { return midEclipse; } }
- ///
- /// DateTime when Total eclipse ends (if applicable)
- ///
- public DateTime TotalEclipseEnd { get { return totalEclipseEnd; } }
- ///
- /// DateTime when the partial elipse ends (if applicable)
- ///
- public DateTime PartialEclispeEnd { get { return partialEclispeEnd; } }
- ///
- /// DateTime when the penumbral elipse ends
- ///
- public DateTime PenumbralEclispeEnd { get { return penumbralEclipseEnd; } }
- ///
- /// Lunar eclipse default string
- ///
- /// Lunar eclipse base date string
- public override string ToString()
- {
- return date.ToString("dd-MMM-yyyy");
- }
-
- internal void Convert_To_Local_Time(double offset)
- {
- FieldInfo[] fields = typeof(LunarEclipseDetails).GetFields(BindingFlags.NonPublic |BindingFlags.Instance);
- foreach (FieldInfo field in fields)
- {
- if (field.FieldType == typeof(DateTime))
- {
- DateTime d = (DateTime)field.GetValue(this);
- if (d > new DateTime())
- {
- d = d.AddHours(offset);
- field.SetValue(this, d);
- }
- }
- }
- date = penumbralEclipseBegin.Date;
-
- }
-
- }
- internal class MoonTimes
- {
- public DateTime set { get; internal set; }
- public DateTime rise { get; internal set; }
- public CelestialStatus status { get; internal set; }
- }
- internal class MoonPosition
- {
- public double Azimuth { get; internal set; }
- public double Altitude { get; internal set; }
- public Distance Distance { get; internal set; }
- public double ParallacticAngle { get; internal set; }
- public double ParallaxCorection { get; internal set; }
- }
- internal class CelCoords
- {
- public double ra { get; internal set; }
- public double dec { get; internal set; }
- public double dist { get; internal set; }
- }
-
+ public DateTime Date { get; private set; }
///
/// Solar eclipse type
///
- [Serializable]
- public enum SolarEclipseType
- {
- ///
- /// Partial Eclipse
- ///
- Partial,
- ///
- /// Annular Eclipse
- ///
- Annular,
- ///
- /// Total Eclipse...of the heart...
- ///
- Total
+ public SolarEclipseType Type { get; }
+ ///
+ /// DateTime when the partial eclipse begins
+ ///
+ public DateTime PartialEclispeBegin { get; private set; }
+ ///
+ /// DateTime when an Annular or Total eclipse begins (if applicable)
+ ///
+ public DateTime AorTEclipseBegin { get; private set; }
+ ///
+ /// DateTime when eclipse is at Maximum
+ ///
+ public DateTime MaximumEclipse { get; private set; }
+
+ ///
+ /// DateTime when the Annular or Total eclipse ends (if applicable)
+ ///
+ public DateTime AorTEclipseEnd { get; private set; }
+ ///
+ /// DateTime when the partial elipse ends
+ ///
+ public DateTime PartialEclispeEnd { get; }
+ ///
+ /// Duration of Annular or Total eclipse (if applicable)
+ ///
+ public TimeSpan AorTDuration { get; }
+ ///
+ /// Solat eclipse default string
+ ///
+ /// Solar eclipse base date string
+ public override String ToString() => this.Date.ToString("dd-MMM-yyyy");
+
+ internal void Convert_To_Local_Time(Double offset) {
+ FieldInfo[] fields = typeof(SolarEclipseDetails).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
+ foreach (FieldInfo field in fields) {
+ if (field.FieldType == typeof(DateTime)) {
+ DateTime d = (DateTime)field.GetValue(this);
+ if (d > new DateTime()) {
+ d = d.AddHours(offset);
+ field.SetValue(this, d);
+ }
+ }
+ }
+
+ this.Date = this.PartialEclispeBegin.Date;
}
+ }
+ ///
+ /// Class containing specific lunar eclipse information
+ ///
+ [Serializable]
+ public class LunarEclipseDetails {
+
+ ///
+ /// Initialize a LunarEclipseDetails object
+ ///
+ /// Lunar Eclipse String Values
+ public LunarEclipseDetails(List values) {
+ //Eclipse has value
+ this.HasEclipseData = true;
+ //Set Eclipse Date
+ this.Date = Convert.ToDateTime(values[0]);
+ switch (values[1]) {
+ case "T":
+ this.Type = LunarEclipseType.Total;
+ break;
+ case "P":
+ this.Type = LunarEclipseType.Partial;
+ break;
+ case "N":
+ this.Type = LunarEclipseType.Penumbral;
+ break;
+ default:
+ break;
+ }
+ //Penumbral Eclipse start
+ if (TimeSpan.TryParse(values[4], out TimeSpan ts)) {
+ this.PenumbralEclipseBegin = this.Date.Add(ts);
+ }
+ //PartialEclipse start
+ if (TimeSpan.TryParse(values[6], out ts)) {
+ this.PartialEclispeBegin = this.Date.Add(ts);
+ }
+ //Total start
+ if (TimeSpan.TryParse(values[8], out ts)) {
+ this.TotalEclipseBegin = this.Date.Add(ts);
+ }
+ //Mid Eclipse
+ if (TimeSpan.TryParse(values[10], out ts)) {
+ this.MidEclipse = this.Date.Add(ts);
+ }
+ //Total ends
+ if (TimeSpan.TryParse(values[12], out ts)) {
+ this.TotalEclipseEnd = this.Date.Add(ts);
+ }
+ //Partial Eclipse end
+ if (TimeSpan.TryParse(values[14], out ts)) {
+ this.PartialEclispeEnd = this.Date.Add(ts);
+ }
+ //Penumbral Eclipse end
+ if (TimeSpan.TryParse(values[16], out ts)) {
+ this.PenumbralEclispeEnd = this.Date.Add(ts);
+ }
+ this.Adjust_Dates();
+ }
+ ///
+ /// Initialize an empty LunarEclipseDetails object
+ ///
+ public LunarEclipseDetails() => this.HasEclipseData = false;
+ ///
+ /// JS Eclipse Calc formulas didn't account for Z time calculation.
+ /// Iterate through and adjust Z dates where eclipse is passed midnight.
+ ///
+ private void Adjust_Dates() {
+ //Load array in squential order.
+ DateTime[] dateArray = new DateTime[] { this.PenumbralEclipseBegin, this.PartialEclispeBegin, this.TotalEclipseBegin, this.MidEclipse, this.TotalEclipseEnd, this.PartialEclispeEnd, this.PenumbralEclispeEnd };
+ Boolean multiDay = false; //used to detrmine if eclipse crossed into next Z day
+ DateTime baseTime = this.PenumbralEclipseBegin;
+ for (Int32 x = 0; x < dateArray.Count(); x++) {
+ DateTime d = dateArray[x];
+ //Check if date exist
+ if (d > new DateTime()) {
+ if (d < baseTime) {
+ multiDay = true;
+ }
+ }
+ baseTime = dateArray[x];
+ if (multiDay == true) {
+ switch (x) {
+ case 1:
+ this.PartialEclispeBegin = this.PartialEclispeBegin.AddDays(1);
+ break;
+ case 2:
+ this.TotalEclipseBegin = this.TotalEclipseBegin.AddDays(1);
+ break;
+ case 3:
+ this.MidEclipse = this.MidEclipse.AddDays(1);
+ break;
+ case 4:
+ this.TotalEclipseEnd = this.TotalEclipseEnd.AddDays(1);
+ break;
+ case 5:
+ this.PartialEclispeEnd = this.PartialEclispeEnd.AddDays(1);
+ break;
+ case 6:
+ this.PenumbralEclispeEnd = this.PenumbralEclispeEnd.AddDays(1);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Determine if the LunarEclipseDetails object has been populated
+ ///
+ public Boolean HasEclipseData { get; }
+ ///
+ /// Date of lunar eclipse
+ ///
+ public DateTime Date { get; private set; }
///
/// Lunar eclipse type
///
- [Serializable]
- public enum LunarEclipseType
- {
- ///
- /// Penumbral Eclipse
- ///
- Penumbral,
- ///
- /// Partial Eclipse
- ///
- Partial,
- ///
- /// Total Eclipse...of the heart...
- ///
- Total
+ public LunarEclipseType Type { get; }
+ ///
+ /// DateTime when the penumbral eclipse begins
+ ///
+ public DateTime PenumbralEclipseBegin { get; }
+ ///
+ /// DateTime when the partial eclipse begins (if applicable)
+ ///
+ public DateTime PartialEclispeBegin { get; private set; }
+ ///
+ /// DateTime when Total eclipse begins (if applicable)
+ ///
+ public DateTime TotalEclipseBegin { get; private set; }
+ ///
+ /// DateTime when eclipse is at Mid
+ ///
+ public DateTime MidEclipse { get; private set; }
+ ///
+ /// DateTime when Total eclipse ends (if applicable)
+ ///
+ public DateTime TotalEclipseEnd { get; private set; }
+ ///
+ /// DateTime when the partial elipse ends (if applicable)
+ ///
+ public DateTime PartialEclispeEnd { get; private set; }
+ ///
+ /// DateTime when the penumbral elipse ends
+ ///
+ public DateTime PenumbralEclispeEnd { get; private set; }
+ ///
+ /// Lunar eclipse default string
+ ///
+ /// Lunar eclipse base date string
+ public override String ToString() => this.Date.ToString("dd-MMM-yyyy");
+
+ internal void Convert_To_Local_Time(Double offset) {
+ FieldInfo[] fields = typeof(LunarEclipseDetails).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
+ foreach (FieldInfo field in fields) {
+ if (field.FieldType == typeof(DateTime)) {
+ DateTime d = (DateTime)field.GetValue(this);
+ if (d > new DateTime()) {
+ d = d.AddHours(offset);
+ field.SetValue(this, d);
+ }
+ }
+ }
+ this.Date = this.PenumbralEclipseBegin.Date;
+
}
+
+ }
+ internal class MoonTimes {
+ public DateTime Set { get; internal set; }
+ public DateTime Rise { get; internal set; }
+ public CelestialStatus Status { get; internal set; }
+ }
+ internal class MoonPosition {
+ public Double Azimuth { get; internal set; }
+ public Double Altitude { get; internal set; }
+ public Distance Distance { get; internal set; }
+ public Double ParallacticAngle { get; internal set; }
+ public Double ParallaxCorection { get; internal set; }
+ }
+ internal class CelCoords {
+ public Double Ra { get; internal set; }
+ public Double Dec { get; internal set; }
+ public Double Dist { get; internal set; }
+ }
+
+ ///
+ /// Solar eclipse type
+ ///
+ [Serializable]
+ public enum SolarEclipseType {
+ ///
+ /// Partial Eclipse
+ ///
+ Partial,
+ ///
+ /// Annular Eclipse
+ ///
+ Annular,
+ ///
+ /// Total Eclipse...of the heart...
+ ///
+ Total
+ }
+ ///
+ /// Lunar eclipse type
+ ///
+ [Serializable]
+ public enum LunarEclipseType {
+ ///
+ /// Penumbral Eclipse
+ ///
+ Penumbral,
+ ///
+ /// Partial Eclipse
+ ///
+ Partial,
+ ///
+ /// Total Eclipse...of the heart...
+ ///
+ Total
+ }
}
diff --git a/CoordinateSharp/Celestial.LunarEclipseCalc.cs b/CoordinateSharp/Celestial.LunarEclipseCalc.cs
index 80951c9..a89d10f 100644
--- a/CoordinateSharp/Celestial.LunarEclipseCalc.cs
+++ b/CoordinateSharp/Celestial.LunarEclipseCalc.cs
@@ -1,412 +1,321 @@
using System;
using System.Collections.Generic;
-namespace CoordinateSharp
-{
- //CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
- //Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used
- //to signify eclipses that had already started during rise and set times on the NASA calculator
+namespace CoordinateSharp {
+ //CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
+ //Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used
+ //to signify eclipses that had already started during rise and set times on the NASA calculator
- //SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC".
+ //SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC".
- //ELLIPSOID ADJUSTMENT
- //6378140.0 Ellipsoid is used in the NASA Calculator
- //WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions.
- //This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
+ //ELLIPSOID ADJUSTMENT
+ //6378140.0 Ellipsoid is used in the NASA Calculator
+ //WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions.
+ //This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
- //CURRENT RANGE 1601-2600.
- internal class LunarEclipseCalc
- {
- public static List> CalculateLunarEclipse(DateTime d, double latRad, double longRad)
- {
- return Calculate(d, latRad, longRad);
- }
- public static List CalculateLunarEclipse(DateTime d, double latRad, double longRad, double[] events)
- {
- List> evs = Calculate(d, latRad, longRad, events);
- List deetsList = new List();
- foreach (List ls in evs)
- {
- LunarEclipseDetails deets = new LunarEclipseDetails(ls);
- deetsList.Add(deets);
- }
- return deetsList;
- }
- public static List> CalculateLunarEclipse(DateTime d, Coordinate coord)
- {
- return Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians());
- }
-
-
- // CALCULATE!
- private static List> Calculate(DateTime d, double latRad, double longRad, double[] ev = null)
- {
- //DECLARE ARRAYS
- double[] obsvconst = new double[6];
- double[] mid = new double[41];
- double[] p1 = new double[41];
- double[] u1 = new double[41];
- double[] u2 = new double[41];
- double[] u3 = new double[41];
- double[] u4 = new double[41];
- double[] p4 = new double[41];
-
- List> events = new List>();
-
- double[] el;
- if (ev == null)
- {
- el = Eclipse.LunarData.LunarDateData(d);//Get 100 year solar data;
- }
- else
- {
- el = ev;
- }
-
- events = new List>();
- ReadData(latRad, longRad, obsvconst);
-
- for (int i = 0; i < el.Length; i += 22)
- {
- if (el[5 + i] <= obsvconst[5])
- {
- List values = new List();
- obsvconst[4] = i;
- GetAll(el, obsvconst, mid, p1, u1, u2,u3,u4,p4);
- // Is there an event...
- if (mid[5] != 1)
- {
-
- values.Add(GetDate(el, p1, obsvconst));
-
- if (el[5 + i] == 1)
- {
- values.Add("T");
- }
- else if (el[5 + i] == 2)
- {
- values.Add("P");
- }
- else
- {
- values.Add("N");
- }
-
- // Pen. Mag
- values.Add(el[3 + i].ToString());
-
- // Umbral Mag
- values.Add(el[4 + i].ToString());
-
- // P1
- values.Add(GetTime(el, p1, obsvconst));
-
- // P1 alt
- values.Add(GetAlt(p1));
-
- if (u1[5] == 1)
- {
- values.Add("-");
- values.Add("-");
- }
- else
- {
- // U1
- values.Add(GetTime(el, u1, obsvconst));
-
- // U1 alt
- values.Add(GetAlt(u1));
- }
- if (u2[5] == 1)
- {
- values.Add("-");
- values.Add("-");
- }
- else
- {
- // U2
- values.Add(GetTime(el, u2, obsvconst));
-
- // U2 alt
- values.Add(GetAlt(u2));
- }
- // mid
-
- values.Add(GetTime(el, mid, obsvconst));
-
- // mid alt
-
- values.Add(GetAlt(mid));
-
- if (u3[5] == 1)
- {
- values.Add("-");
- values.Add("-");
- }
- else
- {
- // u3
- values.Add(GetTime(el, u3, obsvconst));
-
- // u3 alt
- values.Add(GetAlt(u3));
- }
- if (u4[5] == 1)
- {
- values.Add("-");
- values.Add("-");
- }
- else
- {
- // u4
- values.Add(GetTime(el, u4, obsvconst));
-
- // u4 alt
- values.Add(GetAlt(u4));
-
- }
- // P4
- values.Add(GetTime(el, p4, obsvconst));
-
- // P4 alt
- values.Add(GetAlt(p4));
- events.Add(values);
- }
- }
- }
- return events;
- }
- // Read the data that's in the form, and populate the obsvconst array
- private static void ReadData(double latRad, double longRad, double[] obsvconst)
- {
-
- // Get the latitude
- obsvconst[0] = latRad;
-
- // Get the longitude
- obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN.
-
- // Get the altitude
- obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS.
-
- // Get the time zone
- obsvconst[3] = 0; //GMT TIME
-
- obsvconst[4] = 0; //INDEX
-
- //SET MAX ECLIPSE TYPE
- obsvconst[5] = 4;//4 is ALL Eclipses
-
- }
- // Populate the p1, u1, u2, mid, u3, u4 and p4 arrays
- private static void GetAll(double[] elements, double[] obsvconst, double[] mid, double[] p1, double[] u1, double[] u2, double[] u3, double[] u4, double[] p4)
- {
- int index = (int)obsvconst[4];
- p1[1] = elements[index + 9];
- PopulateCircumstances(elements, p1, obsvconst);
- mid[1] = elements[index + 12];
- PopulateCircumstances(elements, mid, obsvconst);
- p4[1] = elements[index + 15];
- PopulateCircumstances(elements, p4, obsvconst);
- if (elements[index + 5] < 3)
- {
- u1[1] = elements[index + 10];
- PopulateCircumstances(elements, u1, obsvconst);
- u4[1] = elements[index + 14];
- PopulateCircumstances(elements, u4, obsvconst);
- if (elements[index + 5] < 2)
- {
- u2[1] = elements[index + 11];
- u3[1] = elements[index + 13];
- PopulateCircumstances(elements, u2, obsvconst);
- PopulateCircumstances(elements, u3, obsvconst);
- }
- else
- {
- u2[5] = 1;
- u3[5] = 1;
- }
- }
- else
- {
- u1[5] = 1;
- u2[5] = 1;
- u3[5] = 1;
- u4[5] = 1;
- }
- if ((p1[5] != 0) && (u1[5] != 0) && (u2[5] != 0) && (mid[5] != 0) && (u3[5] != 0) && (u4[5] != 0) && (p4[5] != 0))
- {
- mid[5] = 1;
- }
- }
- // Populate the circumstances array
- // entry condition - circumstances[1] must contain the correct value
- private static void PopulateCircumstances(double[] elements, double[] circumstances, double[] obsvconst)
- {
- double t, ra, dec, h;
-
- int index = (int)obsvconst[4];
- t = circumstances[1];
- ra = elements[18 + index] * t + elements[17 + index];
- ra = ra * t + elements[16 + index];
- dec = elements[21 + index] * t + elements[20 + index];
- dec = dec * t + elements[19 + index];
- dec = dec * Math.PI / 180.0;
- circumstances[3] = dec;
- h = 15.0 * (elements[6 + index] + (t - elements[2 + index] / 3600.0) * 1.00273791) - ra;
- h = h * Math.PI / 180.0 - obsvconst[1];
- circumstances[2] = h;
- circumstances[4] = Math.Asin(Math.Sin(obsvconst[0]) * Math.Sin(dec) + Math.Cos(obsvconst[0]) * Math.Cos(dec) * Math.Cos(h));
- circumstances[4] -= Math.Asin(Math.Sin(elements[7 + index] * Math.PI / 180.0) * Math.Cos(circumstances[4]));
- if (circumstances[4] * 180.0 / Math.PI < elements[8 + index] - 0.5667)
- {
- circumstances[5] = 2;
- }
- else if (circumstances[4] < 0.0)
- {
- circumstances[4] = 0.0;
- circumstances[5] = 0;
- }
- else
- {
- circumstances[5] = 0;
- }
- }
- // Get the date of an event
- private static string GetDate(double[] elements, double[] circumstances, double[] obsvconst)
- {
- string[] month = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };//Month string array
- double t, jd, a, b, c, d, e;
- string ans = "";
- int index = (int)obsvconst[4];
- // Calculate the JD for noon (TDT) the day before the day that contains T0
- jd = Math.Floor(elements[index] - (elements[1 + index] / 24.0));
- // Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0).
- t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
-
- if (t < 0.0)
- {
- jd--;
- }
- if (t >= 24.0)
- {
- jd++;
- }
- if (jd >= 2299160.0)
- {
- a = Math.Floor((jd - 1867216.25) / 36524.25);
- a = jd + 1 + a - Math.Floor(a / 4.0);
- }
- else
- {
- a = jd;
- }
- b = a + 1525.0;
- c = Math.Floor((b - 122.1) / 365.25);
- d = Math.Floor(365.25 * c);
- e = Math.Floor((b - d) / 30.6001);
- d = b - d - Math.Floor(30.6001 * e);
- if (e < 13.5)
- {
- e = e - 1;
- }
- else
- {
- e = e - 13;
- }
- double year;
- if (e > 2.5)
- {
- ans = c - 4716 + "-";
- year = c - 4716;
- }
- else
- {
- ans = c - 4715 + "-";
- year = c - 4715;
- }
- string m = month[(int)e - 1];
- ans += m+ "-";
- if (d < 10)
- {
- ans = ans + "0";
- }
- ans = ans + d;
- //Leap Year Integrity Check
-
- if (m == "Feb" && d == 29 && !DateTime.IsLeapYear((int)year))
- {
- ans = year.ToString() + "-Mar-01";
- }
- return ans;
- }
- // Get the time of an event
- private static string GetTime(double[] elements, double[] circumstances, double[] obsvconst)
- {
- double t;
- string ans = "";
-
- int index = (int)obsvconst[4];
- t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
- if (t < 0.0)
- {
- t = t + 24.0;
- }
- if (t >= 24.0)
- {
- t = t - 24.0;
- }
- if (t < 10.0)
- {
- ans = ans + "0";
- }
- ans = ans + Math.Floor(t) + ":";
- t = (t * 60.0) - 60.0 * Math.Floor(t);
- if (t < 10.0)
- {
- ans = ans + "0";
- }
- ans = ans + Math.Floor(t);
- if (circumstances[5] == 2)
- {
- return ans; //RETURNED IN ITAL DETERMINE WHY
- }
- else
- {
- return ans;
- }
- }
- // Get the altitude
- private static string GetAlt(double[] circumstances)
- {
- double t;
- string ans = "";
- t = circumstances[4] * 180.0 / Math.PI;
- t = Math.Floor(t + 0.5);
- if (t < 0.0)
- {
- ans = "-";
- t = -t;
- }
- else
- {
- ans = "+";
- }
- if (t < 10.0)
- {
- ans = ans + "0";
- }
- ans = ans + t;
- if (circumstances[5] == 2)
- {
- return ans; //returned in italics determine why
-
- }
- else
- {
- return ans;
- }
- }
+ //CURRENT RANGE 1601-2600.
+ internal class LunarEclipseCalc {
+ public static List> CalculateLunarEclipse(DateTime d, Double latRad, Double longRad) => Calculate(d, latRad, longRad);
+ public static List CalculateLunarEclipse(DateTime d, Double latRad, Double longRad, Double[] events) {
+ List> evs = Calculate(d, latRad, longRad, events);
+ List deetsList = new List();
+ foreach (List ls in evs) {
+ LunarEclipseDetails deets = new LunarEclipseDetails(ls);
+ deetsList.Add(deets);
+ }
+ return deetsList;
}
+ public static List> CalculateLunarEclipse(DateTime d, Coordinate coord) => Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians());
+
+
+ // CALCULATE!
+ private static List> Calculate(DateTime d, Double latRad, Double longRad, Double[] ev = null) {
+ //DECLARE ARRAYS
+ Double[] obsvconst = new Double[6];
+ Double[] mid = new Double[41];
+ Double[] p1 = new Double[41];
+ Double[] u1 = new Double[41];
+ Double[] u2 = new Double[41];
+ Double[] u3 = new Double[41];
+ Double[] u4 = new Double[41];
+ Double[] p4 = new Double[41];
+
+ Double[] el = ev ?? Eclipse.LunarData.LunarDateData(d);
+ List> events = new List>();
+ ReadData(latRad, longRad, obsvconst);
+
+ for (Int32 i = 0; i < el.Length; i += 22) {
+ if (el[5 + i] <= obsvconst[5]) {
+ List values = new List();
+ obsvconst[4] = i;
+ GetAll(el, obsvconst, mid, p1, u1, u2, u3, u4, p4);
+ // Is there an event...
+ if (mid[5] != 1) {
+
+ values.Add(GetDate(el, p1, obsvconst));
+
+ if (el[5 + i] == 1) {
+ values.Add("T");
+ } else if (el[5 + i] == 2) {
+ values.Add("P");
+ } else {
+ values.Add("N");
+ }
+
+ // Pen. Mag
+ values.Add(el[3 + i].ToString());
+
+ // Umbral Mag
+ values.Add(el[4 + i].ToString());
+
+ // P1
+ values.Add(GetTime(el, p1, obsvconst));
+
+ // P1 alt
+ values.Add(GetAlt(p1));
+
+ if (u1[5] == 1) {
+ values.Add("-");
+ values.Add("-");
+ } else {
+ // U1
+ values.Add(GetTime(el, u1, obsvconst));
+
+ // U1 alt
+ values.Add(GetAlt(u1));
+ }
+ if (u2[5] == 1) {
+ values.Add("-");
+ values.Add("-");
+ } else {
+ // U2
+ values.Add(GetTime(el, u2, obsvconst));
+
+ // U2 alt
+ values.Add(GetAlt(u2));
+ }
+ // mid
+
+ values.Add(GetTime(el, mid, obsvconst));
+
+ // mid alt
+
+ values.Add(GetAlt(mid));
+
+ if (u3[5] == 1) {
+ values.Add("-");
+ values.Add("-");
+ } else {
+ // u3
+ values.Add(GetTime(el, u3, obsvconst));
+
+ // u3 alt
+ values.Add(GetAlt(u3));
+ }
+ if (u4[5] == 1) {
+ values.Add("-");
+ values.Add("-");
+ } else {
+ // u4
+ values.Add(GetTime(el, u4, obsvconst));
+
+ // u4 alt
+ values.Add(GetAlt(u4));
+
+ }
+ // P4
+ values.Add(GetTime(el, p4, obsvconst));
+
+ // P4 alt
+ values.Add(GetAlt(p4));
+ events.Add(values);
+ }
+ }
+ }
+ return events;
+ }
+ // Read the data that's in the form, and populate the obsvconst array
+ private static void ReadData(Double latRad, Double longRad, Double[] obsvconst) {
+
+ // Get the latitude
+ obsvconst[0] = latRad;
+
+ // Get the longitude
+ obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN.
+
+ // Get the altitude
+ obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS.
+
+ // Get the time zone
+ obsvconst[3] = 0; //GMT TIME
+
+ obsvconst[4] = 0; //INDEX
+
+ //SET MAX ECLIPSE TYPE
+ obsvconst[5] = 4;//4 is ALL Eclipses
+
+ }
+ // Populate the p1, u1, u2, mid, u3, u4 and p4 arrays
+ private static void GetAll(Double[] elements, Double[] obsvconst, Double[] mid, Double[] p1, Double[] u1, Double[] u2, Double[] u3, Double[] u4, Double[] p4) {
+ Int32 index = (Int32)obsvconst[4];
+ p1[1] = elements[index + 9];
+ PopulateCircumstances(elements, p1, obsvconst);
+ mid[1] = elements[index + 12];
+ PopulateCircumstances(elements, mid, obsvconst);
+ p4[1] = elements[index + 15];
+ PopulateCircumstances(elements, p4, obsvconst);
+ if (elements[index + 5] < 3) {
+ u1[1] = elements[index + 10];
+ PopulateCircumstances(elements, u1, obsvconst);
+ u4[1] = elements[index + 14];
+ PopulateCircumstances(elements, u4, obsvconst);
+ if (elements[index + 5] < 2) {
+ u2[1] = elements[index + 11];
+ u3[1] = elements[index + 13];
+ PopulateCircumstances(elements, u2, obsvconst);
+ PopulateCircumstances(elements, u3, obsvconst);
+ } else {
+ u2[5] = 1;
+ u3[5] = 1;
+ }
+ } else {
+ u1[5] = 1;
+ u2[5] = 1;
+ u3[5] = 1;
+ u4[5] = 1;
+ }
+ if (p1[5] != 0 && u1[5] != 0 && u2[5] != 0 && mid[5] != 0 && u3[5] != 0 && u4[5] != 0 && p4[5] != 0) {
+ mid[5] = 1;
+ }
+ }
+ // Populate the circumstances array
+ // entry condition - circumstances[1] must contain the correct value
+ private static void PopulateCircumstances(Double[] elements, Double[] circumstances, Double[] obsvconst) {
+ Double t, ra, dec, h;
+
+ Int32 index = (Int32)obsvconst[4];
+ t = circumstances[1];
+ ra = elements[18 + index] * t + elements[17 + index];
+ ra = ra * t + elements[16 + index];
+ dec = elements[21 + index] * t + elements[20 + index];
+ dec = dec * t + elements[19 + index];
+ dec = dec * Math.PI / 180.0;
+ circumstances[3] = dec;
+ h = 15.0 * (elements[6 + index] + (t - elements[2 + index] / 3600.0) * 1.00273791) - ra;
+ h = h * Math.PI / 180.0 - obsvconst[1];
+ circumstances[2] = h;
+ circumstances[4] = Math.Asin(Math.Sin(obsvconst[0]) * Math.Sin(dec) + Math.Cos(obsvconst[0]) * Math.Cos(dec) * Math.Cos(h));
+ circumstances[4] -= Math.Asin(Math.Sin(elements[7 + index] * Math.PI / 180.0) * Math.Cos(circumstances[4]));
+ if (circumstances[4] * 180.0 / Math.PI < elements[8 + index] - 0.5667) {
+ circumstances[5] = 2;
+ } else if (circumstances[4] < 0.0) {
+ circumstances[4] = 0.0;
+ circumstances[5] = 0;
+ } else {
+ circumstances[5] = 0;
+ }
+ }
+ // Get the date of an event
+ private static String GetDate(Double[] elements, Double[] circumstances, Double[] obsvconst) {
+ String[] month = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };//Month string array
+ Double t, jd, a, b, c, d, e;
+ Int32 index = (Int32)obsvconst[4];
+ // Calculate the JD for noon (TDT) the day before the day that contains T0
+ jd = Math.Floor(elements[index] - elements[1 + index] / 24.0);
+ // Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0).
+ t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
+
+ if (t < 0.0) {
+ jd--;
+ }
+ if (t >= 24.0) {
+ jd++;
+ }
+ if (jd >= 2299160.0) {
+ a = Math.Floor((jd - 1867216.25) / 36524.25);
+ a = jd + 1 + a - Math.Floor(a / 4.0);
+ } else {
+ a = jd;
+ }
+ b = a + 1525.0;
+ c = Math.Floor((b - 122.1) / 365.25);
+ d = Math.Floor(365.25 * c);
+ e = Math.Floor((b - d) / 30.6001);
+ d = b - d - Math.Floor(30.6001 * e);
+ e = e < 13.5 ? e - 1 : e - 13;
+ Double year;
+ String ans;
+ if (e > 2.5) {
+ ans = c - 4716 + "-";
+ year = c - 4716;
+ } else {
+ ans = c - 4715 + "-";
+ year = c - 4715;
+ }
+ String m = month[(Int32)e - 1];
+ ans += m + "-";
+ if (d < 10) {
+ ans += "0";
+ }
+ ans += d;
+ //Leap Year Integrity Check
+
+ if (m == "Feb" && d == 29 && !DateTime.IsLeapYear((Int32)year)) {
+ ans = year.ToString() + "-Mar-01";
+ }
+ return ans;
+ }
+ // Get the time of an event
+ private static String GetTime(Double[] elements, Double[] circumstances, Double[] obsvconst) {
+ Double t;
+ String ans = "";
+
+ Int32 index = (Int32)obsvconst[4];
+ t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
+ if (t < 0.0) {
+ t += 24.0;
+ }
+ if (t >= 24.0) {
+ t -= 24.0;
+ }
+ if (t < 10.0) {
+ ans += "0";
+ }
+ ans = ans + Math.Floor(t) + ":";
+ t = t * 60.0 - 60.0 * Math.Floor(t);
+ if (t < 10.0) {
+ ans += "0";
+ }
+ ans += Math.Floor(t);
+ if (circumstances[5] == 2) {
+ return ans; //RETURNED IN ITAL DETERMINE WHY
+ } else {
+ return ans;
+ }
+ }
+ // Get the altitude
+ private static String GetAlt(Double[] circumstances) {
+ Double t;
+ t = circumstances[4] * 180.0 / Math.PI;
+ t = Math.Floor(t + 0.5);
+ String ans;
+ if (t < 0.0) {
+ ans = "-";
+ t = -t;
+ } else {
+ ans = "+";
+ }
+ if (t < 10.0) {
+ ans += "0";
+ }
+ ans += t;
+ if (circumstances[5] == 2) {
+ return ans; //returned in italics determine why
+
+ } else {
+ return ans;
+ }
+ }
+ }
}
diff --git a/CoordinateSharp/Celestial.MeeusTables.cs b/CoordinateSharp/Celestial.MeeusTables.cs
index b5cc431..1f1cc4a 100644
--- a/CoordinateSharp/Celestial.MeeusTables.cs
+++ b/CoordinateSharp/Celestial.MeeusTables.cs
@@ -1,15 +1,10 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-namespace CoordinateSharp
-{
- internal partial class MeeusTables
+namespace CoordinateSharp {
+ internal partial class MeeusTables {
+ //Ch 47
+ private static readonly Double[] Table47A_Arguments = new Double[]
{
- //Ch 47
- private static double[] Table47A_Arguments = new double[]
- {
0,0,1,0,
2,0,-1,0,
2,0,0,0,
@@ -71,9 +66,9 @@ namespace CoordinateSharp
1,1,-1,0,
2,0,3,0,
2,0,-1,-2
- };
- private static double[] Table47B_Arguments = new double[]
- {
+ };
+ private static readonly Double[] Table47B_Arguments = new Double[]
+ {
0,0,0,1,
0,0,1,1,
0,0,1,-1,
@@ -135,9 +130,9 @@ namespace CoordinateSharp
1,0,-1,-1,
4,-1,0,-1,
2,-2,0,1,
- };
- private static double[] Table47A_El_Er = new double[]
- {
+ };
+ private static readonly Double[] Table47A_El_Er = new Double[]
+ {
//El
6288774, 1274027,658314,213618,-185116,-114332,58793,57066,53322,45758,
-40923,-34720,-30383,15327,-12528,10980,10675,10034,8548,-7888,-6766,-5163,
@@ -150,72 +145,58 @@ namespace CoordinateSharp
-12831,-10445,-11650,14403,-7003,0,10056,6322,-9884,5751,0,-4950,4130,0,-3958,0,3258,
2616,-1897,-2117,2354,0,0,-1423,-1117,-1571,-1739,0,-4421,0,0,0,0,1165,0,0,8752
- };
- private static double[] Table47B_Eb = new double[]
- {
+ };
+ private static readonly Double[] Table47B_Eb = new Double[]
+ {
5128122,280602,277693,173237,55413,46271,32573,17198,9266,8822,
8216,4324,4200,-3359,2463,2211,2065,-1870,1828,-1794,-1749,-1565,-1491,
-1475,-1410,-1344,-1335,1107,1021,833,
777,671,607,596,491,-451,439,422,421,-366,-351,331,315,302,-283,-229,
223,223,-220,-220,-185,181,-177,176,166,-164,132,-119,115,107
- };
- private static double Get_Table47A_Values(double[] values, int l, double t, bool sine)
- {
- //sine true returns El
- //sine false return Er
- //Er values start at 60 in the Table47A_El_Er array.
+ };
+ private static Double Get_Table47A_Values(Double[] values, Int32 l, Double t, Boolean sine) {
+ //sine true returns El
+ //sine false return Er
+ //Er values start at 60 in the Table47A_El_Er array.
- int nl = l * 4;
+ Int32 nl = l * 4;
- if (sine)
- {
- double e = 1;
+ if (sine) {
+ Double e = 1;
- if (Table47A_Arguments[nl + 1] != 0)
- {
- e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
+ if (Table47A_Arguments[nl + 1] != 0) {
+ e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
- if (Math.Abs(Table47A_Arguments[nl + 1]) == 2)
- {
- e *= e;
- }
- }
- return (Table47A_El_Er[l] * e) * Math.Sin(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] +
- Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
- }
- else
- {
- double e = 1;
- if (Table47A_Arguments[nl + 1] != 0)
- {
- e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
-
- if (Math.Abs(Table47A_Arguments[nl + 1]) == 2)
- {
- e *= e;
- }
- }
- return (Table47A_El_Er[l + 60] * e) * Math.Cos(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] +
- Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
- }
+ if (Math.Abs(Table47A_Arguments[nl + 1]) == 2) {
+ e *= e;
+ }
}
- private static double Get_Table47B_Values(double[] values, int l, double t)
- {
- int nl = l * 4;
- double e = 1;
+ return Table47A_El_Er[l] * e * Math.Sin(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] + Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
+ } else {
+ Double e = 1;
+ if (Table47A_Arguments[nl + 1] != 0) {
+ e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
- if (Table47B_Arguments[nl + 1] != 0)
- {
- e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
-
- if (Math.Abs(Table47B_Arguments[nl + 1]) == 2)
- {
- e *= e;
- }
- }
- return (Table47B_Eb[l] * e) * Math.Sin(Table47B_Arguments[nl] * values[0] + Table47B_Arguments[nl + 1] * values[1] +
- Table47B_Arguments[nl + 2] * values[2] + Table47B_Arguments[nl + 3] * values[3]);
+ if (Math.Abs(Table47A_Arguments[nl + 1]) == 2) {
+ e *= e;
+ }
}
+ return Table47A_El_Er[l + 60] * e * Math.Cos(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] + Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
+ }
}
+ private static Double Get_Table47B_Values(Double[] values, Int32 l, Double t) {
+ Int32 nl = l * 4;
+ Double e = 1;
+
+ if (Table47B_Arguments[nl + 1] != 0) {
+ e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
+
+ if (Math.Abs(Table47B_Arguments[nl + 1]) == 2) {
+ e *= e;
+ }
+ }
+ return Table47B_Eb[l] * e * Math.Sin(Table47B_Arguments[nl] * values[0] + Table47B_Arguments[nl + 1] * values[1] + Table47B_Arguments[nl + 2] * values[2] + Table47B_Arguments[nl + 3] * values[3]);
+ }
+ }
}
diff --git a/CoordinateSharp/Celestial.MoonCalculations.cs b/CoordinateSharp/Celestial.MoonCalculations.cs
index 972a266..977bd0f 100644
--- a/CoordinateSharp/Celestial.MoonCalculations.cs
+++ b/CoordinateSharp/Celestial.MoonCalculations.cs
@@ -1,872 +1,759 @@
using System;
using System.Collections.Generic;
-namespace CoordinateSharp
-{
- internal class MoonCalc
+namespace CoordinateSharp {
+ internal class MoonCalc {
+ static readonly Double rad = Math.PI / 180; //For converting radians
+
+ //obliquity of the ecliptic in radians based on standard equinox 2000.
+ static readonly Double e = rad * 23.4392911;
+ ///
+ /// Gets Moon Times, Altitude and Azimuth
+ ///
+ /// Date
+ /// Latitude
+ /// Longitude
+ /// Celestial
+ public static void GetMoonTimes(DateTime date, Double lat, Double lng, Celestial c) {
+ //Get current Moon Position to populate passed Alt / Azi for user specified date
+ MoonPosition mp = GetMoonPosition(date, lat, lng, c);
+ Double altRad = mp.Altitude / Math.PI * 180; //Convert alt to degrees
+ c.moonAltitude = altRad - mp.ParallaxCorection; //Set altitude with adjusted parallax
+ c.moonAzimuth = mp.Azimuth / Math.PI * 180 + 180; //Azimuth in degrees + 180 for E by N.
+
+ ////New Iterations for Moon set / rise
+ Boolean moonRise = false;
+ Boolean moonSet = false;
+
+ //Start at beginning of day
+ DateTime t = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc);
+
+ //Get start of day Moon Pos
+ MoonPosition moonPos = GetMoonPosition(t, lat, lng, c);
+ Double alt1 = moonPos.Altitude - moonPos.ParallaxCorection * rad;
+
+ DateTime? setTime = null;
+ DateTime? riseTime = null;
+ Double hz = -.3 * rad;//Horizon degrees at -.3 for appearant rise / set
+
+ //Iterate for each hour of the day
+ for (Int32 x = 1; x <= 24; x++) {
+ moonPos = GetMoonPosition(t.AddHours(x), lat, lng, c);//Get the next hours altitude for comparison
+ Double alt2 = moonPos.Altitude - moonPos.ParallaxCorection * rad;
+ //If hour 1 is below horizon and hour 2 is above
+ if (alt1 < hz && alt2 >= hz) {
+ //Moon Rise Occurred
+ moonRise = true;
+ DateTime dt1 = t.AddHours(x - 1);
+ moonPos = GetMoonPosition(dt1, lat, lng, c);//Get the next hours altitude for comparison
+ Double altM1 = moonPos.Altitude - moonPos.ParallaxCorection * rad;
+ //Iterate through each minute to determine at which minute the horizon is crossed.
+ //Interpolation is more efficient, but yielded results with deviations up to 5 minutes.
+ //Investigate formula efficiency
+ for (Int32 y = 1; y <= 60; y++) {
+ DateTime dt2 = t.AddHours(x - 1).AddMinutes(y);
+ moonPos = GetMoonPosition(dt2, lat, lng, c);//Get the next hours altitude for comparison
+ Double altM2 = moonPos.Altitude - moonPos.ParallaxCorection * rad;
+ if (altM1 < hz && altM2 >= hz) {
+ //interpolate seconds
+ Double p = 60 * ((hz - altM1) / (altM2 - altM1));
+ riseTime = dt1.AddMinutes(y - 1).AddSeconds(p);
+ break;
+ }
+ altM1 = altM2;
+
+ }
+ }
+ //if hour 2 is above horizon and hour 1 below
+ if (alt1 >= hz && alt2 < hz) {
+ //Moon Set Occured
+ moonSet = true;
+ DateTime dt1 = t.AddHours(x - 1);
+ moonPos = GetMoonPosition(dt1, lat, lng, c);//Get the next hours altitude for comparison
+ Double altM1 = moonPos.Altitude - moonPos.ParallaxCorection * rad;
+ //Iterate through each minute to determine at which minute the horizon is crossed.
+ //Interpolation is more efficient, but yielded results with deviations up to 5 minutes.
+ //Investigate formula efficiency
+ for (Int32 y = 1; y <= 60; y++) {
+ DateTime dt2 = t.AddHours(x - 1).AddMinutes(y);
+ moonPos = GetMoonPosition(dt2, lat, lng, c);//Get the next hours altitude for comparison
+ Double altM2 = moonPos.Altitude - moonPos.ParallaxCorection * rad;
+ if (altM1 >= hz && altM2 < hz) {
+ //Interpolate seconds
+ Double p = 60 * ((hz - altM2) / (altM1 - altM2));
+ setTime = dt1.AddMinutes(y).AddSeconds(-p);
+ break;
+ }
+ altM1 = altM2;
+
+ }
+ }
+ alt1 = alt2;
+ if (moonRise && moonSet) { break; }
+ }
+
+ c.moonSet = setTime;
+ c.moonRise = riseTime;
+ if (moonRise && moonSet) { c.moonCondition = CelestialStatus.RiseAndSet; } else {
+ if (!moonRise && !moonSet) {
+ c.moonCondition = alt1 >= 0 ? CelestialStatus.UpAllDay : CelestialStatus.DownAllDay;
+ }
+ if (!moonRise && moonSet) { c.moonCondition = CelestialStatus.NoRise; }
+ if (moonRise && !moonSet) { c.moonCondition = CelestialStatus.NoSet; }
+ }
+ }
+
+ private static MoonPosition GetMoonPosition(DateTime date, Double lat, Double lng, Celestial cel) {
+ //Set UTC date integrity
+ date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
+
+ Double d = JulianConversions.GetJulian_Epoch2000(date);
+
+ //Ch 47
+ Double JDE = JulianConversions.GetJulian(date);//Get julian
+
+ Double T = (JDE - 2451545) / 36525; //Get dynamic time.
+ Double[] LDMNF = Get_Moon_LDMNF(T);
+ CelCoords c = GetMoonCoords(d, cel, LDMNF, T);
+ Distance dist = GetMoonDistance(date);
+ Double lw = rad * -lng;
+ Double phi = rad * lat;
+
+ Double H = rad * MeeusFormulas.Get_Sidereal_Time(JDE) - lw - c.Ra;
+
+ Double ra = c.Ra; //Adjust current RA formula to avoid needless RAD conversions
+ Double dec = c.Dec; //Adjust current RA formula to avoid needless RAD conversions
+
+ //Adjust for parallax (low accuracry increases may not be worth cost)
+ //Investigate
+ Double pSinE = Get_pSinE(dec, dist.Meters) * Math.PI / 180;
+ Double pCosE = Get_pCosE(dec, dist.Meters) * Math.PI / 180;
+ Double cRA = Parallax_RA(dist.Meters, H, pCosE, dec, ra);
+ Double tDEC = Parallax_Dec(dist.Meters, H, pCosE, pSinE, dec, cRA);
+ //Double tRA = ra - cRA;
+ dec = tDEC;
+ //ra = tRA;
+
+ //Get true altitude
+ Double h = Altitude(H, phi, dec);
+
+ // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
+ Double pa = Math.Atan2(Math.Sin(H), Math.Tan(phi) * Math.Cos(dec) - Math.Sin(dec) * Math.Cos(H));
+
+ //altitude correction for refraction
+ h += AstroRefraction(h);
+
+ MoonPosition mp = new MoonPosition {
+ Azimuth = Azimuth(H, phi, dec),
+ Altitude = h / Math.PI * 180,
+ Distance = dist,
+ ParallacticAngle = pa
+ };
+
+ Double horParal = 8.794 / (dist.Meters / 149.59787E6); // horizontal parallax (arcseconds), Meeus S. 263
+ Double p = Math.Asin(Math.Cos(h) * Math.Sin(horParal / 3600)); // parallax in altitude (degrees)
+ p *= 1000;
+
+ mp.ParallaxCorection = p;
+ mp.Altitude *= rad;
+
+ return mp;
+ }
+ private static CelCoords GetMoonCoords(Double _1, Celestial _2, Double[] LDMNF, Double t) {
+ // Legacy function. Updated with Meeus Calcs for increased accuracy.
+ // geocentric ecliptic coordinates of the moon
+ // Meeus Ch 47
+ Double[] cs = Get_Moon_Coordinates(LDMNF, t);
+
+ Double l = cs[0]; // longitude
+ Double b = cs[1]; // latitude
+
+ CelCoords mc = new CelCoords {
+ Ra = RightAscension(l, b),
+ Dec = Declination(l, b)
+ };
+ //Double ra = mc.ra / Math.PI * 180;
+ //Double dec = mc.dec / Math.PI * 180;
+
+ return mc;
+ }
+
+ public static void GetMoonIllumination(DateTime date, Celestial c, Double lat, Double lng) {
+ date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
+
+ Double d = JulianConversions.GetJulian_Epoch2000(date);
+ CelCoords s = GetSunCoords(d);
+ Double JDE = JulianConversions.GetJulian(date);//Get julian
+ Double T = (JDE - 2451545) / 36525; //Get dynamic time.
+ Double[] LDMNF = Get_Moon_LDMNF(T);
+
+ CelCoords m = GetMoonCoords(d, c, LDMNF, T);
+
+ Double sdist = 149598000,
+ phi = Math.Acos(Math.Sin(s.Dec) * Math.Sin(m.Dec) + Math.Cos(s.Dec) * Math.Cos(m.Dec) * Math.Cos(s.Ra - m.Ra)),
+ inc = Math.Atan2(sdist * Math.Sin(phi), m.Dist - sdist * Math.Cos(phi)),
+ angle = Math.Atan2(Math.Cos(s.Dec) * Math.Sin(s.Ra - m.Ra), Math.Sin(s.Dec) * Math.Cos(m.Dec) -
+ Math.Cos(s.Dec) * Math.Sin(m.Dec) * Math.Cos(s.Ra - m.Ra));
+
+
+ MoonIllum mi = new MoonIllum {
+ Fraction = (1 + Math.Cos(inc)) / 2,
+ Phase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI,
+ Angle = angle
+ };
+
+
+ c.moonIllum = mi;
+
+ String moonName = "";
+ Int32 moonDate = 0;
+ //GET PHASE NAME
+
+ //CHECK MOON AT BEGINNING AT END OF DAY TO GET DAY PHASE
+ DateTime dMon = new DateTime(date.Year, date.Month, 1);
+ for (Int32 x = 1; x <= date.Day; x++) {
+ DateTime nDate = new DateTime(dMon.Year, dMon.Month, x, 0, 0, 0, DateTimeKind.Utc);
+ d = JulianConversions.GetJulian_Epoch2000(nDate);
+ s = GetSunCoords(d);
+ JDE = JulianConversions.GetJulian(nDate);//Get julian
+ T = (JDE - 2451545) / 36525; //Get dynamic time.
+ LDMNF = Get_Moon_LDMNF(T);
+ m = GetMoonCoords(d, c, LDMNF, T);
+
+ phi = Math.Acos(Math.Sin(s.Dec) * Math.Sin(m.Dec) + Math.Cos(s.Dec) * Math.Cos(m.Dec) * Math.Cos(s.Ra - m.Ra));
+ inc = Math.Atan2(sdist * Math.Sin(phi), m.Dist - sdist * Math.Cos(phi));
+ angle = Math.Atan2(Math.Cos(s.Dec) * Math.Sin(s.Ra - m.Ra), Math.Sin(s.Dec) * Math.Cos(m.Dec) -
+ Math.Cos(s.Dec) * Math.Sin(m.Dec) * Math.Cos(s.Ra - m.Ra));
+
+ Double startPhase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
+
+ nDate = new DateTime(dMon.Year, dMon.Month, x, 23, 59, 59, DateTimeKind.Utc);
+ d = JulianConversions.GetJulian_Epoch2000(nDate);
+ s = GetSunCoords(d);
+ JDE = JulianConversions.GetJulian(nDate);//Get julian
+ T = (JDE - 2451545) / 36525; //Get dynamic time.
+ LDMNF = Get_Moon_LDMNF(T);
+ m = GetMoonCoords(d, c, LDMNF, T);
+
+ phi = Math.Acos(Math.Sin(s.Dec) * Math.Sin(m.Dec) + Math.Cos(s.Dec) * Math.Cos(m.Dec) * Math.Cos(s.Ra - m.Ra));
+ inc = Math.Atan2(sdist * Math.Sin(phi), m.Dist - sdist * Math.Cos(phi));
+ angle = Math.Atan2(Math.Cos(s.Dec) * Math.Sin(s.Ra - m.Ra), Math.Sin(s.Dec) * Math.Cos(m.Dec) -
+ Math.Cos(s.Dec) * Math.Sin(m.Dec) * Math.Cos(s.Ra - m.Ra));
+
+ Double endPhase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
+ //Determine Moon Name.
+ if (startPhase <= .5 && endPhase >= .5) {
+ moonDate = x;
+ moonName = GetMoonName(dMon.Month, moonName);
+ }
+ //Get Moon Name (month, string);
+ //Get Moon Phase Name
+ if (date.Day == x) {
+ if (startPhase > endPhase) {
+ mi.PhaseName = "New Moon";
+ break;
+ }
+ if (startPhase <= .25 && endPhase >= .25) {
+ mi.PhaseName = "First Quarter";
+ break;
+ }
+ if (startPhase <= .5 && endPhase >= .5) {
+ mi.PhaseName = "Full Moon";
+ break;
+ }
+ if (startPhase <= .75 && endPhase >= .75) {
+ mi.PhaseName = "Last Quarter";
+ break;
+ }
+
+ if (startPhase > 0 && startPhase < .25 && endPhase > 0 && endPhase < .25) {
+ mi.PhaseName = "Waxing Crescent";
+ break;
+ }
+ if (startPhase > .25 && startPhase < .5 && endPhase > .25 && endPhase < .5) {
+ mi.PhaseName = "Waxing Gibbous";
+ break;
+ }
+ if (startPhase > .5 && startPhase < .75 && endPhase > .5 && endPhase < .75) {
+ mi.PhaseName = "Waning Gibbous";
+ break;
+ }
+ if (startPhase > .75 && startPhase < 1 && endPhase > .75 && endPhase < 1) {
+ mi.PhaseName = "Waning Crescent";
+ break;
+ }
+ }
+
+ }
+ c.AstrologicalSigns.MoonName = date.Day == moonDate ? moonName : "";
+ CalculateLunarEclipse(date, lat, lng, c);
+
+ }
+ public static void CalculateLunarEclipse(DateTime date, Double lat, Double longi, Celestial c) {
+ //Convert to Radian
+ Double latR = lat * Math.PI / 180;
+ Double longR = longi * Math.PI / 180;
+ List> se = LunarEclipseCalc.CalculateLunarEclipse(date, latR, longR);
+ //RETURN FIRST AND LAST
+ if (se.Count == 0) { return; }
+ //FIND LAST AND NEXT ECLIPSE
+ Int32 lastE = -1;
+ Int32 nextE = -1;
+ Int32 currentE = 0;
+ DateTime lastDate = new DateTime();
+ DateTime nextDate = new DateTime(3300, 1, 1);
+ //Iterate to get last and next eclipse
+
+ foreach (List values in se) {
+ DateTime ld = DateTime.ParseExact(values[0], "yyyy-MMM-dd", System.Globalization.CultureInfo.InvariantCulture);
+ if (ld < date && ld > lastDate) { lastDate = ld; lastE = currentE; }
+ if (ld >= date && ld < nextDate) { nextDate = ld; nextE = currentE; }
+ currentE++;
+ }
+ //SET ECLIPSE DATA
+ if (lastE >= 0) {
+ c.LunarEclipse.LastEclipse = new LunarEclipseDetails(se[lastE]);
+ }
+ if (nextE >= 0) {
+ c.LunarEclipse.NextEclipse = new LunarEclipseDetails(se[nextE]);
+ }
+ }
+
+ private static String GetMoonName(Int32 month, String name) => name != "" ? "Blue Moon" : (month switch
{
- static double rad = Math.PI / 180; //For converting radians
+ 1 => "Wolf Moon",
+ 2 => "Snow Moon",
+ 3 => "Worm Moon",
+ 4 => "Pink Moon",
+ 5 => "Flower Moon",
+ 6 => "Strawberry Moon",
+ 7 => "Buck Moon",
+ 8 => "Sturgeon Moon",
+ 9 => "Corn Moon",
+ 10 => "Hunters Moon",
+ 11 => "Beaver Moon",
+ 12 => "Cold Moon",
+ _ => "",
+ });
+ public static void GetMoonDistance(DateTime date, Celestial c) {
+ date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
- //obliquity of the ecliptic in radians based on standard equinox 2000.
- static double e = rad * 23.4392911;
- ///
- /// Gets Moon Times, Altitude and Azimuth
- ///
- /// Date
- /// Latitude
- /// Longitude
- /// Celestial
- public static void GetMoonTimes(DateTime date, double lat, double lng, Celestial c)
- {
- //Get current Moon Position to populate passed Alt / Azi for user specified date
- MoonPosition mp = GetMoonPosition(date, lat, lng, c);
- double altRad = mp.Altitude / Math.PI*180; //Convert alt to degrees
- c.moonAltitude = (altRad - mp.ParallaxCorection); //Set altitude with adjusted parallax
- c.moonAzimuth = mp.Azimuth / Math.PI*180 + 180; //Azimuth in degrees + 180 for E by N.
-
- ////New Iterations for Moon set / rise
- bool moonRise = false;
- bool moonSet = false;
-
- //Start at beginning of day
- DateTime t = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc);
-
- //Get start of day Moon Pos
- MoonPosition moonPos = GetMoonPosition(t, lat, lng, c);
- double alt1 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
-
- DateTime? setTime = null;
- DateTime? riseTime = null;
- double hz = -.3 * rad;//Horizon degrees at -.3 for appearant rise / set
-
- //Iterate for each hour of the day
- for(int x = 1;x<=24;x++)
- {
- moonPos = GetMoonPosition(t.AddHours(x), lat, lng, c);//Get the next hours altitude for comparison
- double alt2 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
- //If hour 1 is below horizon and hour 2 is above
- if(alt1 =hz)
- {
- //Moon Rise Occurred
- moonRise = true;
- DateTime dt1 = t.AddHours(x - 1);
- moonPos = GetMoonPosition(dt1, lat, lng, c);//Get the next hours altitude for comparison
- double altM1 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
- //Iterate through each minute to determine at which minute the horizon is crossed.
- //Interpolation is more efficient, but yielded results with deviations up to 5 minutes.
- //Investigate formula efficiency
- for (int y = 1;y<=60;y++)
- {
- DateTime dt2 = t.AddHours(x-1).AddMinutes(y);
- moonPos = GetMoonPosition(dt2, lat, lng, c);//Get the next hours altitude for comparison
- double altM2 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
- if (altM1=hz)
- {
- //interpolate seconds
- double p = 60 * ((hz - altM1) / (altM2 - altM1));
- riseTime = dt1.AddMinutes(y-1).AddSeconds(p);
- break;
- }
- altM1 = altM2;
-
- }
- }
- //if hour 2 is above horizon and hour 1 below
- if(alt1>=hz && alt2 = hz && altM2 < hz)
- {
- //Interpolate seconds
- double p = 60 * ((hz - altM2) / (altM1 - altM2));
- setTime = dt1.AddMinutes(y).AddSeconds(-p);
- break;
- }
- altM1 = altM2;
-
- }
- }
- alt1 = alt2;
- if(moonRise && moonSet) { break; }
- }
-
- c.moonSet = setTime;
- c.moonRise = riseTime;
- if (moonRise && moonSet) { c.moonCondition = CelestialStatus.RiseAndSet; }
- else
- {
- if (!moonRise && !moonSet)
- {
- if (alt1 >= 0) { c.moonCondition = CelestialStatus.UpAllDay; }
- else { c.moonCondition = CelestialStatus.DownAllDay; }
- }
- if (!moonRise && moonSet) { c.moonCondition = CelestialStatus.NoRise; }
- if (moonRise && !moonSet) { c.moonCondition = CelestialStatus.NoSet; }
- }
- }
-
- private static MoonPosition GetMoonPosition(DateTime date, double lat, double lng, Celestial cel)
- {
- //Set UTC date integrity
- date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
-
- double d = JulianConversions.GetJulian_Epoch2000(date);
-
- //Ch 47
- double JDE = JulianConversions.GetJulian(date);//Get julian
-
- double T = (JDE - 2451545) / 36525; //Get dynamic time.
- double[] LDMNF = Get_Moon_LDMNF(T);
- CelCoords c = GetMoonCoords(d, cel, LDMNF, T);
- Distance dist = GetMoonDistance(date);
- double lw = rad * -lng;
- double phi = rad * lat;
-
- double H = rad * MeeusFormulas.Get_Sidereal_Time(JDE) - lw - c.ra;
-
- double ra = c.ra; //Adjust current RA formula to avoid needless RAD conversions
- double dec = c.dec; //Adjust current RA formula to avoid needless RAD conversions
-
- //Adjust for parallax (low accuracry increases may not be worth cost)
- //Investigate
- double pSinE = Get_pSinE(dec, dist.Meters) * Math.PI / 180;
- double pCosE = Get_pCosE(dec, dist.Meters) * Math.PI / 180;
- double cRA = Parallax_RA(dist.Meters, H, pCosE, dec, ra);
- double tDEC = Parallax_Dec(dist.Meters, H, pCosE, pSinE, dec, cRA);
- double tRA = ra - cRA;
- dec = tDEC;
- ra = tRA;
-
- //Get true altitude
- double h = altitude(H, phi, dec);
-
- // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
- double pa = Math.Atan2(Math.Sin(H), Math.Tan(phi) * Math.Cos(dec) - Math.Sin(dec) * Math.Cos(H));
-
- //altitude correction for refraction
- h = h + astroRefraction(h);
-
- MoonPosition mp = new MoonPosition();
- mp.Azimuth = azimuth(H, phi, dec);
- mp.Altitude = h / Math.PI * 180;
- mp.Distance = dist;
- mp.ParallacticAngle = pa;
-
- double horParal = 8.794 / (dist.Meters / 149.59787E6); // horizontal parallax (arcseconds), Meeus S. 263
- double p = Math.Asin(Math.Cos(h) * Math.Sin(horParal/3600)); // parallax in altitude (degrees)
- p *= 1000;
-
- mp.ParallaxCorection = p;
- mp.Altitude *= rad;
-
- return mp;
- }
- private static CelCoords GetMoonCoords(double d, Celestial c, double[] LDMNF, double t)
- {
- // Legacy function. Updated with Meeus Calcs for increased accuracy.
- // geocentric ecliptic coordinates of the moon
- // Meeus Ch 47
- double[] cs = Get_Moon_Coordinates(LDMNF, t);
-
- double l = cs[0]; // longitude
- double b = cs[1]; // latitude
-
- CelCoords mc = new CelCoords();
-
- mc.ra = rightAscension(l, b);
- double ra = mc.ra / Math.PI * 180;
-
- mc.dec = declination(l, b);
- double dec = mc.dec / Math.PI * 180;
-
- return mc;
- }
-
- public static void GetMoonIllumination(DateTime date, Celestial c, double lat, double lng)
- {
- date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
-
- double d = JulianConversions.GetJulian_Epoch2000(date);
- CelCoords s = GetSunCoords(d);
- double JDE = JulianConversions.GetJulian(date);//Get julian
- double T = (JDE - 2451545) / 36525; //Get dynamic time.
- double[] LDMNF = Get_Moon_LDMNF(T);
-
- CelCoords m = GetMoonCoords(d, c,LDMNF, T);
-
- double sdist = 149598000,
- phi = Math.Acos(Math.Sin(s.dec) * Math.Sin(m.dec) + Math.Cos(s.dec) * Math.Cos(m.dec) * Math.Cos(s.ra - m.ra)),
- inc = Math.Atan2(sdist * Math.Sin(phi), m.dist - sdist * Math.Cos(phi)),
- angle = Math.Atan2(Math.Cos(s.dec) * Math.Sin(s.ra - m.ra), Math.Sin(s.dec) * Math.Cos(m.dec) -
- Math.Cos(s.dec) * Math.Sin(m.dec) * Math.Cos(s.ra - m.ra));
-
-
- MoonIllum mi = new MoonIllum();
-
- mi.Fraction = (1 + Math.Cos(inc)) / 2;
- mi.Phase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
- mi.Angle = angle;
-
-
- c.moonIllum = mi;
-
- string moonName = "";
- int moonDate = 0;
- //GET PHASE NAME
-
- //CHECK MOON AT BEGINNING AT END OF DAY TO GET DAY PHASE
- DateTime dMon = new DateTime(date.Year, date.Month, 1);
- for(int x = 1;x<= date.Day;x++)
- {
- DateTime nDate = new DateTime(dMon.Year, dMon.Month, x, 0, 0, 0, DateTimeKind.Utc);
- d = JulianConversions.GetJulian_Epoch2000(nDate);
- s = GetSunCoords(d);
- JDE = JulianConversions.GetJulian(nDate);//Get julian
- T = (JDE - 2451545) / 36525; //Get dynamic time.
- LDMNF = Get_Moon_LDMNF(T);
- m = GetMoonCoords(d, c,LDMNF,T);
-
- phi = Math.Acos(Math.Sin(s.dec) * Math.Sin(m.dec) + Math.Cos(s.dec) * Math.Cos(m.dec) * Math.Cos(s.ra - m.ra));
- inc = Math.Atan2(sdist * Math.Sin(phi), m.dist - sdist * Math.Cos(phi));
- angle = Math.Atan2(Math.Cos(s.dec) * Math.Sin(s.ra - m.ra), Math.Sin(s.dec) * Math.Cos(m.dec) -
- Math.Cos(s.dec) * Math.Sin(m.dec) * Math.Cos(s.ra - m.ra));
-
- double startPhase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
-
- nDate = new DateTime(dMon.Year, dMon.Month, x, 23, 59, 59, DateTimeKind.Utc);
- d = JulianConversions.GetJulian_Epoch2000(nDate);
- s = GetSunCoords(d);
- JDE = JulianConversions.GetJulian(nDate);//Get julian
- T = (JDE - 2451545) / 36525; //Get dynamic time.
- LDMNF = Get_Moon_LDMNF(T);
- m = GetMoonCoords(d, c,LDMNF,T);
-
- phi = Math.Acos(Math.Sin(s.dec) * Math.Sin(m.dec) + Math.Cos(s.dec) * Math.Cos(m.dec) * Math.Cos(s.ra - m.ra));
- inc = Math.Atan2(sdist * Math.Sin(phi), m.dist - sdist * Math.Cos(phi));
- angle = Math.Atan2(Math.Cos(s.dec) * Math.Sin(s.ra - m.ra), Math.Sin(s.dec) * Math.Cos(m.dec) -
- Math.Cos(s.dec) * Math.Sin(m.dec) * Math.Cos(s.ra - m.ra));
-
- double endPhase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
- //Determine Moon Name.
- if (startPhase <= .5 && endPhase >= .5)
- {
- moonDate = x;
- moonName = GetMoonName(dMon.Month, moonName);
- }
- //Get Moon Name (month, string);
- //Get Moon Phase Name
- if (date.Day == x)
- {
- if (startPhase > endPhase)
- {
- mi.PhaseName = "New Moon";
- break;
- }
- if (startPhase <= .25 && endPhase >= .25)
- {
- mi.PhaseName = "First Quarter";
- break;
- }
- if (startPhase <= .5 && endPhase >= .5)
- {
- mi.PhaseName = "Full Moon";
- break;
- }
- if (startPhase <= .75 && endPhase >= .75)
- {
- mi.PhaseName = "Last Quarter";
- break;
- }
-
- if (startPhase > 0 && startPhase < .25 && endPhase > 0 && endPhase < .25)
- {
- mi.PhaseName = "Waxing Crescent";
- break;
- }
- if (startPhase > .25 && startPhase < .5 && endPhase > .25 && endPhase < .5)
- {
- mi.PhaseName = "Waxing Gibbous";
- break;
- }
- if (startPhase > .5 && startPhase < .75 && endPhase > .5 && endPhase < .75)
- {
- mi.PhaseName = "Waning Gibbous";
- break;
- }
- if (startPhase > .75 && startPhase < 1 && endPhase > .75 && endPhase < 1)
- {
- mi.PhaseName = "Waning Crescent";
- break;
- }
- }
-
- }
- if (date.Day == moonDate)
- {
- c.AstrologicalSigns.MoonName = moonName;
- }
- else { c.AstrologicalSigns.MoonName = ""; }
- CalculateLunarEclipse(date, lat, lng, c);
-
- }
- public static void CalculateLunarEclipse(DateTime date, double lat, double longi, Celestial c)
- {
- //Convert to Radian
- double latR = lat * Math.PI / 180;
- double longR = longi * Math.PI / 180;
- List> se = LunarEclipseCalc.CalculateLunarEclipse(date, latR, longR);
- //RETURN FIRST AND LAST
- if (se.Count == 0) { return; }
- //FIND LAST AND NEXT ECLIPSE
- int lastE = -1;
- int nextE = -1;
- int currentE = 0;
- DateTime lastDate = new DateTime();
- DateTime nextDate = new DateTime(3300, 1, 1);
- //Iterate to get last and next eclipse
-
- foreach (List values in se)
- {
- DateTime ld = DateTime.ParseExact(values[0], "yyyy-MMM-dd", System.Globalization.CultureInfo.InvariantCulture);
- if (ld < date && ld > lastDate) { lastDate = ld; lastE = currentE; }
- if (ld >= date && ld < nextDate) { nextDate = ld; nextE = currentE; }
- currentE++;
- }
- //SET ECLIPSE DATA
- if (lastE >= 0)
- {
- c.LunarEclipse.LastEclipse = new LunarEclipseDetails(se[lastE]);
- }
- if (nextE >= 0)
- {
- c.LunarEclipse.NextEclipse = new LunarEclipseDetails(se[nextE]);
- }
- }
-
- private static string GetMoonName(int month, string name)
- {
- if (name != "") { return "Blue Moon"; }
- switch (month)
- {
- case 1:
- return "Wolf Moon";
- case 2:
- return "Snow Moon";
- case 3:
- return "Worm Moon";
- case 4:
- return "Pink Moon";
- case 5:
- return "Flower Moon";
- case 6:
- return "Strawberry Moon";
- case 7:
- return "Buck Moon";
- case 8:
- return "Sturgeon Moon";
- case 9:
- return "Corn Moon";
- case 10:
- return "Hunters Moon";
- case 11:
- return "Beaver Moon";
- case 12:
- return "Cold Moon";
- default:
- return "";
- }
- }
- public static void GetMoonDistance(DateTime date, Celestial c)
- {
- date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
-
- c.moonDistance = GetMoonDistance(date); //Updating distance formula
- }
- //Moon Time Functions
- private static CelCoords GetSunCoords(double d)
- {
- double M = solarMeanAnomaly(d),
- L = eclipticLongitude(M);
- CelCoords c = new CelCoords();
- c.dec = declination(L, 0);
- c.ra = rightAscension(L, 0);
- return c;
- }
- private static double solarMeanAnomaly(double d) { return rad * (357.5291 + 0.98560028 * d); }
- private static double eclipticLongitude(double M)
- {
- double C = rad * (1.9148 * Math.Sin(M) + 0.02 * Math.Sin(2 * M) + 0.0003 * Math.Sin(3 * M)), // equation of center
+ c.moonDistance = GetMoonDistance(date); //Updating distance formula
+ }
+ //Moon Time Functions
+ private static CelCoords GetSunCoords(Double d) {
+ Double M = SolarMeanAnomaly(d),
+ L = EclipticLongitude(M);
+ CelCoords c = new CelCoords {
+ Dec = Declination(L, 0),
+ Ra = RightAscension(L, 0)
+ };
+ return c;
+ }
+ private static Double SolarMeanAnomaly(Double d) => rad * (357.5291 + 0.98560028 * d);
+ private static Double EclipticLongitude(Double M) {
+ Double C = rad * (1.9148 * Math.Sin(M) + 0.02 * Math.Sin(2 * M) + 0.0003 * Math.Sin(3 * M)), // equation of center
P = rad * 102.9372; // perihelion of the Earth
- return M + C + P + Math.PI;
- }
+ return M + C + P + Math.PI;
+ }
- public static void GetMoonSign(DateTime date, Celestial c)
- {
- //Formulas taken from https://www.astrocal.co.uk/moon-sign-calculator/
- double d = date.Day;
- double m = date.Month;
- double y = date.Year;
- double hr = date.Hour;
- double mi = date.Minute;
+ public static void GetMoonSign(DateTime date, Celestial c) {
+ //Formulas taken from https://www.astrocal.co.uk/moon-sign-calculator/
+ Double d = date.Day;
+ Double m = date.Month;
+ Double y = date.Year;
+ Double hr = date.Hour;
+ Double mi = date.Minute;
- double f = hr + (mi / 60);
- double im = 12 * (y + 4800) + m - 3;
- double j = (2 * (im - Math.Floor(im / 12) * 12) + 7 + 365 * im) / 12;
- j = Math.Floor(j) + d + Math.Floor(im / 48) - 32083;
- double jd = j + Math.Floor(im / 4800) - Math.Floor(im / 1200) + 38;
- double T = ((jd - 2415020) + f / 24 - .5) / 36525;
- double ob = FNr(23.452294 - .0130125 * T);
- double ll = 973563 + 1732564379 * T - 4 * T * T;
- double g = 1012395 + 6189 * T;
- double n = 933060 - 6962911 * T + 7.5 * T * T;
- double g1 = 1203586 + 14648523 * T - 37 * T * T;
- d = 1262655 + 1602961611 * T - 5 * T * T;
- double M = 3600;
- double l = (ll - g1) / M;
- double l1 = ((ll - d) - g) / M;
- f = (ll - n) / M;
- d = d / M;
- y = 2 * d;
- double ml = 22639.6 * FNs(l) - 4586.4 * FNs(l - y);
- ml = ml + 2369.9 * FNs(y) + 769 * FNs(2 * l) - 669 * FNs(l1);
- ml = ml - 411.6 * FNs(2 * f) - 212 * FNs(2 * l - y);
- ml = ml - 206 * FNs(l + l1 - y) + 192 * FNs(l + y);
- ml = ml - 165 * FNs(l1 - y) + 148 * FNs(l - l1) - 125 * FNs(d);
- ml = ml - 110 * FNs(l + l1) - 55 * FNs(2 * f - y);
- ml = ml - 45 * FNs(l + 2 * f) + 40 * FNs(l - 2 * f);
- double tn = n + 5392 * FNs(2 * f - y) - 541 * FNs(l1) - 442 * FNs(y);
- tn = tn + 423 * FNs(2 * f) - 291 * FNs(2 * l - 2 * f);
- g = FNu(FNp(ll + ml));
- double sign = Math.Floor(g / 30);
- double degree = (g - (sign * 30));
- sign = sign + 1;
+ Double f = hr + mi / 60;
+ Double im = 12 * (y + 4800) + m - 3;
+ Double j = (2 * (im - Math.Floor(im / 12) * 12) + 7 + 365 * im) / 12;
+ j = Math.Floor(j) + d + Math.Floor(im / 48) - 32083;
+ Double jd = j + Math.Floor(im / 4800) - Math.Floor(im / 1200) + 38;
+ Double T = (jd - 2415020 + f / 24 - .5) / 36525;
+ //Double ob = FNr(23.452294 - .0130125 * T);
+ Double ll = 973563 + 1732564379 * T - 4 * T * T;
+ Double g = 1012395 + 6189 * T;
+ Double n = 933060 - 6962911 * T + 7.5 * T * T;
+ Double g1 = 1203586 + 14648523 * T - 37 * T * T;
+ d = 1262655 + 1602961611 * T - 5 * T * T;
+ Double M = 3600;
+ Double l = (ll - g1) / M;
+ Double l1 = (ll - d - g) / M;
+ f = (ll - n) / M;
+ d /= M;
+ y = 2 * d;
+ Double ml = 22639.6 * FNs(l) - 4586.4 * FNs(l - y);
+ ml = ml + 2369.9 * FNs(y) + 769 * FNs(2 * l) - 669 * FNs(l1);
+ ml = ml - 411.6 * FNs(2 * f) - 212 * FNs(2 * l - y);
+ ml = ml - 206 * FNs(l + l1 - y) + 192 * FNs(l + y);
+ ml = ml - 165 * FNs(l1 - y) + 148 * FNs(l - l1) - 125 * FNs(d);
+ ml = ml - 110 * FNs(l + l1) - 55 * FNs(2 * f - y);
+ ml = ml - 45 * FNs(l + 2 * f) + 40 * FNs(l - 2 * f);
+ //Double tn = n + 5392 * FNs(2 * f - y) - 541 * FNs(l1) - 442 * FNs(y);
+ //tn = tn + 423 * FNs(2 * f) - 291 * FNs(2 * l - 2 * f);
+ g = FNu(FNp(ll + ml));
+ Double sign = Math.Floor(g / 30);
+ //Double degree = g - sign * 30;
+ sign += 1;
- switch (sign.ToString())
- {
- case "1": c.AstrologicalSigns.MoonSign = "Aries"; break;
- case "2": c.AstrologicalSigns.MoonSign = "Taurus"; break;
- case "3": c.AstrologicalSigns.MoonSign = "Gemini"; break;
- case "4": c.AstrologicalSigns.MoonSign = "Cancer"; break;
- case "5": c.AstrologicalSigns.MoonSign = "Leo"; break;
- case "6": c.AstrologicalSigns.MoonSign = "Virgo"; break;
- case "7": c.AstrologicalSigns.MoonSign = "Libra"; break;
- case "8": c.AstrologicalSigns.MoonSign = "Scorpio"; break;
- case "9": c.AstrologicalSigns.MoonSign = "Sagitarius"; break;
- case "10": c.AstrologicalSigns.MoonSign = "Capricorn"; break;
- case "11": c.AstrologicalSigns.MoonSign = "Aquarius"; break;
- case "12": c.AstrologicalSigns.MoonSign = "Pisces"; break;
- default: c.AstrologicalSigns.MoonSign = "Pisces"; break;
- }
+ c.AstrologicalSigns.MoonSign = (sign.ToString()) switch
+ {
+ "1" => "Aries",
+ "2" => "Taurus",
+ "3" => "Gemini",
+ "4" => "Cancer",
+ "5" => "Leo",
+ "6" => "Virgo",
+ "7" => "Libra",
+ "8" => "Scorpio",
+ "9" => "Sagitarius",
+ "10" => "Capricorn",
+ "11" => "Aquarius",
+ "12" => "Pisces",
+ _ => "Pisces",
+ };
+ }
- }
+ private static Double FNp(Double x) {
+ Double sgn = x < 0 ? -1 : 1;
+ return sgn * (Math.Abs(x) / 3600 / 360 - Math.Floor(Math.Abs(x) / 3600.0 / 360.0)) * 360;
+ }
+ private static Double FNu(Double x) => x - Math.Floor(x / 360) * 360;
+ //private static Double FNr(Double x) => Math.PI / 180 * x;
+ private static Double FNs(Double x) => Math.Sin(Math.PI / 180 * x);
- private static double FNp(double x)
- {
- double sgn;
- if (x < 0)
- { sgn = -1; }
- else
- { sgn = 1; }
- return sgn * ((Math.Abs(x) / 3600) / 360 - Math.Floor((Math.Abs(x) / 3600.0) / 360.0)) * 360;
- }
- private static double FNu(double x)
- { return x - (Math.Floor(x / 360) * 360); }
- private static double FNr(double x)
- { return Math.PI / 180 * x; }
- private static double FNs(double x)
- { return Math.Sin(Math.PI / 180 * x); }
+ //v1.1.3 Formulas
+ //The following formulas are either additions
+ //or conversions of SunCalcs formulas into Meeus
- //v1.1.3 Formulas
- //The following formulas are either additions
- //or conversions of SunCalcs formulas into Meeus
+ ///
+ /// Grabs Perigee or Apogee of Moon based on specified time.
+ /// Results will return event just before, or just after specified DateTime
+ ///
+ /// DateTime
+ /// Event Type
+ /// PerigeeApogee
+ private static PerigeeApogee MoonPerigeeOrApogee(DateTime d, MoonDistanceType md) {
+ //Perigee & Apogee Algorithms from Jean Meeus Astronomical Algorithms Ch. 50
- ///
- /// Grabs Perigee or Apogee of Moon based on specified time.
- /// Results will return event just before, or just after specified DateTime
- ///
- /// DateTime
- /// Event Type
- /// PerigeeApogee
- private static PerigeeApogee MoonPerigeeOrApogee(DateTime d, MoonDistanceType md)
- {
- //Perigee & Apogee Algorithms from Jean Meeus Astronomical Algorithms Ch. 50
+ //50.1
+ //JDE = 2451534.6698 + 27.55454989 * k
+ // -0.0006691 * Math.Pow(T,2)
+ // -0.000.01098 * Math.Pow(T,3)
+ // -0.0000000052 * Math.Pow(T,4)
- //50.1
- //JDE = 2451534.6698 + 27.55454989 * k
- // -0.0006691 * Math.Pow(T,2)
- // -0.000.01098 * Math.Pow(T,3)
- // -0.0000000052 * Math.Pow(T,4)
+ //50.2
+ //K approx = (yv - 1999.97)*13.2555
+ //yv is the year + percentage of days that have occured in the year. 1998 Oct 1 is approx 1998.75
+ //k ending in .0 represent perigee and .5 apogee. Anything > .5 is an error.
- //50.2
- //K approx = (yv - 1999.97)*13.2555
- //yv is the year + percentage of days that have occured in the year. 1998 Oct 1 is approx 1998.75
- //k ending in .0 represent perigee and .5 apogee. Anything > .5 is an error.
+ //50.3
+ //T = k/1325.55
- //50.3
- //T = k/1325.55
+ Double yt = 365; //days in year
+ if (DateTime.IsLeapYear(d.Year)) { yt = 366; } //days in year if leap year
+ Double f = d.DayOfYear / yt; //Get percentage of year that as passed
+ Double yv = d.Year + f; //add percentage of year passed to year.
+ Double k = (yv - 1999.97) * 13.2555; //find approximate k using formula 50.2
- double yt = 365; //days in year
- if (DateTime.IsLeapYear(d.Year)) { yt = 366; } //days in year if leap year
- double f = d.DayOfYear / yt; //Get percentage of year that as passed
- double yv = d.Year + f; //add percentage of year passed to year.
- double k = (yv - 1999.97) * 13.2555; //find approximate k using formula 50.2
+ //Set k decimal based on apogee or perigee
+ k = md == MoonDistanceType.Apogee ? Math.Floor(k) + .5 : Math.Floor(k);
- //Set k decimal based on apogee or perigee
- if (md == MoonDistanceType.Apogee)
- {
- k = Math.Floor(k) + .5;
- }
- else
- {
- k = Math.Floor(k);
- }
-
- //Find T using formula 50.3
- double T = k / 1325.55;
- //Find JDE using formula 50.1
- double JDE = 2451534.6698 + 27.55454989 * k -
+ //Find T using formula 50.3
+ Double T = k / 1325.55;
+ //Find JDE using formula 50.1
+ Double JDE = 2451534.6698 + 27.55454989 * k -
0.0006691 * Math.Pow(T, 2) -
0.00001098 * Math.Pow(T, 3) -
0.0000000052 * Math.Pow(T, 4);
- //Find Moon's mean elongation at time JDE.
- double D = 171.9179 + 335.9106046 * k -
+ //Find Moon's mean elongation at time JDE.
+ Double D = 171.9179 + 335.9106046 * k -
0.0100383 * Math.Pow(T, 2) -
0.00001156 * Math.Pow(T, 3) +
0.000000055 * Math.Pow(T, 4);
- //Find Sun's mean anomaly at time JDE
- double M = 347.3477 + 27.1577721 * k -
+ //Find Sun's mean anomaly at time JDE
+ Double M = 347.3477 + 27.1577721 * k -
0.0008130 * Math.Pow(T, 2) -
0.0000010 * Math.Pow(T, 3);
- //Find Moon's argument of latitude at Time JDE
- double F = 316.6109 + 364.5287911 * k -
+ //Find Moon's argument of latitude at Time JDE
+ Double F = 316.6109 + 364.5287911 * k -
0.0125053 * Math.Pow(T, 2) -
0.0000148 * Math.Pow(T, 3);
- //Normalize DMF to a 0-360 degree number
- D %= 360;
- if (D < 0) { D += 360; }
- M %= 360;
- if (M < 0) { M += 360; }
- F %= 360;
- if (F < 0) { F += 360; }
+ //Normalize DMF to a 0-360 degree number
+ D %= 360;
+ if (D < 0) { D += 360; }
+ M %= 360;
+ if (M < 0) { M += 360; }
+ F %= 360;
+ if (F < 0) { F += 360; }
- //Convert DMF to radians
- D = D * Math.PI / 180;
- M = M * Math.PI / 180;
- F = F * Math.PI / 180;
- double termsA;
- //Find Terms A from Table 50.A
- if (md == MoonDistanceType.Apogee)
- {
- termsA = MeeusTables.ApogeeTermsA(D, M, F, T);
- }
- else
- {
- termsA = MeeusTables.PerigeeTermsA(D, M, F, T);
- }
- JDE += termsA;
- double termsB;
- if (md == MoonDistanceType.Apogee)
- {
- termsB = MeeusTables.ApogeeTermsB(D, M, F, T);
- }
- else
- {
- termsB = MeeusTables.PerigeeTermsB(D, M, F, T);
- }
- //Convert julian back to date
- DateTime date = JulianConversions.GetDate_FromJulian(JDE).Value;
- //Obtain distance
- Distance dist = GetMoonDistance(date);
+ //Convert DMF to radians
+ D = D * Math.PI / 180;
+ M = M * Math.PI / 180;
+ F = F * Math.PI / 180;
+ Double termsA = md == MoonDistanceType.Apogee ? MeeusTables.ApogeeTermsA(D, M, F, T) : MeeusTables.PerigeeTermsA(D, M, F, T);
+ //Find Terms A from Table 50.A
+ JDE += termsA;
+ Double termsB = md == MoonDistanceType.Apogee ? MeeusTables.ApogeeTermsB(D, M, F, T) : MeeusTables.PerigeeTermsB(D, M, F, T);
+ //Convert julian back to date
+ DateTime date = JulianConversions.GetDate_FromJulian(JDE).Value;
+ //Obtain distance
+ Distance dist = GetMoonDistance(date);
- PerigeeApogee ap = new PerigeeApogee(date, termsB, dist);
- return ap;
+ PerigeeApogee ap = new PerigeeApogee(date, termsB, dist);
+ return ap;
+ }
+
+ public static Perigee GetPerigeeEvents(DateTime d) {
+ //Iterate in 15 day increments due to formula variations.
+ //Determine closest events to date.
+ //per1 is last date
+ //per2 is next date
+
+ //integrity for new date.
+ if (d.Year <= 0001) { return new Perigee(new PerigeeApogee(new DateTime(), 0, new Distance(0)), new PerigeeApogee(new DateTime(), 0, new Distance(0))); }
+ //Start at lowest increment
+ PerigeeApogee per1 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Perigee);
+ PerigeeApogee per2 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Perigee);
+
+ for (Int32 x = -30; x <= 45; x += 15) {
+ //used for comparison
+ PerigeeApogee t = MoonPerigeeOrApogee(d.AddDays(x), MoonDistanceType.Perigee);
+
+ //Find the next pergiee after specified date
+ if (t.Date > per2.Date && t.Date >= d) {
+ per2 = t;
+ break;
+ }
+ //Find last perigee before specified date
+ if (t.Date > per1.Date && t.Date < d) {
+ per1 = t;
+ per2 = t;
}
- public static Perigee GetPerigeeEvents(DateTime d)
- {
- //Iterate in 15 day increments due to formula variations.
- //Determine closest events to date.
- //per1 is last date
- //per2 is next date
+ }
+ return new Perigee(per1, per2);
+ }
+ public static Apogee GetApogeeEvents(DateTime d) {
+ //Iterate in 5 month increments due to formula variations.
+ //Determine closest events to date.
+ //apo1 is last date
+ //apo2 is next date
- //integrity for new date.
- if (d.Year <= 0001) { return new Perigee(new PerigeeApogee(new DateTime(), 0, new Distance(0)), new PerigeeApogee(new DateTime(), 0, new Distance(0))); }
- //Start at lowest increment
- PerigeeApogee per1 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Perigee);
- PerigeeApogee per2 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Perigee);
+ //integrity for new date.
+ if (d.Year <= 0001) { return new Apogee(new PerigeeApogee(new DateTime(), 0, new Distance(0)), new PerigeeApogee(new DateTime(), 0, new Distance(0))); }
- for (int x = -30; x <= 45; x+=15)
- {
- //used for comparison
- PerigeeApogee t = MoonPerigeeOrApogee(d.AddDays(x), MoonDistanceType.Perigee);
-
- //Find the next pergiee after specified date
- if (t.Date > per2.Date && t.Date >= d)
- {
- per2 = t;
- break;
- }
- //Find last perigee before specified date
- if (t.Date > per1.Date && t.Date < d)
- {
- per1 = t;
- per2 = t;
- }
-
- }
- return new Perigee(per1, per2);
+ PerigeeApogee apo1 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Apogee);
+ PerigeeApogee apo2 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Apogee);
+ for (Int32 x = -30; x <= 45; x += 15) {
+ PerigeeApogee t = MoonPerigeeOrApogee(d.AddDays(x), MoonDistanceType.Apogee);
+ //Find next apogee after specified date
+ if (t.Date > apo2.Date && t.Date >= d) {
+ apo2 = t;
+ break;
}
- public static Apogee GetApogeeEvents(DateTime d)
- {
- //Iterate in 5 month increments due to formula variations.
- //Determine closest events to date.
- //apo1 is last date
- //apo2 is next date
-
- //integrity for new date.
- if (d.Year <= 0001) { return new Apogee(new PerigeeApogee(new DateTime(), 0, new Distance(0)), new PerigeeApogee(new DateTime(), 0, new Distance(0))); }
-
- PerigeeApogee apo1 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Apogee);
- PerigeeApogee apo2 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Apogee);
- for (int x = -30; x <= 45; x+=15)
- {
- PerigeeApogee t = MoonPerigeeOrApogee(d.AddDays(x), MoonDistanceType.Apogee);
- //Find next apogee after specified date
- if (t.Date > apo2.Date && t.Date >= d)
- {
- apo2 = t;
- break;
- }
- //Find last apogee before specified date
- if (t.Date > apo1.Date && t.Date < d)
- {
- apo1 = t;
- apo2 = t;
- }
-
- }
- return new Apogee(apo1, apo2);
-
+ //Find last apogee before specified date
+ if (t.Date > apo1.Date && t.Date < d) {
+ apo1 = t;
+ apo2 = t;
}
- ///
- /// Gets moon distance (Ch 47).
- ///
- /// DateTime
- /// Distance
- public static Distance GetMoonDistance(DateTime d)
- {
- //Ch 47
- double JDE = JulianConversions.GetJulian(d);//Get julian
- double T = (JDE - 2451545) / 36525; //Get dynamic time.
+ }
+ return new Apogee(apo1, apo2);
- double[] values = Get_Moon_LDMNF(T);
+ }
- double D = values[1];
- double M = values[2];
- double N = values[3];
- double F = values[4];
+ ///
+ /// Gets moon distance (Ch 47).
+ ///
+ /// DateTime
+ /// Distance
+ public static Distance GetMoonDistance(DateTime d) {
+ //Ch 47
+ Double JDE = JulianConversions.GetJulian(d);//Get julian
+ Double T = (JDE - 2451545) / 36525; //Get dynamic time.
- //Ch 47 distance formula
- double dist = 385000.56 + (MeeusTables.Moon_Periodic_Er(D, M, N, F, T) / 1000);
- return new Distance(dist);
- }
+ Double[] values = Get_Moon_LDMNF(T);
- private static Distance GetMoonDistance(DateTime d, double[] values)
- {
- //Ch 47
- double JDE = JulianConversions.GetJulian(d);//Get julian
- double T = (JDE - 2451545) / 36525; //Get dynamic time.
+ Double D = values[1];
+ Double M = values[2];
+ Double N = values[3];
+ Double F = values[4];
- double D = values[1];
- double M = values[2];
- double N = values[3];
- double F = values[4];
+ //Ch 47 distance formula
+ Double dist = 385000.56 + MeeusTables.Moon_Periodic_Er(D, M, N, F, T) / 1000;
+ return new Distance(dist);
+ }
- double dist = 385000.56 + (MeeusTables.Moon_Periodic_Er(D, M, N, F, T) / 1000);
- return new Distance(dist);
- }
+ /*private static Distance GetMoonDistance(DateTime d, Double[] values) {
+ //Ch 47
+ Double JDE = JulianConversions.GetJulian(d);//Get julian
+ Double T = (JDE - 2451545) / 36525; //Get dynamic time.
- ///
- /// Gets Moon L, D, M, N, F values
- /// Ch. 47
- ///
- /// Dynamic Time
- /// double[] containing L,D,M,N,F
- static double[] Get_Moon_LDMNF(double T)
- {
- //T = dynamic time
+ Double D = values[1];
+ Double M = values[2];
+ Double N = values[3];
+ Double F = values[4];
- //Moon's mean longitude
- double L = 218.316447 + 481267.88123421 * T -
+ Double dist = 385000.56 + MeeusTables.Moon_Periodic_Er(D, M, N, F, T) / 1000;
+ return new Distance(dist);
+ }*/
+
+ ///
+ /// Gets Moon L, D, M, N, F values
+ /// Ch. 47
+ ///
+ /// Dynamic Time
+ /// double[] containing L,D,M,N,F
+ static Double[] Get_Moon_LDMNF(Double T) {
+ //T = dynamic time
+
+ //Moon's mean longitude
+ Double L = 218.316447 + 481267.88123421 * T -
.0015786 * Math.Pow(T, 2) + Math.Pow(T, 3) / 538841 -
Math.Pow(T, 4) / 65194000;
- //Moon's mean elongation
- double D = 297.8501921 + 445267.1114034 * T -
+ //Moon's mean elongation
+ Double D = 297.8501921 + 445267.1114034 * T -
0.0018819 * Math.Pow(T, 2) + Math.Pow(T, 3) / 545868 - Math.Pow(T, 4) / 113065000;
- //Sun's mean anomaly
- double M = 357.5291092 + 35999.0502909 * T -
+ //Sun's mean anomaly
+ Double M = 357.5291092 + 35999.0502909 * T -
.0001536 * Math.Pow(T, 2) + Math.Pow(T, 3) / 24490000;
- //Moon's mean anomaly
- double N = 134.9633964 + 477198.8675055 * T + .0087414 * Math.Pow(T, 2) +
+ //Moon's mean anomaly
+ Double N = 134.9633964 + 477198.8675055 * T + .0087414 * Math.Pow(T, 2) +
Math.Pow(T, 3) / 69699 - Math.Pow(T, 4) / 14712000;
- //Moon's argument of latitude
- double F = 93.2720950 + 483202.0175233 * T - .0036539 * Math.Pow(T, 2) - Math.Pow(T, 3) /
+ //Moon's argument of latitude
+ Double F = 93.2720950 + 483202.0175233 * T - .0036539 * Math.Pow(T, 2) - Math.Pow(T, 3) /
3526000 + Math.Pow(T, 4) / 863310000;
- //Normalize DMF to a 0-360 degree number
- D %= 360;
- if (D < 0) { D += 360; }
- M %= 360;
- if (M < 0) { M += 360; }
- N %= 360;
- if (N < 0) { N += 360; }
- F %= 360;
- if (F < 0) { F += 360; }
-
- //Convert DMF to radians
-
- D = D * Math.PI / 180;
- M = M * Math.PI / 180;
- N = N * Math.PI / 180;
- F = F * Math.PI / 180;
+ //Normalize DMF to a 0-360 degree number
+ D %= 360;
+ if (D < 0) { D += 360; }
+ M %= 360;
+ if (M < 0) { M += 360; }
+ N %= 360;
+ if (N < 0) { N += 360; }
+ F %= 360;
+ if (F < 0) { F += 360; }
- return new double[] { L, D, M, N, F };
- }
- ///
- /// Get moons lat/long in radians (Ch 47).
- ///
- /// L,D,M,N,F
- /// Dynamic Time
- /// Lat[0], Long[1]
- private static double[] Get_Moon_Coordinates(double[] LDMNF,double T)
- {
- //Refence Ch 47.
- double lat = LDMNF[0] + (MeeusTables.Moon_Periodic_El(LDMNF[0], LDMNF[1], LDMNF[2], LDMNF[3], LDMNF[4],T)/1000000);
- double longi = MeeusTables.Moon_Periodic_Eb(LDMNF[0], LDMNF[1], LDMNF[2], LDMNF[3], LDMNF[4], T) / 1000000;
- lat %= 360;
- if (lat < 0) { lat += 360; }
-
- //Convert to radians
- double l = rad * lat; // longitude
- double b = rad * longi; // latitude
-
- return new double[] { l, b };
- }
-
- ///
- /// Gets right Ascension of celestial object (Ch 13 Fig 13.3)
- ///
- /// latitude in radians
- /// longitude in radian
- /// Right Ascension
- private static double rightAscension(double l, double b)
- {
- //Ch 13 Fig 13.3
- //tan a = ( sin(l) * cos(e) - tan(b)-sin(e) ) / cons(l)
- //Converts to the following using Atan2 for 4 quadriatic regions
- return Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l));
- }
- ///
- /// Gets declination of celestial object (Ch 13 Fig 13.4)
- ///
- /// latitude in radians
- /// longitude in radian
- /// Declination
- private static double declination(double l, double b)
- {
- //Ch 13 Fig 13.4
- //sin o = sin(b) * cos(e) + cos(b)*sin(e) * sin(l)
- //Converts to the following using Asin
- return Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));
- }
-
- static double Parallax_Dec(double distance, double H, double pCosE, double pSinE, double dec, double cRA)
- {
- //Ch 40 (Correction for parallax
- //H - geocentric hour angle of the body (sidereal) IAW Ch 12
- double pi = Math.Asin((Math.Sin(8.794 / distance))) * Math.PI / 180; // 40.1 in radians
- H = H * Math.PI / 180;
- //Directly to topocencric dec
- double tDEC = Math.Atan2((Math.Sin(dec) - pSinE * Math.Sin(pi)) * Math.Cos(cRA), Math.Cos(dec) - pCosE * Math.Sin(pi) * Math.Cos(H));
- return tDEC;
+ //Convert DMF to radians
- }
- static double Parallax_RA(double distance, double H, double pCosE, double dec, double ra)
- {
- //ENSURE RADIANS
+ D = D * Math.PI / 180;
+ M = M * Math.PI / 180;
+ N = N * Math.PI / 180;
+ F = F * Math.PI / 180;
- //Ch 40 (Correction for parallax
- //H - geocentric hour angle of the body (sidereal) IAW Ch 12
-
- double pi = Math.Asin((Math.Sin(8.794 / distance))) * Math.PI / 180; // 40.1
-
-
- //Convert to Radian
- double t = -pCosE * Math.Sin(pi) * Math.Sin(H);
- double b = Math.Cos(dec) - pCosE * Math.Sin(pi) * Math.Cos(H);
- double cRA = Math.Atan2(t, b);
- return cRA;
- //Topocencric RA = RA - cRA
- }
- static double Get_pSinE(double dec, double H)
- {
- //ASSUME WGS 84 FOR NOW
- double a = 6378.14;
- double f = 1 / 298.257;
- double b = a * (1 - f);
- double ba = .99664719; // or 1-f
- double u = (ba * dec) * Math.PI / 180;
-
- double ps = ba * Math.Sin(u) + (H / 6378140) * Math.Sin(dec);
- return ps;
-
- }
- static double Get_pCosE(double dec, double H)
- {
- //ASSUME WGS 84 FOR NOW
- double a = 6378.14;
- double f = 1 / 298.257;
- double b = a * (1 - f);
- double ba = .99664719; // or 1-f
- double u = (ba * dec) * Math.PI / 180;
-
- double ps = Math.Cos(u) + (H / 6378140) * Math.Cos(dec);
- return ps;
- }
-
- static double azimuth(double H, double phi, double dec) { return Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(dec) * Math.Cos(phi)); }
- static double altitude(double H, double phi, double dec)
- {
- return Math.Asin(Math.Sin(phi) * Math.Sin(dec) + Math.Cos(phi) * Math.Cos(dec) * Math.Cos(H));
- }
- static double astroRefraction(double h)
- {
- //CH 16
- double P = 1013.25; //Average pressure of earth
- double T = 16; //Average temp of earth
- double alt = h / Math.PI * 180;
- double Ref = P * (.1594 + .0196 * alt + .00002 * Math.Pow(alt, 2)) / ((273 + T) * (1 + .505 * alt + .0845 * Math.Pow(alt, 2)));
- return Ref / 60;
- }
+ return new Double[] { L, D, M, N, F };
}
+ ///
+ /// Get moons lat/long in radians (Ch 47).
+ ///
+ /// L,D,M,N,F
+ /// Dynamic Time
+ /// Lat[0], Long[1]
+ private static Double[] Get_Moon_Coordinates(Double[] LDMNF, Double T) {
+ //Refence Ch 47.
+ Double lat = LDMNF[0] + MeeusTables.Moon_Periodic_El(LDMNF[0], LDMNF[1], LDMNF[2], LDMNF[3], LDMNF[4], T) / 1000000;
+ Double longi = MeeusTables.Moon_Periodic_Eb(LDMNF[0], LDMNF[1], LDMNF[2], LDMNF[3], LDMNF[4], T) / 1000000;
+ lat %= 360;
+ if (lat < 0) { lat += 360; }
+
+ //Convert to radians
+ Double l = rad * lat; // longitude
+ Double b = rad * longi; // latitude
+
+ return new Double[] { l, b };
+ }
+
+ ///
+ /// Gets right Ascension of celestial object (Ch 13 Fig 13.3)
+ ///
+ /// latitude in radians
+ /// longitude in radian
+ /// Right Ascension
+ private static Double RightAscension(Double l, Double b) =>
+ //Ch 13 Fig 13.3
+ //tan a = ( sin(l) * cos(e) - tan(b)-sin(e) ) / cons(l)
+ //Converts to the following using Atan2 for 4 quadriatic regions
+ Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l));
+ ///
+ /// Gets declination of celestial object (Ch 13 Fig 13.4)
+ ///
+ /// latitude in radians
+ /// longitude in radian
+ /// Declination
+ private static Double Declination(Double l, Double b) =>
+ //Ch 13 Fig 13.4
+ //sin o = sin(b) * cos(e) + cos(b)*sin(e) * sin(l)
+ //Converts to the following using Asin
+ Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));
+
+ static Double Parallax_Dec(Double distance, Double H, Double pCosE, Double pSinE, Double dec, Double cRA) {
+ //Ch 40 (Correction for parallax
+ //H - geocentric hour angle of the body (sidereal) IAW Ch 12
+ Double pi = Math.Asin(Math.Sin(8.794 / distance)) * Math.PI / 180; // 40.1 in radians
+ H = H * Math.PI / 180;
+ //Directly to topocencric dec
+ Double tDEC = Math.Atan2((Math.Sin(dec) - pSinE * Math.Sin(pi)) * Math.Cos(cRA), Math.Cos(dec) - pCosE * Math.Sin(pi) * Math.Cos(H));
+ return tDEC;
+
+ }
+ static Double Parallax_RA(Double distance, Double H, Double pCosE, Double dec, Double _) {
+ //ENSURE RADIANS
+
+ //Ch 40 (Correction for parallax
+ //H - geocentric hour angle of the body (sidereal) IAW Ch 12
+
+ Double pi = Math.Asin(Math.Sin(8.794 / distance)) * Math.PI / 180; // 40.1
+
+
+ //Convert to Radian
+ Double t = -pCosE * Math.Sin(pi) * Math.Sin(H);
+ Double b = Math.Cos(dec) - pCosE * Math.Sin(pi) * Math.Cos(H);
+ Double cRA = Math.Atan2(t, b);
+ return cRA;
+ //Topocencric RA = RA - cRA
+ }
+ static Double Get_pSinE(Double dec, Double H) {
+ //ASSUME WGS 84 FOR NOW
+ //Double a = 6378.14;
+ //Double f = 1 / 298.257;
+ //Double b = a * (1 - f);
+ Double ba = .99664719; // or 1-f
+ Double u = ba * dec * Math.PI / 180;
+
+ Double ps = ba * Math.Sin(u) + H / 6378140 * Math.Sin(dec);
+ return ps;
+
+ }
+ static Double Get_pCosE(Double dec, Double H) {
+ //ASSUME WGS 84 FOR NOW
+ //Double a = 6378.14;
+ //Double f = 1 / 298.257;
+ //Double b = a * (1 - f);
+ Double ba = .99664719; // or 1-f
+ Double u = ba * dec * Math.PI / 180;
+
+ Double ps = Math.Cos(u) + H / 6378140 * Math.Cos(dec);
+ return ps;
+ }
+
+ static Double Azimuth(Double H, Double phi, Double dec) => Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(dec) * Math.Cos(phi));
+ static Double Altitude(Double H, Double phi, Double dec) => Math.Asin(Math.Sin(phi) * Math.Sin(dec) + Math.Cos(phi) * Math.Cos(dec) * Math.Cos(H));
+ static Double AstroRefraction(Double h) {
+ //CH 16
+ Double P = 1013.25; //Average pressure of earth
+ Double T = 16; //Average temp of earth
+ Double alt = h / Math.PI * 180;
+ Double Ref = P * (.1594 + .0196 * alt + .00002 * Math.Pow(alt, 2)) / ((273 + T) * (1 + .505 * alt + .0845 * Math.Pow(alt, 2)));
+ return Ref / 60;
+ }
+ }
}
diff --git a/CoordinateSharp/Celestial.SolarEclipseCalc.cs b/CoordinateSharp/Celestial.SolarEclipseCalc.cs
index b4b7c3b..43f7da9 100644
--- a/CoordinateSharp/Celestial.SolarEclipseCalc.cs
+++ b/CoordinateSharp/Celestial.SolarEclipseCalc.cs
@@ -1,971 +1,735 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-namespace CoordinateSharp
-{
- //CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
- //Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used
- //to signify eclipses that had already started during rise and set times on the NASA calculator
+namespace CoordinateSharp {
+ //CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
+ //Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used
+ //to signify eclipses that had already started during rise and set times on the NASA calculator
- //SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC".
+ //SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC".
- //ELLIPSOID ADJUSTMENT
- //6378140.0 Ellipsoid is used in the NASA Calculator
- //WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions.
- //This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
+ //ELLIPSOID ADJUSTMENT
+ //6378140.0 Ellipsoid is used in the NASA Calculator
+ //WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions.
+ //This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
- //CURRENT RANGE 1601-2600.
- internal class SolarEclipseCalc
- {
- public static List> CalculateSolarEclipse(DateTime d, double latRad, double longRad)
- {
- return Calculate(d, latRad, longRad, null);
- }
- public static List CalculateSolarEclipse(DateTime d, double latRad, double longRad, double[] events)
- {
- List> evs = Calculate(d, latRad, longRad, events);
- List deetsList = new List();
- foreach(List ls in evs)
- {
- SolarEclipseDetails deets = new SolarEclipseDetails(ls);
- deetsList.Add(deets);
- }
- return deetsList;
- }
- public static List> CalculateSolarEclipse(DateTime d, Coordinate coord)
- {
- return Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians(), null);
- }
-
- private static List> Calculate(DateTime d, double latRad, double longRad, double[] ev)
- {
- //Declare storage arrays
- double[] obsvconst = new double[7];
- double[] mid = new double[41];//Check index to see if array needs to be this size
- double[] c1 = new double[41];
- double[] c2 = new double[41];
- double[] c3 = new double[41];
- double[] c4 = new double[41];
-
- List> events = new List>();
- double[] el;
- if (ev == null)
- {
- el = Eclipse.SolarData.SolarDateData(d);//Get 100 year solar data;
- }
- else
- {
- el = ev;
- }
-
- events = new List>();
- ReadData(latRad, longRad, obsvconst);
- for (int i = 0; i < el.Length; i += 28)
- {
- obsvconst[6] = i;
- GetAll(el, obsvconst, mid,c1,c2,c3,c4);
- // Is there an event...
- if (mid[39] > 0)
- {
- List values = new List();
- values.Add(GetDate(el, mid, obsvconst));
- if (mid[39] == 1)
- {
- values.Add("P");
- }
- else if (mid[39] == 2)
- {
- values.Add("A");
- }
- else
- {
- values.Add("T");
- }
-
- // Partial eclipse start
- if (c1[40] == 4)
- {
- values.Add("-");
- values.Add(" ");
- }
- else
- {
- // Partial eclipse start time
- values.Add(GetTime(el, c1, obsvconst));
- values.Add(GetAlt(c1));
- }
- // Central eclipse time
- if ((mid[39] > 1) && (c2[40] != 4))
- {
- values.Add(GetTime(el, c2, obsvconst));
- }
- else
- {
- values.Add("-");
- }
-
- //Mid Time
- values.Add(GetTime(el, mid, obsvconst));
-
- // Maximum eclipse alt
- values.Add(GetAlt(mid));
-
- // Maximum eclipse azi
- values.Add(GetAzi(mid));
- // Central eclipse ends
- if ((mid[39] > 1) && (c3[40] != 4))
- {
- values.Add(GetTime(el, c3, obsvconst));
- }
- else
- {
- values.Add("-");
- }
- // Partial eclipse ends
- if (c4[40] == 4)
- {
- values.Add("-");
- values.Add(" ");
- }
- else
- {
- // Partial eclipse ends
- values.Add(GetTime(el, c4, obsvconst));
-
- // ... sun alt
- values.Add(GetAlt(c4));
- }
- // Eclipse magnitude
- values.Add(GetMagnitude(mid));
-
-
- // Coverage
- values.Add(GetCoverage(mid));
-
- // Central duration
- if (mid[39] > 1)
- {
- values.Add(GetDuration(mid,c2,c3));
- }
- else
- {
- values.Add("-");
- }
-
- events.Add(values);
- }
- }
- return events;
- }
- //Populates the obsvcont array
- private static void ReadData(double latRad, double longRad, double[] obsvconst)
- {
- // Get the latitude
- obsvconst[0] = latRad;
-
- //// Get the longitude
- obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN.
-
- // Get the altitude
- obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS.
-
- // Get the time zone
- obsvconst[3] = 0; //ALWAYS GMT
-
- // Get the observer's geocentric position
- double tmp = Math.Atan(0.99664719 * Math.Tan(obsvconst[0]));
- obsvconst[4] = 0.99664719 * Math.Sin(tmp) + (obsvconst[2] / 6378140.0) * Math.Sin(obsvconst[0]);
- obsvconst[5] = Math.Cos(tmp) + (obsvconst[2] / 6378140.0 * Math.Cos(obsvconst[0]));
-
- }
- // Populate the c1, c2, mid, c3 and c4 arrays
- private static void GetAll(double[] elements, double[] obsvconst, double[] mid, double[] c1, double[] c2,double[] c3, double[] c4)
- {
- GetMid(elements, obsvconst, mid);
- MidObservational(obsvconst, mid);
- if (mid[37] > 0.0)
- {
- Getc1c4(elements, obsvconst, mid,c1,c2,c3,c4);
- if ((mid[36] < mid[29]) || (mid[36] < -mid[29]))
- {
- Getc2c3(elements, obsvconst, mid,c2,c3);
- if (mid[29] < 0.0)
- {
- mid[39] = 3; // Total eclipse
- }
- else
- {
- mid[39] = 2; // Annular eclipse
- }
- Observational(c1, obsvconst, mid);
- Observational(c2, obsvconst, mid);
- Observational(c3, obsvconst, mid);
- Observational(c4, obsvconst, mid);
- c2[36] = 999.9;
- c3[36] = 999.9;
- // Calculate how much of the eclipse is above the horizon
- double pattern = 0;
- if (c1[40] == 0) { pattern += 10000; }
- if (c2[40] == 0) { pattern += 1000; }
- if (mid[40] == 0) { pattern += 100; }
- if (c3[40] == 0) { pattern += 10; }
- if (c4[40] == 0) { pattern += 1; }
- // Now, time to make sure that all my Observational[39] and Observational[40] are OK
- if (pattern == 11110)
- {
- GetSunset(elements, c4, obsvconst);
- Observational(c4, obsvconst, mid);
- c4[40] = 3;
- }
- else if (pattern == 11100)
- {
- GetSunset(elements, c3, obsvconst);
- Observational(c3, obsvconst, mid);
- c3[40] = 3;
- CopyCircumstances(c3, c4);
- }
- else if (pattern == 11000)
- {
- c3[40] = 4;
- GetSunset(elements, mid, obsvconst);
- MidObservational(obsvconst, mid);
- mid[40] = 3;
- CopyCircumstances(mid, c4);
- }
- else if (pattern == 10000)
- {
- mid[39] = 1;
- GetSunset(elements, mid, obsvconst);
- MidObservational(obsvconst, mid);
- mid[40] = 3;
- CopyCircumstances(mid, c4);
- }
- else if (pattern == 1111)
- {
- GetSunrise(elements, c1, obsvconst);
- Observational(c1, obsvconst, mid);
- c1[40] = 2;
- }
- else if (pattern == 111)
- {
- GetSunrise(elements, c2, obsvconst);
- Observational(c2, obsvconst, mid);
- c2[40] = 2;
- CopyCircumstances(c2, c1);
- }
- else if (pattern == 11)
- {
- c2[40] = 4;
- GetSunrise(elements, mid, obsvconst);
- MidObservational(obsvconst, mid);
- mid[40] = 2;
- CopyCircumstances(mid, c1);
- }
- else if (pattern == 1)
- {
- mid[39] = 1;
- GetSunrise(elements, mid, obsvconst);
- MidObservational(obsvconst, mid);
- mid[40] = 2;
- CopyCircumstances(mid, c1);
- }
- else if (pattern == 0)
- {
- mid[39] = 0;
- }
- // There are other patterns, but those are the only ones we're covering!
- }
- else
- {
- mid[39] = 1; // Partial eclipse
- double pattern = 0;
- Observational(c1, obsvconst, mid);
- Observational(c4, obsvconst, mid);
- if (c1[40] == 0) { pattern += 100; }
- if (mid[40] == 0) { pattern += 10; }
- if (c4[40] == 0) { pattern += 1; }
- if (pattern == 110)
- {
- GetSunset(elements, c4, obsvconst);
- Observational(c4, obsvconst, mid);
- c4[40] = 3;
- }
- else if (pattern == 100)
- {
- GetSunset(elements, mid, obsvconst);
- MidObservational(obsvconst, mid);
- mid[40] = 3;
- CopyCircumstances(mid, c4);
- }
- else if (pattern == 11)
- {
- GetSunrise(elements, c1, obsvconst);
- Observational(c1, obsvconst, mid);
- c1[40] = 2;
- }
- else if (pattern == 1)
- {
- GetSunrise(elements, mid, obsvconst);
- MidObservational(obsvconst, mid);
- mid[40] = 2;
- CopyCircumstances(mid, c1);
- }
- else if (pattern == 0)
- {
- mid[39] = 0;
- }
- // There are other patterns, but those are the only ones we're covering!
- }
- }
- else
- {
- mid[39] = 0; // No eclipse
- }
- // Magnitude for total and annular eclipse is moon/sun ratio
- if ((mid[39] == 2) || (mid[39] == 3))
- {
- mid[37] = mid[38];
- }
- }
- // Calculate mid eclipse
- private static void GetMid(double[] elements, double[] obsvconst, double[] mid)
- {
- double iter, tmp;
-
- mid[0] = 0;
- mid[1] = 0.0;
- iter = 0;
- tmp = 1.0;
- TimeLocDependent(elements, mid, obsvconst);
- while (((tmp > 0.000001) || (tmp < -0.000001)) && (iter < 50))
- {
- tmp = (mid[24] * mid[26] + mid[25] * mid[27]) / mid[30];
- mid[1] = mid[1] - tmp;
- iter++;
- TimeLocDependent(elements, mid, obsvconst);
- }
- }
- // Populate the circumstances array with the time and location dependent circumstances
- private static double[] TimeLocDependent(double[] elements, double[] circumstances, double[] obsvconst)
- {
- double index, type;
-
- TimeDependent(elements, circumstances, obsvconst);
- index = obsvconst[6];
- // Calculate h, sin h, cos h
- circumstances[16] = circumstances[7] - obsvconst[1] - (elements[(int)index + 5] / 13713.44);
- circumstances[17] = Math.Sin(circumstances[16]);
- circumstances[18] = Math.Cos(circumstances[16]);
- // Calculate xi
- circumstances[19] = obsvconst[5] * circumstances[17];
- // Calculate eta
- circumstances[20] = obsvconst[4] * circumstances[6] - obsvconst[5] * circumstances[18] * circumstances[5];
- // Calculate zeta
- circumstances[21] = obsvconst[4] * circumstances[5] + obsvconst[5] * circumstances[18] * circumstances[6];
- // Calculate dxi
- circumstances[22] = circumstances[13] * obsvconst[5] * circumstances[18];
- // Calculate deta
- circumstances[23] = circumstances[13] * circumstances[19] * circumstances[5] - circumstances[21] * circumstances[12];
- // Calculate u
- circumstances[24] = circumstances[2] - circumstances[19];
- // Calculate v
- circumstances[25] = circumstances[3] - circumstances[20];
- // Calculate a
- circumstances[26] = circumstances[10] - circumstances[22];
- // Calculate b
- circumstances[27] = circumstances[11] - circumstances[23];
- // Calculate l1'
- type = circumstances[0];
- if ((type == -2) || (type == 0) || (type == 2))
- {
- circumstances[28] = circumstances[8] - circumstances[21] * elements[26 + (int)index];
- }
- // Calculate l2'
- if ((type == -1) || (type == 0) || (type == 1))
- {
- circumstances[29] = circumstances[9] - circumstances[21] * elements[27 + (int)index];
- }
- // Calculate n^2
- circumstances[30] = circumstances[26] * circumstances[26] + circumstances[27] * circumstances[27];
- return circumstances;
- }
- // Populate the circumstances array with the time-only dependent circumstances (x, y, d, m, ...)
- private static double[] TimeDependent(double[] elements, double[] circumstances, double[] obsvconst)
- {
- double type, t, ans;
-
- t = circumstances[1];
- int index = (int)obsvconst[6];
- // Calculate x
- ans = elements[9 + index] * t + elements[8 + index];
- ans = ans * t + elements[7 + index];
- ans = ans * t + elements[6 + index];
- circumstances[2] = ans;
- // Calculate dx
- ans = 3.0 * elements[9 + index] * t + 2.0 * elements[8 + index];
- ans = ans * t + elements[7 + index];
- circumstances[10] = ans;
- // Calculate y
- ans = elements[13 + index] * t + elements[12 + index];
- ans = ans * t + elements[11 + index];
- ans = ans * t + elements[10 + index];
- circumstances[3] = ans;
- // Calculate dy
- ans = 3.0 * elements[13 + index] * t + 2.0 * elements[12 + index];
- ans = ans * t + elements[11 + index];
- circumstances[11] = ans;
- // Calculate d
- ans = elements[16 + index] * t + elements[15 + index];
- ans = ans * t + elements[14 + index];
- ans = ans * Math.PI / 180.0;
- circumstances[4] = ans;
- // sin d and cos d
- circumstances[5] = Math.Sin(ans);
- circumstances[6] = Math.Cos(ans);
- // Calculate dd
- ans = 2.0 * elements[16 + index] * t + elements[15 + index];
- ans = ans * Math.PI / 180.0;
- circumstances[12] = ans;
- // Calculate m
- ans = elements[19 + index] * t + elements[18 + index];
- ans = ans * t + elements[17 + index];
- if (ans >= 360.0)
- {
- ans = ans - 360.0;
- }
- ans = ans * Math.PI / 180.0;
- circumstances[7] = ans;
- // Calculate dm
- ans = 2.0 * elements[19 + index] * t + elements[18 + index];
- ans = ans * Math.PI / 180.0;
- circumstances[13] = ans;
- // Calculate l1 and dl1
- type = circumstances[0];
- if ((type == -2) || (type == 0) || (type == 2))
- {
- ans = elements[22 + index] * t + elements[21 + index];
- ans = ans * t + elements[20 + index];
- circumstances[8] = ans;
- circumstances[14] = 2.0 * elements[22 + index] * t + elements[21 + index];
- }
- // Calculate l2 and dl2
- if ((type == -1) || (type == 0) || (type == 1))
- {
- ans = elements[25 + index] * t + elements[24 + index];
- ans = ans * t + elements[23 + index];
- circumstances[9] = ans;
- circumstances[15] = 2.0 * elements[25 + index] * t + elements[24 + index];
- }
- return circumstances;
- }
- // Get the observational circumstances for mid eclipse
- private static void MidObservational(double[] obsvconst, double[] mid)
- {
- Observational(mid, obsvconst, mid);
- // Calculate m, magnitude and moon/sun
- mid[36] = Math.Sqrt(mid[24] * mid[24] + mid[25] * mid[25]);
- mid[37] = (mid[28] - mid[36]) / (mid[28] + mid[29]);
- mid[38] = (mid[28] - mid[29]) / (mid[28] + mid[29]);
- }
- // Get the observational circumstances
- private static void Observational(double[] circumstances, double[] obsvconst, double[] mid)
- {
- double contacttype, coslat, sinlat;
-
- // We are looking at an "external" contact UNLESS this is a total eclipse AND we are looking at
- // c2 or c3, in which case it is an INTERNAL contact! Note that if we are looking at mid eclipse,
- // then we may not have determined the type of eclipse (mid[39]) just yet!
- if (circumstances[0] == 0)
- {
- contacttype = 1.0;
- }
- else
- {
- if ((mid[39] == 3) && ((circumstances[0] == -1) || (circumstances[0] == 1)))
- {
- contacttype = -1.0;
- }
- else
- {
- contacttype = 1.0;
- }
- }
- // Calculate p
- circumstances[31] = Math.Atan2(contacttype * circumstances[24], contacttype * circumstances[25]);
- // Calculate alt
- sinlat = Math.Sin(obsvconst[0]);
- coslat = Math.Cos(obsvconst[0]);
- circumstances[32] = Math.Asin(circumstances[5] * sinlat + circumstances[6] * coslat * circumstances[18]);
- // Calculate q
- circumstances[33] = Math.Asin(coslat * circumstances[17] / Math.Cos(circumstances[32]));
- if (circumstances[20] < 0.0)
- {
- circumstances[33] = Math.PI - circumstances[33];
- }
- // Calculate v
- circumstances[34] = circumstances[31] - circumstances[33];
- // Calculate azi
- circumstances[35] = Math.Atan2(-1.0 * circumstances[17] * circumstances[6], circumstances[5] * coslat - circumstances[18] * sinlat * circumstances[6]);
- // Calculate visibility
- if (circumstances[32] > -0.00524)
- {
- circumstances[40] = 0;
- }
- else
- {
- circumstances[40] = 1;
- }
- }
- // Get C1 and C4 data
- // Entry conditions -
- // 1. The mid array must be populated
- // 2. The magnitude at mid eclipse must be > 0.0
- private static void Getc1c4(double[] elements, double[] obsvconst, double[] mid, double[] c1, double[] c2, double[] c3, double[] c4)
- {
- double tmp, n;
-
- n = Math.Sqrt(mid[30]);
- tmp = mid[26] * mid[25] - mid[24] * mid[27];
- tmp = tmp / n / mid[28];
- tmp = Math.Sqrt(1.0 - tmp * tmp) * mid[28] / n;
- c1[0] = -2;
- c4[0] = 2;
- c1[1] = mid[1] - tmp;
- c4[1] = mid[1] + tmp;
- c1c4iterate(elements, c1, obsvconst);
- c1c4iterate(elements, c4, obsvconst);
- }
- // Iterate on C1 or C4
- private static double[] c1c4iterate(double[] elements, double[] circumstances, double[] obsvconst)
- {
- double sign, iter, tmp, n;
-
- TimeLocDependent(elements, circumstances, obsvconst);
- if (circumstances[0] < 0)
- {
- sign = -1.0;
- }
- else
- {
- sign = 1.0;
- }
- tmp = 1.0;
- iter = 0;
- while (((tmp > 0.000001) || (tmp < -0.000001)) && (iter < 50))
- {
- n = Math.Sqrt(circumstances[30]);
- tmp = circumstances[26] * circumstances[25] - circumstances[24] * circumstances[27];
- tmp = tmp / n / circumstances[28];
- tmp = sign * Math.Sqrt(1.0 - tmp * tmp) * circumstances[28] / n;
- tmp = (circumstances[24] * circumstances[26] + circumstances[25] * circumstances[27]) / circumstances[30] - tmp;
- circumstances[1] = circumstances[1] - tmp;
- TimeLocDependent(elements, circumstances, obsvconst);
- iter++;
- }
- return circumstances;
- }
- // Get C2 and C3 data
- // Entry conditions -
- // 1. The mid array must be populated
- // 2. There must be either a total or annular eclipse at the location!
- private static void Getc2c3(double[] elements, double[] obsvconst, double[] mid, double[] c2, double[] c3)
- {
- double tmp, n;
-
- n = Math.Sqrt(mid[30]);
- tmp = mid[26] * mid[25] - mid[24] * mid[27];
- tmp = tmp / n / mid[29];
- tmp = Math.Sqrt(1.0 - tmp * tmp) * mid[29] / n;
- c2[0] = -1;
- c3[0] = 1;
- if (mid[29] < 0.0)
- {
- c2[1] = mid[1] + tmp;
- c3[1] = mid[1] - tmp;
- }
- else
- {
- c2[1] = mid[1] - tmp;
- c3[1] = mid[1] + tmp;
- }
- c2c3iterate(elements, c2, obsvconst, mid);
- c2c3iterate(elements, c3, obsvconst, mid);
- }
- // Iterate on C2 or C3
- private static double[] c2c3iterate(double[] elements, double[] circumstances, double[] obsvconst, double[] mid)
- {
- double sign, iter, tmp, n;
-
- TimeLocDependent(elements, circumstances, obsvconst);
- if (circumstances[0] < 0)
- {
- sign = -1.0;
- }
- else
- {
- sign = 1.0;
- }
- if (mid[29] < 0.0)
- {
- sign = -sign;
- }
- tmp = 1.0;
- iter = 0;
- while (((tmp > 0.000001) || (tmp < -0.000001)) && (iter < 50))
- {
- n = Math.Sqrt(circumstances[30]);
- tmp = circumstances[26] * circumstances[25] - circumstances[24] * circumstances[27];
- tmp = tmp / n / circumstances[29];
- tmp = sign * Math.Sqrt(1.0 - tmp * tmp) * circumstances[29] / n;
- tmp = (circumstances[24] * circumstances[26] + circumstances[25] * circumstances[27]) / circumstances[30] - tmp;
- circumstances[1] = circumstances[1] - tmp;
- TimeLocDependent(elements, circumstances, obsvconst);
- iter++;
- }
- return circumstances;
- }
- // Get the date of an event
- private static string GetDate(double[] elements, double[] circumstances, double[] obsvconst)
- {
- string[] month = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
- double t, jd, a, b, c, d, e, index;
- string ans = "";
- index = obsvconst[6];
- // Calculate the JD for noon (TDT) the day before the day that contains T0
- jd = Math.Floor(elements[(int)index] - (elements[1 + (int)index] / 24.0));
- // Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0).
- t = circumstances[1] + elements[1 + (int)index] - obsvconst[3] - (elements[4 + (int)index] - 0.5) / 3600.0;
- if (t < 0.0)
- {
- jd--;
- }
- if (t >= 24.0)
- {
- jd++;
- }
- if (jd >= 2299160.0)
- {
- a = Math.Floor((jd - 1867216.25) / 36524.25);
- a = jd + 1 + a - Math.Floor(a / 4.0);
- }
- else
- {
- a = jd;
- }
- b = a + 1525.0;
- c = Math.Floor((b - 122.1) / 365.25);
- d = Math.Floor(365.25 * c);
- e = Math.Floor((b - d) / 30.6001);
- d = b - d - Math.Floor(30.6001 * e);
- if (e < 13.5)
- {
- e = e - 1;
- }
- else
- {
- e = e - 13;
- }
- double year;
- if (e > 2.5)
- {
- ans = c - 4716 + "-";
- year = c - 4716;
- }
- else
- {
- ans = c - 4715 + "-";
- year = c - 4715;
- }
- string m = month[(int)e - 1];
- ans += m + "-";
- if (d < 10)
- {
- ans = ans + "0";
- }
-
- ans = ans + d;
- //Leap Year Integrity Check
-
- if(m =="Feb" && d ==29 && !DateTime.IsLeapYear((int)year))
- {
- ans = year.ToString() + "-Mar-01";
- }
- return ans;
- }
- // Calculate the time of sunset
- private static void GetSunset(double[] elements, double[] circumstances, double[] obsvconst)
- {
- GetSunriset(elements, circumstances, 1.0, obsvconst);
- }
- // Calculate the time of sunrise
- private static void GetSunrise(double[] elements, double[] circumstances, double[] obsvconst)
- {
- GetSunriset(elements, circumstances, -1.0, obsvconst);
- }
- // Calculate the time of sunrise or sunset
- private static void GetSunriset(double[] elements, double[] circumstances, double riset, double[] obsvconst)
- {
- double h0, diff, iter;
-
- diff = 1.0;
- iter = 0;
- while ((diff > 0.00001) || (diff < -0.00001))
- {
- iter++;
- if (iter == 4) { return; }
- h0 = Math.Acos((Math.Sin(-0.00524) - Math.Sin(obsvconst[0]) * circumstances[5]) / Math.Cos(obsvconst[0]) / circumstances[6]);
- diff = (riset * h0 - circumstances[16]) / circumstances[13];
- while (diff >= 12.0) { diff -= 24.0; }
- while (diff <= -12.0) { diff += 24.0; }
- circumstances[1] += diff;
- TimeLocDependent(elements, circumstances, obsvconst);
- }
- }
- // Copy a set of circumstances
- private static void CopyCircumstances(double[] circumstancesfrom, double[] circumstancesto)
- {
- for (int i = 1; i < 41; i++)
- {
- circumstancesto[i] = circumstancesfrom[i];
- }
- }
- // Get the local time of an event
- private static string GetTime(double[] elements, double[] circumstances, double[] obsvconst)
- {
- string ans = "";
- int index = (int)obsvconst[6];
- double t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[4 + index] - 0.5) / 3600.0;
- if (t < 0.0)
- {
- t = t + 24.0;
- }
- if (t >= 24.0)
- {
- t = t - 24.0;
- }
- if (t < 10.0)
- {
- ans = ans + "0";
- }
- ans = ans + Math.Floor(t) + ":";
- t = (t * 60.0) - 60.0 * Math.Floor(t);
- if (t < 10.0)
- {
- ans = ans + "0";
- }
- ans = ans + Math.Floor(t);
- if (circumstances[40] <= 1)
- { // not sunrise or sunset
- ans = ans + ":";
- t = (t * 60.0) - 60.0 * Math.Floor(t);
- if (t < 10.0)
- {
- ans = ans + "0";
- }
- ans = ans + Math.Floor(t);
- }
- if (circumstances[40] == 1)
- {
- //WAS ITALIC
- return ans;
- }
- else if (circumstances[40] == 2)
- {
- //Rise (CHANGED FROM NASA CALC THE INDICATES (r) WITH STRING, INVESTIGATE REMOVAL)
- return ans;
- }
- else if (circumstances[40] == 3)
- {
- //Set (CHANGED FROM NASA CALC THE INDICATES (s) WITH STRING, INVESTIGATE REMOVAL)
- return ans;
- }
- else
- {
- return ans;
- }
- }
- // Get the altitude
- private static string GetAlt(double[] circumstances)
- {
- double t;
- string ans = "";
-
- if (circumstances[40] == 2)
- {
- return "0(r)";
- }
- if (circumstances[40] == 3)
- {
- return "0(s)";
- }
- if ((circumstances[32] < 0.0) && (circumstances[32] >= -0.00524))
- {
- // Crude correction for refraction (and for consistency's sake)
- t = 0.0;
- }
- else
- {
- t = circumstances[32] * 180.0 / Math.PI;
- }
- if (t < 0.0)
- {
- ans = "-";
- t = -t;
- }
- else
- {
- ans = "";
- }
- t = Math.Floor(t + 0.5);
- if (t < 10.0)
- {
- ans = ans + "0";
- }
- ans = ans + t;
- if (circumstances[40] == 1)
- {
- //WAS ITALIC
- return ans;
- }
- else
- {
- return ans;
- }
- }
- // Get the azimuth
- private static string GetAzi(double[] circumstances)
- {
- string ans = "";
- double t = circumstances[35] * 180.0 / Math.PI;
- if (t < 0.0)
- {
- t = t + 360.0;
- }
- if (t >= 360.0)
- {
- t = t - 360.0;
- }
- t = Math.Floor(t + 0.5);
- if (t < 100.0)
- {
- ans = ans + "0";
- }
- if (t < 10.0)
- {
- ans = ans + "0";
- }
- ans = ans + t;
- if (circumstances[40] == 1)
- {
- //WAS ITALIC
- return ans;
- }
- else
- {
- return ans;
- }
- }
- // Get the magnitude
- private static string GetMagnitude(double[] mid)
- {
- double a = Math.Floor(1000.0 * mid[37] + 0.5) / 1000.0;
- string ans = a.ToString();
- if (mid[40] == 1)
- {
- return ans;
- }
- if (mid[40] == 2)
- {
- ans = a.ToString() + "(r)";
- }
- if (mid[40] == 3)
- {
- ans = a.ToString() + "(s)";
- }
- return ans;
- }
- // Get the coverage
- private static string GetCoverage(double[] mid)
- {
- double a=0, b, c;
- string ans = "";
- if (mid[37] <= 0.0)
- {
- ans = "0.0";
- }
- else if (mid[37] >= 1.0)
- {
- ans = "1.000";
- }
- else
- {
- if (mid[39] == 2)
- {
- c = mid[38] * mid[38];
- }
- else
- {
- c = Math.Acos((mid[28] * mid[28] + mid[29] * mid[29] - 2.0 * mid[36] * mid[36]) / (mid[28] * mid[28] - mid[29] * mid[29]));
- b = Math.Acos((mid[28] * mid[29] + mid[36] * mid[36]) / mid[36] / (mid[28] + mid[29]));
- a = Math.PI - b - c;
- c = ((mid[38] * mid[38] * a + b) - mid[38] * Math.Sin(c)) / Math.PI;
- }
- a = Math.Floor(1000.0 * c + 0.5) / 1000.0;
- ans = a.ToString();
- }
- if (mid[40] == 1)
- {
- //WAS ITALIC
- return ans;
- }
- if (mid[40] == 2)
- {
- ans = a.ToString() + "(r)";
- }
- if (mid[40] == 3)
- {
- ans = a + "(s)";
- }
- return ans;
- }
- // Get the duration in mm:ss.s format
- // Adapted from code written by Stephen McCann - 27/04/2001
- private static string GetDuration(double[] mid, double[] c2, double[] c3)
- {
- double tmp;
- string ans;
-
- if (c3[40] == 4)
- {
- tmp = mid[1] - c2[1];
- }
- else if (c2[40] == 4)
- {
- tmp = c3[1] - mid[1];
- }
- else
- {
- tmp = c3[1] - c2[1];
- }
- if (tmp < 0.0)
- {
- tmp = tmp + 24.0;
- }
- else if (tmp >= 24.0)
- {
- tmp = tmp - 24.0;
- }
- tmp = (tmp * 60.0) - 60.0 * Math.Floor(tmp) + 0.05 / 60.0;
- ans = Math.Floor(tmp) + "m";
- tmp = (tmp * 60.0) - 60.0 * Math.Floor(tmp);
- if (tmp < 10.0)
- {
- ans = ans + "0";
- }
- ans += Math.Floor(tmp) + "s";
- return ans;
- }
+ //CURRENT RANGE 1601-2600.
+ internal class SolarEclipseCalc {
+ public static List> CalculateSolarEclipse(DateTime d, Double latRad, Double longRad) => Calculate(d, latRad, longRad, null);
+ public static List CalculateSolarEclipse(DateTime d, Double latRad, Double longRad, Double[] events) {
+ List> evs = Calculate(d, latRad, longRad, events);
+ List deetsList = new List();
+ foreach (List ls in evs) {
+ SolarEclipseDetails deets = new SolarEclipseDetails(ls);
+ deetsList.Add(deets);
+ }
+ return deetsList;
}
+ public static List> CalculateSolarEclipse(DateTime d, Coordinate coord) => Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians(), null);
+
+ private static List> Calculate(DateTime d, Double latRad, Double longRad, Double[] ev) {
+ //Declare storage arrays
+ Double[] obsvconst = new Double[7];
+ Double[] mid = new Double[41];//Check index to see if array needs to be this size
+ Double[] c1 = new Double[41];
+ Double[] c2 = new Double[41];
+ Double[] c3 = new Double[41];
+ Double[] c4 = new Double[41];
+ Double[] el = ev ?? Eclipse.SolarData.SolarDateData(d);
+ List> events = new List>();
+ ReadData(latRad, longRad, obsvconst);
+ for (Int32 i = 0; i < el.Length; i += 28) {
+ obsvconst[6] = i;
+ GetAll(el, obsvconst, mid, c1, c2, c3, c4);
+ // Is there an event...
+ if (mid[39] > 0) {
+ List values = new List {
+ GetDate(el, mid, obsvconst)
+ };
+ if (mid[39] == 1) {
+ values.Add("P");
+ } else if (mid[39] == 2) {
+ values.Add("A");
+ } else {
+ values.Add("T");
+ }
+
+ // Partial eclipse start
+ if (c1[40] == 4) {
+ values.Add("-");
+ values.Add(" ");
+ } else {
+ // Partial eclipse start time
+ values.Add(GetTime(el, c1, obsvconst));
+ values.Add(GetAlt(c1));
+ }
+ // Central eclipse time
+ if (mid[39] > 1 && c2[40] != 4) {
+ values.Add(GetTime(el, c2, obsvconst));
+ } else {
+ values.Add("-");
+ }
+
+ //Mid Time
+ values.Add(GetTime(el, mid, obsvconst));
+
+ // Maximum eclipse alt
+ values.Add(GetAlt(mid));
+
+ // Maximum eclipse azi
+ values.Add(GetAzi(mid));
+ // Central eclipse ends
+ if (mid[39] > 1 && c3[40] != 4) {
+ values.Add(GetTime(el, c3, obsvconst));
+ } else {
+ values.Add("-");
+ }
+ // Partial eclipse ends
+ if (c4[40] == 4) {
+ values.Add("-");
+ values.Add(" ");
+ } else {
+ // Partial eclipse ends
+ values.Add(GetTime(el, c4, obsvconst));
+
+ // ... sun alt
+ values.Add(GetAlt(c4));
+ }
+ // Eclipse magnitude
+ values.Add(GetMagnitude(mid));
+
+
+ // Coverage
+ values.Add(GetCoverage(mid));
+
+ // Central duration
+ if (mid[39] > 1) {
+ values.Add(GetDuration(mid, c2, c3));
+ } else {
+ values.Add("-");
+ }
+
+ events.Add(values);
+ }
+ }
+ return events;
+ }
+ //Populates the obsvcont array
+ private static void ReadData(Double latRad, Double longRad, Double[] obsvconst) {
+ // Get the latitude
+ obsvconst[0] = latRad;
+
+ //// Get the longitude
+ obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN.
+
+ // Get the altitude
+ obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS.
+
+ // Get the time zone
+ obsvconst[3] = 0; //ALWAYS GMT
+
+ // Get the observer's geocentric position
+ Double tmp = Math.Atan(0.99664719 * Math.Tan(obsvconst[0]));
+ obsvconst[4] = 0.99664719 * Math.Sin(tmp) + obsvconst[2] / 6378140.0 * Math.Sin(obsvconst[0]);
+ obsvconst[5] = Math.Cos(tmp) + obsvconst[2] / 6378140.0 * Math.Cos(obsvconst[0]);
+
+ }
+ // Populate the c1, c2, mid, c3 and c4 arrays
+ private static void GetAll(Double[] elements, Double[] obsvconst, Double[] mid, Double[] c1, Double[] c2, Double[] c3, Double[] c4) {
+ GetMid(elements, obsvconst, mid);
+ MidObservational(obsvconst, mid);
+ if (mid[37] > 0.0) {
+ Getc1c4(elements, obsvconst, mid, c1, c2, c3, c4);
+ if (mid[36] < mid[29] || mid[36] < -mid[29]) {
+ Getc2c3(elements, obsvconst, mid, c2, c3);
+ mid[39] = mid[29] < 0.0 ? 3 : 2;
+ Observational(c1, obsvconst, mid);
+ Observational(c2, obsvconst, mid);
+ Observational(c3, obsvconst, mid);
+ Observational(c4, obsvconst, mid);
+ c2[36] = 999.9;
+ c3[36] = 999.9;
+ // Calculate how much of the eclipse is above the horizon
+ Double pattern = 0;
+ if (c1[40] == 0) { pattern += 10000; }
+ if (c2[40] == 0) { pattern += 1000; }
+ if (mid[40] == 0) { pattern += 100; }
+ if (c3[40] == 0) { pattern += 10; }
+ if (c4[40] == 0) { pattern += 1; }
+ // Now, time to make sure that all my Observational[39] and Observational[40] are OK
+ if (pattern == 11110) {
+ GetSunset(elements, c4, obsvconst);
+ Observational(c4, obsvconst, mid);
+ c4[40] = 3;
+ } else if (pattern == 11100) {
+ GetSunset(elements, c3, obsvconst);
+ Observational(c3, obsvconst, mid);
+ c3[40] = 3;
+ CopyCircumstances(c3, c4);
+ } else if (pattern == 11000) {
+ c3[40] = 4;
+ GetSunset(elements, mid, obsvconst);
+ MidObservational(obsvconst, mid);
+ mid[40] = 3;
+ CopyCircumstances(mid, c4);
+ } else if (pattern == 10000) {
+ mid[39] = 1;
+ GetSunset(elements, mid, obsvconst);
+ MidObservational(obsvconst, mid);
+ mid[40] = 3;
+ CopyCircumstances(mid, c4);
+ } else if (pattern == 1111) {
+ GetSunrise(elements, c1, obsvconst);
+ Observational(c1, obsvconst, mid);
+ c1[40] = 2;
+ } else if (pattern == 111) {
+ GetSunrise(elements, c2, obsvconst);
+ Observational(c2, obsvconst, mid);
+ c2[40] = 2;
+ CopyCircumstances(c2, c1);
+ } else if (pattern == 11) {
+ c2[40] = 4;
+ GetSunrise(elements, mid, obsvconst);
+ MidObservational(obsvconst, mid);
+ mid[40] = 2;
+ CopyCircumstances(mid, c1);
+ } else if (pattern == 1) {
+ mid[39] = 1;
+ GetSunrise(elements, mid, obsvconst);
+ MidObservational(obsvconst, mid);
+ mid[40] = 2;
+ CopyCircumstances(mid, c1);
+ } else if (pattern == 0) {
+ mid[39] = 0;
+ }
+ // There are other patterns, but those are the only ones we're covering!
+ } else {
+ mid[39] = 1; // Partial eclipse
+ Double pattern = 0;
+ Observational(c1, obsvconst, mid);
+ Observational(c4, obsvconst, mid);
+ if (c1[40] == 0) { pattern += 100; }
+ if (mid[40] == 0) { pattern += 10; }
+ if (c4[40] == 0) { pattern += 1; }
+ if (pattern == 110) {
+ GetSunset(elements, c4, obsvconst);
+ Observational(c4, obsvconst, mid);
+ c4[40] = 3;
+ } else if (pattern == 100) {
+ GetSunset(elements, mid, obsvconst);
+ MidObservational(obsvconst, mid);
+ mid[40] = 3;
+ CopyCircumstances(mid, c4);
+ } else if (pattern == 11) {
+ GetSunrise(elements, c1, obsvconst);
+ Observational(c1, obsvconst, mid);
+ c1[40] = 2;
+ } else if (pattern == 1) {
+ GetSunrise(elements, mid, obsvconst);
+ MidObservational(obsvconst, mid);
+ mid[40] = 2;
+ CopyCircumstances(mid, c1);
+ } else if (pattern == 0) {
+ mid[39] = 0;
+ }
+ // There are other patterns, but those are the only ones we're covering!
+ }
+ } else {
+ mid[39] = 0; // No eclipse
+ }
+ // Magnitude for total and annular eclipse is moon/sun ratio
+ if (mid[39] == 2 || mid[39] == 3) {
+ mid[37] = mid[38];
+ }
+ }
+ // Calculate mid eclipse
+ private static void GetMid(Double[] elements, Double[] obsvconst, Double[] mid) {
+ Double iter, tmp;
+
+ mid[0] = 0;
+ mid[1] = 0.0;
+ iter = 0;
+ tmp = 1.0;
+ _ = TimeLocDependent(elements, mid, obsvconst);
+ while ((tmp > 0.000001 || tmp < -0.000001) && iter < 50) {
+ tmp = (mid[24] * mid[26] + mid[25] * mid[27]) / mid[30];
+ mid[1] = mid[1] - tmp;
+ iter++;
+ _ = TimeLocDependent(elements, mid, obsvconst);
+ }
+ }
+ // Populate the circumstances array with the time and location dependent circumstances
+ private static Double[] TimeLocDependent(Double[] elements, Double[] circumstances, Double[] obsvconst) {
+ Double index, type;
+
+ _ = TimeDependent(elements, circumstances, obsvconst);
+ index = obsvconst[6];
+ // Calculate h, sin h, cos h
+ circumstances[16] = circumstances[7] - obsvconst[1] - elements[(Int32)index + 5] / 13713.44;
+ circumstances[17] = Math.Sin(circumstances[16]);
+ circumstances[18] = Math.Cos(circumstances[16]);
+ // Calculate xi
+ circumstances[19] = obsvconst[5] * circumstances[17];
+ // Calculate eta
+ circumstances[20] = obsvconst[4] * circumstances[6] - obsvconst[5] * circumstances[18] * circumstances[5];
+ // Calculate zeta
+ circumstances[21] = obsvconst[4] * circumstances[5] + obsvconst[5] * circumstances[18] * circumstances[6];
+ // Calculate dxi
+ circumstances[22] = circumstances[13] * obsvconst[5] * circumstances[18];
+ // Calculate deta
+ circumstances[23] = circumstances[13] * circumstances[19] * circumstances[5] - circumstances[21] * circumstances[12];
+ // Calculate u
+ circumstances[24] = circumstances[2] - circumstances[19];
+ // Calculate v
+ circumstances[25] = circumstances[3] - circumstances[20];
+ // Calculate a
+ circumstances[26] = circumstances[10] - circumstances[22];
+ // Calculate b
+ circumstances[27] = circumstances[11] - circumstances[23];
+ // Calculate l1'
+ type = circumstances[0];
+ if (type == -2 || type == 0 || type == 2) {
+ circumstances[28] = circumstances[8] - circumstances[21] * elements[26 + (Int32)index];
+ }
+ // Calculate l2'
+ if (type == -1 || type == 0 || type == 1) {
+ circumstances[29] = circumstances[9] - circumstances[21] * elements[27 + (Int32)index];
+ }
+ // Calculate n^2
+ circumstances[30] = circumstances[26] * circumstances[26] + circumstances[27] * circumstances[27];
+ return circumstances;
+ }
+ // Populate the circumstances array with the time-only dependent circumstances (x, y, d, m, ...)
+ private static Double[] TimeDependent(Double[] elements, Double[] circumstances, Double[] obsvconst) {
+ Double type, t, ans;
+
+ t = circumstances[1];
+ Int32 index = (Int32)obsvconst[6];
+ // Calculate x
+ ans = elements[9 + index] * t + elements[8 + index];
+ ans = ans * t + elements[7 + index];
+ ans = ans * t + elements[6 + index];
+ circumstances[2] = ans;
+ // Calculate dx
+ ans = 3.0 * elements[9 + index] * t + 2.0 * elements[8 + index];
+ ans = ans * t + elements[7 + index];
+ circumstances[10] = ans;
+ // Calculate y
+ ans = elements[13 + index] * t + elements[12 + index];
+ ans = ans * t + elements[11 + index];
+ ans = ans * t + elements[10 + index];
+ circumstances[3] = ans;
+ // Calculate dy
+ ans = 3.0 * elements[13 + index] * t + 2.0 * elements[12 + index];
+ ans = ans * t + elements[11 + index];
+ circumstances[11] = ans;
+ // Calculate d
+ ans = elements[16 + index] * t + elements[15 + index];
+ ans = ans * t + elements[14 + index];
+ ans = ans * Math.PI / 180.0;
+ circumstances[4] = ans;
+ // sin d and cos d
+ circumstances[5] = Math.Sin(ans);
+ circumstances[6] = Math.Cos(ans);
+ // Calculate dd
+ ans = 2.0 * elements[16 + index] * t + elements[15 + index];
+ ans = ans * Math.PI / 180.0;
+ circumstances[12] = ans;
+ // Calculate m
+ ans = elements[19 + index] * t + elements[18 + index];
+ ans = ans * t + elements[17 + index];
+ if (ans >= 360.0) {
+ ans -= 360.0;
+ }
+ ans = ans * Math.PI / 180.0;
+ circumstances[7] = ans;
+ // Calculate dm
+ ans = 2.0 * elements[19 + index] * t + elements[18 + index];
+ ans = ans * Math.PI / 180.0;
+ circumstances[13] = ans;
+ // Calculate l1 and dl1
+ type = circumstances[0];
+ if (type == -2 || type == 0 || type == 2) {
+ ans = elements[22 + index] * t + elements[21 + index];
+ ans = ans * t + elements[20 + index];
+ circumstances[8] = ans;
+ circumstances[14] = 2.0 * elements[22 + index] * t + elements[21 + index];
+ }
+ // Calculate l2 and dl2
+ if (type == -1 || type == 0 || type == 1) {
+ ans = elements[25 + index] * t + elements[24 + index];
+ ans = ans * t + elements[23 + index];
+ circumstances[9] = ans;
+ circumstances[15] = 2.0 * elements[25 + index] * t + elements[24 + index];
+ }
+ return circumstances;
+ }
+ // Get the observational circumstances for mid eclipse
+ private static void MidObservational(Double[] obsvconst, Double[] mid) {
+ Observational(mid, obsvconst, mid);
+ // Calculate m, magnitude and moon/sun
+ mid[36] = Math.Sqrt(mid[24] * mid[24] + mid[25] * mid[25]);
+ mid[37] = (mid[28] - mid[36]) / (mid[28] + mid[29]);
+ mid[38] = (mid[28] - mid[29]) / (mid[28] + mid[29]);
+ }
+ // Get the observational circumstances
+ private static void Observational(Double[] circumstances, Double[] obsvconst, Double[] mid) {
+ Double contacttype, coslat, sinlat;
+
+ // We are looking at an "external" contact UNLESS this is a total eclipse AND we are looking at
+ // c2 or c3, in which case it is an INTERNAL contact! Note that if we are looking at mid eclipse,
+ // then we may not have determined the type of eclipse (mid[39]) just yet!
+ contacttype = circumstances[0] == 0 ? 1.0 : mid[39] == 3 && (circumstances[0] == -1 || circumstances[0] == 1) ? -1.0 : 1.0;
+ // Calculate p
+ circumstances[31] = Math.Atan2(contacttype * circumstances[24], contacttype * circumstances[25]);
+ // Calculate alt
+ sinlat = Math.Sin(obsvconst[0]);
+ coslat = Math.Cos(obsvconst[0]);
+ circumstances[32] = Math.Asin(circumstances[5] * sinlat + circumstances[6] * coslat * circumstances[18]);
+ // Calculate q
+ circumstances[33] = Math.Asin(coslat * circumstances[17] / Math.Cos(circumstances[32]));
+ if (circumstances[20] < 0.0) {
+ circumstances[33] = Math.PI - circumstances[33];
+ }
+ // Calculate v
+ circumstances[34] = circumstances[31] - circumstances[33];
+ // Calculate azi
+ circumstances[35] = Math.Atan2(-1.0 * circumstances[17] * circumstances[6], circumstances[5] * coslat - circumstances[18] * sinlat * circumstances[6]);
+ // Calculate visibility
+ circumstances[40] = circumstances[32] > -0.00524 ? 0 : 1;
+ }
+ // Get C1 and C4 data
+ // Entry conditions -
+ // 1. The mid array must be populated
+ // 2. The magnitude at mid eclipse must be > 0.0
+ private static void Getc1c4(Double[] elements, Double[] obsvconst, Double[] mid, Double[] c1, Double[] _1, Double[] _2, Double[] c4) {
+ Double tmp, n;
+
+ n = Math.Sqrt(mid[30]);
+ tmp = mid[26] * mid[25] - mid[24] * mid[27];
+ tmp = tmp / n / mid[28];
+ tmp = Math.Sqrt(1.0 - tmp * tmp) * mid[28] / n;
+ c1[0] = -2;
+ c4[0] = 2;
+ c1[1] = mid[1] - tmp;
+ c4[1] = mid[1] + tmp;
+ _ = C1c4iterate(elements, c1, obsvconst);
+ _ = C1c4iterate(elements, c4, obsvconst);
+ }
+ // Iterate on C1 or C4
+ private static Double[] C1c4iterate(Double[] elements, Double[] circumstances, Double[] obsvconst) {
+ Double sign, iter, tmp, n;
+
+ _ = TimeLocDependent(elements, circumstances, obsvconst);
+ sign = circumstances[0] < 0 ? -1.0 : 1.0;
+ tmp = 1.0;
+ iter = 0;
+ while ((tmp > 0.000001 || tmp < -0.000001) && iter < 50) {
+ n = Math.Sqrt(circumstances[30]);
+ tmp = circumstances[26] * circumstances[25] - circumstances[24] * circumstances[27];
+ tmp = tmp / n / circumstances[28];
+ tmp = sign * Math.Sqrt(1.0 - tmp * tmp) * circumstances[28] / n;
+ tmp = (circumstances[24] * circumstances[26] + circumstances[25] * circumstances[27]) / circumstances[30] - tmp;
+ circumstances[1] = circumstances[1] - tmp;
+ _ = TimeLocDependent(elements, circumstances, obsvconst);
+ iter++;
+ }
+ return circumstances;
+ }
+ // Get C2 and C3 data
+ // Entry conditions -
+ // 1. The mid array must be populated
+ // 2. There must be either a total or annular eclipse at the location!
+ private static void Getc2c3(Double[] elements, Double[] obsvconst, Double[] mid, Double[] c2, Double[] c3) {
+ Double tmp, n;
+
+ n = Math.Sqrt(mid[30]);
+ tmp = mid[26] * mid[25] - mid[24] * mid[27];
+ tmp = tmp / n / mid[29];
+ tmp = Math.Sqrt(1.0 - tmp * tmp) * mid[29] / n;
+ c2[0] = -1;
+ c3[0] = 1;
+ if (mid[29] < 0.0) {
+ c2[1] = mid[1] + tmp;
+ c3[1] = mid[1] - tmp;
+ } else {
+ c2[1] = mid[1] - tmp;
+ c3[1] = mid[1] + tmp;
+ }
+ _ = C2c3iterate(elements, c2, obsvconst, mid);
+ _ = C2c3iterate(elements, c3, obsvconst, mid);
+ }
+ // Iterate on C2 or C3
+ private static Double[] C2c3iterate(Double[] elements, Double[] circumstances, Double[] obsvconst, Double[] mid) {
+ Double sign, iter, tmp, n;
+
+ _ = TimeLocDependent(elements, circumstances, obsvconst);
+ sign = circumstances[0] < 0 ? -1.0 : 1.0;
+ if (mid[29] < 0.0) {
+ sign = -sign;
+ }
+ tmp = 1.0;
+ iter = 0;
+ while ((tmp > 0.000001 || tmp < -0.000001) && iter < 50) {
+ n = Math.Sqrt(circumstances[30]);
+ tmp = circumstances[26] * circumstances[25] - circumstances[24] * circumstances[27];
+ tmp = tmp / n / circumstances[29];
+ tmp = sign * Math.Sqrt(1.0 - tmp * tmp) * circumstances[29] / n;
+ tmp = (circumstances[24] * circumstances[26] + circumstances[25] * circumstances[27]) / circumstances[30] - tmp;
+ circumstances[1] = circumstances[1] - tmp;
+ _ = TimeLocDependent(elements, circumstances, obsvconst);
+ iter++;
+ }
+ return circumstances;
+ }
+ // Get the date of an event
+ private static String GetDate(Double[] elements, Double[] circumstances, Double[] obsvconst) {
+ String[] month = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ Double t, jd, a, b, c, d, e, index;
+ index = obsvconst[6];
+ // Calculate the JD for noon (TDT) the day before the day that contains T0
+ jd = Math.Floor(elements[(Int32)index] - elements[1 + (Int32)index] / 24.0);
+ // Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0).
+ t = circumstances[1] + elements[1 + (Int32)index] - obsvconst[3] - (elements[4 + (Int32)index] - 0.5) / 3600.0;
+ if (t < 0.0) {
+ jd--;
+ }
+ if (t >= 24.0) {
+ jd++;
+ }
+ if (jd >= 2299160.0) {
+ a = Math.Floor((jd - 1867216.25) / 36524.25);
+ a = jd + 1 + a - Math.Floor(a / 4.0);
+ } else {
+ a = jd;
+ }
+ b = a + 1525.0;
+ c = Math.Floor((b - 122.1) / 365.25);
+ d = Math.Floor(365.25 * c);
+ e = Math.Floor((b - d) / 30.6001);
+ d = b - d - Math.Floor(30.6001 * e);
+ if (e < 13.5) {
+ e -= 1;
+ } else {
+ e -= 13;
+ }
+ Double year;
+ String ans;
+ if (e > 2.5) {
+ ans = c - 4716 + "-";
+ year = c - 4716;
+ } else {
+ ans = c - 4715 + "-";
+ year = c - 4715;
+ }
+ String m = month[(Int32)e - 1];
+ ans += m + "-";
+ if (d < 10) {
+ ans += "0";
+ }
+
+ ans += d;
+ //Leap Year Integrity Check
+
+ if (m == "Feb" && d == 29 && !DateTime.IsLeapYear((Int32)year)) {
+ ans = year.ToString() + "-Mar-01";
+ }
+ return ans;
+ }
+ // Calculate the time of sunset
+ private static void GetSunset(Double[] elements, Double[] circumstances, Double[] obsvconst) => GetSunriset(elements, circumstances, 1.0, obsvconst);
+ // Calculate the time of sunrise
+ private static void GetSunrise(Double[] elements, Double[] circumstances, Double[] obsvconst) => GetSunriset(elements, circumstances, -1.0, obsvconst);
+ // Calculate the time of sunrise or sunset
+ private static void GetSunriset(Double[] elements, Double[] circumstances, Double riset, Double[] obsvconst) {
+ Double h0, diff, iter;
+
+ diff = 1.0;
+ iter = 0;
+ while (diff > 0.00001 || diff < -0.00001) {
+ iter++;
+ if (iter == 4) { return; }
+ h0 = Math.Acos((Math.Sin(-0.00524) - Math.Sin(obsvconst[0]) * circumstances[5]) / Math.Cos(obsvconst[0]) / circumstances[6]);
+ diff = (riset * h0 - circumstances[16]) / circumstances[13];
+ while (diff >= 12.0) { diff -= 24.0; }
+ while (diff <= -12.0) { diff += 24.0; }
+ circumstances[1] += diff;
+ _ = TimeLocDependent(elements, circumstances, obsvconst);
+ }
+ }
+ // Copy a set of circumstances
+ private static void CopyCircumstances(Double[] circumstancesfrom, Double[] circumstancesto) {
+ for (Int32 i = 1; i < 41; i++) {
+ circumstancesto[i] = circumstancesfrom[i];
+ }
+ }
+ // Get the local time of an event
+ private static String GetTime(Double[] elements, Double[] circumstances, Double[] obsvconst) {
+ String ans = "";
+ Int32 index = (Int32)obsvconst[6];
+ Double t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[4 + index] - 0.5) / 3600.0;
+ if (t < 0.0) {
+ t += 24.0;
+ }
+ if (t >= 24.0) {
+ t -= 24.0;
+ }
+ if (t < 10.0) {
+ ans += "0";
+ }
+ ans = ans + Math.Floor(t) + ":";
+ t = t * 60.0 - 60.0 * Math.Floor(t);
+ if (t < 10.0) {
+ ans += "0";
+ }
+ ans += Math.Floor(t);
+ if (circumstances[40] <= 1) { // not sunrise or sunset
+ ans += ":";
+ t = t * 60.0 - 60.0 * Math.Floor(t);
+ if (t < 10.0) {
+ ans += "0";
+ }
+ ans += Math.Floor(t);
+ }
+ if (circumstances[40] == 1) {
+ //WAS ITALIC
+ return ans;
+ } else if (circumstances[40] == 2) {
+ //Rise (CHANGED FROM NASA CALC THE INDICATES (r) WITH STRING, INVESTIGATE REMOVAL)
+ return ans;
+ } else if (circumstances[40] == 3) {
+ //Set (CHANGED FROM NASA CALC THE INDICATES (s) WITH STRING, INVESTIGATE REMOVAL)
+ return ans;
+ } else {
+ return ans;
+ }
+ }
+ // Get the altitude
+ private static String GetAlt(Double[] circumstances) {
+ Double t;
+ if (circumstances[40] == 2) {
+ return "0(r)";
+ }
+ if (circumstances[40] == 3) {
+ return "0(s)";
+ }
+ if (circumstances[32] < 0.0 && circumstances[32] >= -0.00524) {
+ // Crude correction for refraction (and for consistency's sake)
+ t = 0.0;
+ } else {
+ t = circumstances[32] * 180.0 / Math.PI;
+ }
+ String ans;
+ if (t < 0.0) {
+ ans = "-";
+ t = -t;
+ } else {
+ ans = "";
+ }
+ t = Math.Floor(t + 0.5);
+ if (t < 10.0) {
+ ans += "0";
+ }
+ ans += t;
+ if (circumstances[40] == 1) {
+ //WAS ITALIC
+ return ans;
+ } else {
+ return ans;
+ }
+ }
+ // Get the azimuth
+ private static String GetAzi(Double[] circumstances) {
+ String ans = "";
+ Double t = circumstances[35] * 180.0 / Math.PI;
+ if (t < 0.0) {
+ t += 360.0;
+ }
+ if (t >= 360.0) {
+ t -= 360.0;
+ }
+ t = Math.Floor(t + 0.5);
+ if (t < 100.0) {
+ ans += "0";
+ }
+ if (t < 10.0) {
+ ans += "0";
+ }
+ ans += t;
+ if (circumstances[40] == 1) {
+ //WAS ITALIC
+ return ans;
+ } else {
+ return ans;
+ }
+ }
+ // Get the magnitude
+ private static String GetMagnitude(Double[] mid) {
+ Double a = Math.Floor(1000.0 * mid[37] + 0.5) / 1000.0;
+ String ans = a.ToString();
+ if (mid[40] == 1) {
+ return ans;
+ }
+ if (mid[40] == 2) {
+ ans = a.ToString() + "(r)";
+ }
+ if (mid[40] == 3) {
+ ans = a.ToString() + "(s)";
+ }
+ return ans;
+ }
+ // Get the coverage
+ private static String GetCoverage(Double[] mid) {
+ Double a = 0, b, c;
+ String ans;
+ if (mid[37] <= 0.0) {
+ ans = "0.0";
+ } else if (mid[37] >= 1.0) {
+ ans = "1.000";
+ } else {
+ if (mid[39] == 2) {
+ c = mid[38] * mid[38];
+ } else {
+ c = Math.Acos((mid[28] * mid[28] + mid[29] * mid[29] - 2.0 * mid[36] * mid[36]) / (mid[28] * mid[28] - mid[29] * mid[29]));
+ b = Math.Acos((mid[28] * mid[29] + mid[36] * mid[36]) / mid[36] / (mid[28] + mid[29]));
+ a = Math.PI - b - c;
+ c = (mid[38] * mid[38] * a + b - mid[38] * Math.Sin(c)) / Math.PI;
+ }
+ a = Math.Floor(1000.0 * c + 0.5) / 1000.0;
+ ans = a.ToString();
+ }
+ if (mid[40] == 1) {
+ //WAS ITALIC
+ return ans;
+ }
+ if (mid[40] == 2) {
+ ans = a.ToString() + "(r)";
+ }
+ if (mid[40] == 3) {
+ ans = a + "(s)";
+ }
+ return ans;
+ }
+ // Get the duration in mm:ss.s format
+ // Adapted from code written by Stephen McCann - 27/04/2001
+ private static String GetDuration(Double[] mid, Double[] c2, Double[] c3) {
+ Double tmp;
+ String ans;
+
+ tmp = c3[40] == 4 ? mid[1] - c2[1] : c2[40] == 4 ? c3[1] - mid[1] : c3[1] - c2[1];
+ if (tmp < 0.0) {
+ tmp += 24.0;
+ } else if (tmp >= 24.0) {
+ tmp -= 24.0;
+ }
+ tmp = tmp * 60.0 - 60.0 * Math.Floor(tmp) + 0.05 / 60.0;
+ ans = Math.Floor(tmp) + "m";
+ tmp = tmp * 60.0 - 60.0 * Math.Floor(tmp);
+ if (tmp < 10.0) {
+ ans += "0";
+ }
+ ans += Math.Floor(tmp) + "s";
+ return ans;
+ }
+ }
}
diff --git a/CoordinateSharp/Celestial.SunCalculations.cs b/CoordinateSharp/Celestial.SunCalculations.cs
index 376d019..bf0f07e 100644
--- a/CoordinateSharp/Celestial.SunCalculations.cs
+++ b/CoordinateSharp/Celestial.SunCalculations.cs
@@ -1,374 +1,318 @@
using System;
using System.Collections.Generic;
-namespace CoordinateSharp
-{
- internal class SunCalc
- {
- public static void CalculateSunTime(double lat, double longi, DateTime date, Celestial c,double offset = 0)
- {
- if (date.Year == 0001) { return; } //Return if date vaue hasn't been established.
- DateTime actualDate = new DateTime(date.Year,date.Month,date.Day,0, 0, 0, DateTimeKind.Utc);
- ////Sun Time Calculations
-
- //Get Julian
- double lw = rad * -longi;
- double phi = rad * lat;
+namespace CoordinateSharp {
+ internal class SunCalc {
+ public static void CalculateSunTime(Double lat, Double longi, DateTime date, Celestial c, Double _ = 0) {
+ if (date.Year == 0001) { return; } //Return if date vaue hasn't been established.
+ DateTime actualDate = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc);
- //Rise Set
- DateTime?[] evDate = Get_Event_Time(lw, phi, -.8333, actualDate);
- c.sunRise = evDate[0];
- c.sunSet = evDate[1];
-
- c.sunCondition = CelestialStatus.RiseAndSet;
- //Azimuth and Altitude
- CalculateSunAngle(date, longi, lat, c);
- // neither sunrise nor sunset
- if ((!c.SunRise.HasValue) && (!c.SunSet.HasValue))
- {
- if (c.SunAltitude < 0)
- {
- c.sunCondition = CelestialStatus.DownAllDay;
- }
- else
- {
- c.sunCondition = CelestialStatus.UpAllDay;
- }
- }
- // sunrise or sunset
- else
- {
- if (!c.SunRise.HasValue)
- {
- // No sunrise this date
- c.sunCondition = CelestialStatus.NoRise;
+ ////Sun Time Calculations
- }
- else if (!c.SunSet.HasValue)
- {
- // No sunset this date
- c.sunCondition = CelestialStatus.NoSet;
- }
- }
- //Additional Times
- c.additionalSolarTimes = new AdditionalSolarTimes();
- //Dusk and Dawn
- //Civil
- evDate = Get_Event_Time(lw, phi, -6, actualDate);
- c.AdditionalSolarTimes.CivilDawn = evDate[0];
- c.AdditionalSolarTimes.CivilDusk = evDate[1];
+ //Get Julian
+ Double lw = rad * -longi;
+ Double phi = rad * lat;
+ //Rise Set
+ DateTime?[] evDate = Get_Event_Time(lw, phi, -.8333, actualDate);
+ c.sunRise = evDate[0];
+ c.sunSet = evDate[1];
- //Nautical
- evDate = Get_Event_Time(lw, phi, -12, actualDate);
- c.AdditionalSolarTimes.NauticalDawn = evDate[0];
- c.AdditionalSolarTimes.NauticalDusk = evDate[1];
+ c.sunCondition = CelestialStatus.RiseAndSet;
+ //Azimuth and Altitude
+ CalculateSunAngle(date, longi, lat, c);
+ // neither sunrise nor sunset
+ if (!c.SunRise.HasValue && !c.SunSet.HasValue) {
+ c.sunCondition = c.SunAltitude < 0 ? CelestialStatus.DownAllDay : CelestialStatus.UpAllDay;
+ }
+ // sunrise or sunset
+ else {
+ if (!c.SunRise.HasValue) {
+ // No sunrise this date
+ c.sunCondition = CelestialStatus.NoRise;
- //Astronomical
- evDate = Get_Event_Time(lw, phi, -18, actualDate);
-
- c.AdditionalSolarTimes.AstronomicalDawn = evDate[0];
- c.AdditionalSolarTimes.AstronomicalDusk = evDate[1];
-
- //BottomDisc
- evDate = Get_Event_Time(lw, phi, -.2998, actualDate);
- c.AdditionalSolarTimes.SunriseBottomDisc = evDate[0];
- c.AdditionalSolarTimes.SunsetBottomDisc = evDate[1];
-
- CalculateSolarEclipse(date, lat, longi, c);
-
- }
- ///
- /// Gets time of event based on specified degree below horizon
- ///
- /// Observer Longitude in radians
- /// Observer Latitude in radians
- /// Angle in Degrees
- /// Date of Event
- /// DateTime?[]{rise, set}
- private static DateTime?[] Get_Event_Time(double lw, double phi, double h,DateTime date)
- {
- //Create arrays. Index 0 = Day -1, 1 = Day, 2 = Day + 1;
- //These will be used to find exact day event occurs for comparison
- DateTime?[] sets = new DateTime?[] { null, null, null, null, null };
- DateTime?[] rises = new DateTime?[] { null, null, null,null, null };
-
- //Iterate starting with day -1;
- for (int x = 0; x < 5; x++)
- {
- double d = JulianConversions.GetJulian(date.AddDays(x-2)) - j2000 + .5; //LESS PRECISE JULIAN NEEDED
-
- double n = julianCycle(d, lw);
- double ds = approxTransit(0, lw, n);
-
- double M = solarMeanAnomaly(ds);
- double L = eclipticLongitude(M);
-
- double dec = declination(L, 0);
-
- double Jnoon = solarTransitJ(ds, M, L);
-
- double Jset;
- double Jrise;
-
-
- DateTime? solarNoon = JulianConversions.GetDate_FromJulian(Jnoon);
- DateTime? nadir = JulianConversions.GetDate_FromJulian(Jnoon - 0.5);
-
- //Rise Set
- Jset = GetTime(h * rad, lw, phi, dec, n, M, L);
- Jrise = Jnoon - (Jset - Jnoon);
-
- DateTime? rise = JulianConversions.GetDate_FromJulian(Jrise);
- DateTime? set = JulianConversions.GetDate_FromJulian(Jset);
-
- rises[x] = rise;
- sets[x] = set;
- }
-
- //Compare and send
- DateTime? tRise = null;
- for(int x=0;x<5;x++)
- {
- if(rises[x].HasValue)
- {
- if(rises[x].Value.Day == date.Day)
- {
- tRise = rises[x];
- break;
- }
- }
- }
- DateTime? tSet = null;
- for (int x = 0; x < 5; x++)
- {
- if (sets[x].HasValue)
- {
- if (sets[x].Value.Day == date.Day)
- {
- tSet = sets[x];
- break;
- }
- }
- }
- return new DateTime?[] { tRise, tSet };
+ } else if (!c.SunSet.HasValue) {
+ // No sunset this date
+ c.sunCondition = CelestialStatus.NoSet;
}
+ }
+ //Additional Times
+ c.additionalSolarTimes = new AdditionalSolarTimes();
+ //Dusk and Dawn
+ //Civil
+ evDate = Get_Event_Time(lw, phi, -6, actualDate);
+ c.AdditionalSolarTimes.CivilDawn = evDate[0];
+ c.AdditionalSolarTimes.CivilDusk = evDate[1];
- public static void CalculateZodiacSign(DateTime date, Celestial c)
- {
- //Aquarius (January 20 to February 18)
- //Pisces (February 19 to March 20)
- //Aries (March 21-April 19)
- //Taurus (April 20-May 20)
- //Gemini (May 21-June 20)
- //Cancer (June 21-July 22)
- //Leo (July 23-August 22)
- //Virgo (August 23-September 22)
- //Libra (September 23-October 22)
- //Scorpio (October 23-November 21)
- //Sagittarius (November 22-December 21)
- //Capricorn (December 22-January 19)
- if (date >= new DateTime(date.Year, 1, 1) && date <= new DateTime(date.Year, 1, 19, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Capricorn";
- return;
- }
- if (date >= new DateTime(date.Year, 1, 20) && date <= new DateTime(date.Year, 2, 18, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Aquarius";
- return;
- }
- if (date >= new DateTime(date.Year, 2, 19) && date <= new DateTime(date.Year, 3, 20, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Pisces";
- return;
- }
- if (date >= new DateTime(date.Year, 3, 21) && date <= new DateTime(date.Year, 4, 19, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Aries";
- return;
- }
- if (date >= new DateTime(date.Year, 4, 20) && date <= new DateTime(date.Year, 5, 20, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Taurus";
- return;
- }
- if (date >= new DateTime(date.Year, 5, 21) && date <= new DateTime(date.Year, 6, 20,23,59,59))
- {
- c.AstrologicalSigns.ZodiacSign = "Gemini";
- return;
- }
- if (date >= new DateTime(date.Year, 6, 21) && date <= new DateTime(date.Year, 7, 22, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Cancer";
- return;
- }
- if (date >= new DateTime(date.Year, 7, 23) && date <= new DateTime(date.Year, 8, 22, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Leo";
- return;
- }
- if (date >= new DateTime(date.Year, 8, 23) && date <= new DateTime(date.Year, 9, 22, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Virgo";
- return;
- }
- if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 10, 22, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Libra";
- return;
- }
- if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 11, 21, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Scorpio";
- return;
- }
- if (date >= new DateTime(date.Year, 11, 21) && date <= new DateTime(date.Year, 12, 21, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Sagittarius";
- return;
- }
- if (date >= new DateTime(date.Year, 12, 22) && date <= new DateTime(date.Year, 12, 31, 23, 59, 59))
- {
- c.AstrologicalSigns.ZodiacSign = "Capricorn";
- return;
- }
- }
- public static void CalculateSolarEclipse(DateTime date, double lat, double longi, Celestial c)
- {
- //Convert to Radian
- double latR = lat * Math.PI / 180;
- double longR = longi * Math.PI / 180;
- List> se = SolarEclipseCalc.CalculateSolarEclipse(date, latR, longR);
- //RETURN FIRST AND LAST
- if (se.Count == 0) { return; }
- //FIND LAST AND NEXT ECLIPSE
- int lastE = -1;
- int nextE = -1;
- int currentE = 0;
- DateTime lastDate = new DateTime();
- DateTime nextDate = new DateTime(3300, 1, 1);
- //Iterate to get last and next eclipse
- foreach(List values in se)
- {
- DateTime ld = DateTime.ParseExact(values[0], "yyyy-MMM-dd", System.Globalization.CultureInfo.InvariantCulture);
-
- if (ld < date && ld>lastDate) { lastDate = ld;lastE = currentE; }
- if(ld>= date && ld < nextDate) { nextDate = ld;nextE = currentE; }
- currentE++;
- }
- //SET ECLIPSE DATA
- if (lastE >= 0)
- {
- c.SolarEclipse.LastEclipse = new SolarEclipseDetails(se[lastE]);
- }
- if (nextE >= 0)
- {
- c.SolarEclipse.NextEclipse = new SolarEclipseDetails(se[nextE]);
- }
- }
- #region Private Suntime Members
- private static readonly double dayMS = 1000 * 60 * 60 * 24, j1970 = 2440588, j2000 = 2451545;
- private static readonly double rad = Math.PI / 180;
+ //Nautical
+ evDate = Get_Event_Time(lw, phi, -12, actualDate);
+ c.AdditionalSolarTimes.NauticalDawn = evDate[0];
+ c.AdditionalSolarTimes.NauticalDusk = evDate[1];
- private static double LocalSiderealTimeForTimeZone(double lon, double jd, double z)
- {
- double s = 24110.5 + 8640184.812999999 * jd / 36525 + 86636.6 * z + 86400 * lon;
- s = s / 86400;
- s = s - Math.Truncate(s);
- double lst = s * 360 *rad;
-
- return lst;
- }
- private static double SideRealTime(double d, double lw)
- {
- double s = rad * (280.16 + 360.9856235 * d) - lw;
- return s;
- }
- private static double solarTransitJ(double ds, double M, double L)
- {
- return j2000 + ds + 0.0053 * Math.Sin(M) - 0.0069 * Math.Sin(2 * L);
- }
-
- //CH15
- //Formula 15.1
- //Returns Approximate Time
- private static double hourAngle(double h, double phi, double d)
- {
- //NUMBER RETURNING > and < 1 NaN;
- double d1 = Math.Sin(h) - Math.Sin(phi) * Math.Sin(d);
- double d2 = Math.Cos(phi) * Math.Cos(d);
- double d3 = (d1 / d2);
-
- return Math.Acos(d3);
- }
- private static double approxTransit(double Ht, double lw, double n)
- {
- return 0.0009 + (Ht + lw) / (2 * Math.PI) + n;
- }
-
- private static double julianCycle(double d, double lw) { return Math.Round(d - 0.0009 - lw / (2 * Math.PI)); }
+ //Astronomical
+ evDate = Get_Event_Time(lw, phi, -18, actualDate);
- //Returns Time of specified event based on suns angle
- private static double GetTime(double h, double lw, double phi, double dec, double n,double M, double L)
- {
- double approxTime = hourAngle(h, phi, dec); //Ch15 Formula 15.1
+ c.AdditionalSolarTimes.AstronomicalDawn = evDate[0];
+ c.AdditionalSolarTimes.AstronomicalDusk = evDate[1];
- double a = approxTransit(approxTime, lw, n);
- double st = solarTransitJ(a, M, L);
-
- return st;
- }
- private static double declination(double l, double b)
- {
- double e = (Math.PI/180) * 23.4392911; // obliquity of the Earth
-
- return Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));
- }
-
- private static void CalculateSunAngle(DateTime date, double longi, double lat, Celestial c)
- {
- TimeSpan ts = date - new DateTime(1970, 1, 1,0,0,0, DateTimeKind.Utc);
- double dms = (ts.TotalMilliseconds / dayMS -.5 + j1970)-j2000;
-
- double lw = rad * -longi;
- double phi = rad * lat;
- double e = rad * 23.4397;
-
- double[] sc = sunCoords(dms);
-
- double H = SideRealTime(dms, lw) - sc[1];
+ //BottomDisc
+ evDate = Get_Event_Time(lw, phi, -.2998, actualDate);
+ c.AdditionalSolarTimes.SunriseBottomDisc = evDate[0];
+ c.AdditionalSolarTimes.SunsetBottomDisc = evDate[1];
- c.sunAzimuth = Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(sc[0]) * Math.Cos(phi)) * 180 / Math.PI + 180;
- c.sunAltitude = Math.Asin(Math.Sin(phi) * Math.Sin(sc[0]) + Math.Cos(phi) * Math.Cos(sc[0]) * Math.Cos(H)) * 180 / Math.PI;
- }
+ CalculateSolarEclipse(date, lat, longi, c);
- private static double solarMeanAnomaly(double d)
- {
- return rad * (357.5291 + 0.98560028 * d);
- }
-
- private static double eclipticLongitude(double m)
- {
- double c = rad * (1.9148 * Math.Sin(m) + 0.02 * Math.Sin(2 * m) + 0.0003 * Math.Sin(3 * m)); // equation of center
- double p = rad * 102.9372; // perihelion of the Earth
-
- return m + c + p + Math.PI;
- }
- private static double[] sunCoords(double d)
- {
-
- double m = solarMeanAnomaly(d);
- double l = eclipticLongitude(m);
- double[] sc = new double[2];
- double b = 0;
- double e = rad * 23.4397; // obliquity of the Earth
- sc[0] = Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l)); //declination
- sc[1] = Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l)); //rightAscension
- return sc;
- }
- #endregion
-
}
+ ///
+ /// Gets time of event based on specified degree below horizon
+ ///
+ /// Observer Longitude in radians
+ /// Observer Latitude in radians
+ /// Angle in Degrees
+ /// Date of Event
+ /// DateTime?[]{rise, set}
+ private static DateTime?[] Get_Event_Time(Double lw, Double phi, Double h, DateTime date) {
+ //Create arrays. Index 0 = Day -1, 1 = Day, 2 = Day + 1;
+ //These will be used to find exact day event occurs for comparison
+ DateTime?[] sets = new DateTime?[] { null, null, null, null, null };
+ DateTime?[] rises = new DateTime?[] { null, null, null, null, null };
+
+ //Iterate starting with day -1;
+ for (Int32 x = 0; x < 5; x++) {
+ Double d = JulianConversions.GetJulian(date.AddDays(x - 2)) - j2000 + .5; //LESS PRECISE JULIAN NEEDED
+
+ Double n = JulianCycle(d, lw);
+ Double ds = ApproxTransit(0, lw, n);
+
+ Double M = SolarMeanAnomaly(ds);
+ Double L = EclipticLongitude(M);
+
+ Double dec = Declination(L, 0);
+
+ Double Jnoon = SolarTransitJ(ds, M, L);
+
+ Double Jset;
+ Double Jrise;
+
+
+ //DateTime? solarNoon = JulianConversions.GetDate_FromJulian(Jnoon);
+ //DateTime? nadir = JulianConversions.GetDate_FromJulian(Jnoon - 0.5);
+
+ //Rise Set
+ Jset = GetTime(h * rad, lw, phi, dec, n, M, L);
+ Jrise = Jnoon - (Jset - Jnoon);
+
+ DateTime? rise = JulianConversions.GetDate_FromJulian(Jrise);
+ DateTime? set = JulianConversions.GetDate_FromJulian(Jset);
+
+ rises[x] = rise;
+ sets[x] = set;
+ }
+
+ //Compare and send
+ DateTime? tRise = null;
+ for (Int32 x = 0; x < 5; x++) {
+ if (rises[x].HasValue) {
+ if (rises[x].Value.Day == date.Day) {
+ tRise = rises[x];
+ break;
+ }
+ }
+ }
+ DateTime? tSet = null;
+ for (Int32 x = 0; x < 5; x++) {
+ if (sets[x].HasValue) {
+ if (sets[x].Value.Day == date.Day) {
+ tSet = sets[x];
+ break;
+ }
+ }
+ }
+ return new DateTime?[] { tRise, tSet };
+ }
+
+ public static void CalculateZodiacSign(DateTime date, Celestial c) {
+ //Aquarius (January 20 to February 18)
+ //Pisces (February 19 to March 20)
+ //Aries (March 21-April 19)
+ //Taurus (April 20-May 20)
+ //Gemini (May 21-June 20)
+ //Cancer (June 21-July 22)
+ //Leo (July 23-August 22)
+ //Virgo (August 23-September 22)
+ //Libra (September 23-October 22)
+ //Scorpio (October 23-November 21)
+ //Sagittarius (November 22-December 21)
+ //Capricorn (December 22-January 19)
+ if (date >= new DateTime(date.Year, 1, 1) && date <= new DateTime(date.Year, 1, 19, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Capricorn";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 1, 20) && date <= new DateTime(date.Year, 2, 18, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Aquarius";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 2, 19) && date <= new DateTime(date.Year, 3, 20, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Pisces";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 3, 21) && date <= new DateTime(date.Year, 4, 19, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Aries";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 4, 20) && date <= new DateTime(date.Year, 5, 20, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Taurus";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 5, 21) && date <= new DateTime(date.Year, 6, 20, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Gemini";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 6, 21) && date <= new DateTime(date.Year, 7, 22, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Cancer";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 7, 23) && date <= new DateTime(date.Year, 8, 22, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Leo";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 8, 23) && date <= new DateTime(date.Year, 9, 22, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Virgo";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 10, 22, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Libra";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 11, 21, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Scorpio";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 11, 21) && date <= new DateTime(date.Year, 12, 21, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Sagittarius";
+ return;
+ }
+ if (date >= new DateTime(date.Year, 12, 22) && date <= new DateTime(date.Year, 12, 31, 23, 59, 59)) {
+ c.AstrologicalSigns.ZodiacSign = "Capricorn";
+ return;
+ }
+ }
+ public static void CalculateSolarEclipse(DateTime date, Double lat, Double longi, Celestial c) {
+ //Convert to Radian
+ Double latR = lat * Math.PI / 180;
+ Double longR = longi * Math.PI / 180;
+ List> se = SolarEclipseCalc.CalculateSolarEclipse(date, latR, longR);
+ //RETURN FIRST AND LAST
+ if (se.Count == 0) { return; }
+ //FIND LAST AND NEXT ECLIPSE
+ Int32 lastE = -1;
+ Int32 nextE = -1;
+ Int32 currentE = 0;
+ DateTime lastDate = new DateTime();
+ DateTime nextDate = new DateTime(3300, 1, 1);
+ //Iterate to get last and next eclipse
+ foreach (List values in se) {
+ DateTime ld = DateTime.ParseExact(values[0], "yyyy-MMM-dd", System.Globalization.CultureInfo.InvariantCulture);
+
+ if (ld < date && ld > lastDate) { lastDate = ld; lastE = currentE; }
+ if (ld >= date && ld < nextDate) { nextDate = ld; nextE = currentE; }
+ currentE++;
+ }
+ //SET ECLIPSE DATA
+ if (lastE >= 0) {
+ c.SolarEclipse.LastEclipse = new SolarEclipseDetails(se[lastE]);
+ }
+ if (nextE >= 0) {
+ c.SolarEclipse.NextEclipse = new SolarEclipseDetails(se[nextE]);
+ }
+ }
+
+ #region Private Suntime Members
+ private static readonly Double dayMS = 1000 * 60 * 60 * 24, j1970 = 2440588, j2000 = 2451545;
+ private static readonly Double rad = Math.PI / 180;
+
+ /*private static Double LocalSiderealTimeForTimeZone(Double lon, Double jd, Double z)
+ {
+ Double s = 24110.5 + 8640184.812999999 * jd / 36525 + 86636.6 * z + 86400 * lon;
+ s = s / 86400;
+ s = s - Math.Truncate(s);
+ Double lst = s * 360 *rad;
+
+ return lst;
+ }*/
+ private static Double SideRealTime(Double d, Double lw) {
+ Double s = rad * (280.16 + 360.9856235 * d) - lw;
+ return s;
+ }
+ private static Double SolarTransitJ(Double ds, Double M, Double L) => j2000 + ds + 0.0053 * Math.Sin(M) - 0.0069 * Math.Sin(2 * L);
+
+ //CH15
+ //Formula 15.1
+ //Returns Approximate Time
+ private static Double HourAngle(Double h, Double phi, Double d) {
+ //NUMBER RETURNING > and < 1 NaN;
+ Double d1 = Math.Sin(h) - Math.Sin(phi) * Math.Sin(d);
+ Double d2 = Math.Cos(phi) * Math.Cos(d);
+ Double d3 = d1 / d2;
+
+ return Math.Acos(d3);
+ }
+ private static Double ApproxTransit(Double Ht, Double lw, Double n) => 0.0009 + (Ht + lw) / (2 * Math.PI) + n;
+
+ private static Double JulianCycle(Double d, Double lw) => Math.Round(d - 0.0009 - lw / (2 * Math.PI));
+
+ //Returns Time of specified event based on suns angle
+ private static Double GetTime(Double h, Double lw, Double phi, Double dec, Double n, Double M, Double L) {
+ Double approxTime = HourAngle(h, phi, dec); //Ch15 Formula 15.1
+
+ Double a = ApproxTransit(approxTime, lw, n);
+ Double st = SolarTransitJ(a, M, L);
+
+ return st;
+ }
+ private static Double Declination(Double l, Double b) {
+ Double e = Math.PI / 180 * 23.4392911; // obliquity of the Earth
+
+ return Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));
+ }
+
+ private static void CalculateSunAngle(DateTime date, Double longi, Double lat, Celestial c) {
+ TimeSpan ts = date - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ Double dms = ts.TotalMilliseconds / dayMS - .5 + j1970 - j2000;
+
+ Double lw = rad * -longi;
+ Double phi = rad * lat;
+ //Double e = rad * 23.4397;
+
+ Double[] sc = SunCoords(dms);
+
+ Double H = SideRealTime(dms, lw) - sc[1];
+
+ c.sunAzimuth = Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(sc[0]) * Math.Cos(phi)) * 180 / Math.PI + 180;
+ c.sunAltitude = Math.Asin(Math.Sin(phi) * Math.Sin(sc[0]) + Math.Cos(phi) * Math.Cos(sc[0]) * Math.Cos(H)) * 180 / Math.PI;
+ }
+
+ private static Double SolarMeanAnomaly(Double d) => rad * (357.5291 + 0.98560028 * d);
+
+ private static Double EclipticLongitude(Double m) {
+ Double c = rad * (1.9148 * Math.Sin(m) + 0.02 * Math.Sin(2 * m) + 0.0003 * Math.Sin(3 * m)); // equation of center
+ Double p = rad * 102.9372; // perihelion of the Earth
+
+ return m + c + p + Math.PI;
+ }
+ private static Double[] SunCoords(Double d) {
+
+ Double m = SolarMeanAnomaly(d);
+ Double l = EclipticLongitude(m);
+ Double[] sc = new Double[2];
+ Double b = 0;
+ Double e = rad * 23.4397; // obliquity of the Earth
+ sc[0] = Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l)); //declination
+ sc[1] = Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l)); //rightAscension
+ return sc;
+ }
+ #endregion
+
+ }
}
diff --git a/CoordinateSharp/Celestial.cs b/CoordinateSharp/Celestial.cs
index a7f2d90..5bdf65b 100644
--- a/CoordinateSharp/Celestial.cs
+++ b/CoordinateSharp/Celestial.cs
@@ -1,620 +1,520 @@
using System;
-using System.ComponentModel;
using System.Collections.Generic;
-namespace CoordinateSharp
-{
+
+namespace CoordinateSharp {
+ ///
+ /// The main class for handling location based celestial information.
+ ///
+ ///
+ /// This class can calculate various pieces of solar and lunar data, based on location and date
+ ///
+ [Serializable]
+ public class Celestial {
+
+ //When a rise or a set does not occur, the DateTime will return null
+
///
- /// The main class for handling location based celestial information.
+ /// Creates an empty Celestial.
///
- ///
- /// This class can calculate various pieces of solar and lunar data, based on location and date
- ///
- [Serializable]
- public class Celestial
- {
-
- //When a rise or a set does not occur, the DateTime will return null
-
- ///
- /// Creates an empty Celestial.
- ///
- public Celestial()
- {
- astrologicalSigns = new AstrologicalSigns();
- lunarEclipse = new LunarEclipse();
- solarEclipse = new SolarEclipse();
- CalculateCelestialTime(0, 0, new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc));
- }
-
- private Celestial(bool hasCalcs)
- {
-
- astrologicalSigns = new AstrologicalSigns();
- lunarEclipse = new LunarEclipse();
- solarEclipse = new SolarEclipse();
- if (hasCalcs) { CalculateCelestialTime(0, 0, new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)); }
- }
-
- ///
- /// Creates a Celestial based on a location and specified date
- ///
- /// latitude
- /// longitude
- /// DateTime (UTC)
- public Celestial(double lat, double longi, DateTime geoDate)
- {
- DateTime d = new DateTime(geoDate.Year, geoDate.Month, geoDate.Day, geoDate.Hour, geoDate.Minute, geoDate.Second, DateTimeKind.Utc);
- astrologicalSigns = new AstrologicalSigns();
- lunarEclipse = new LunarEclipse();
- solarEclipse = new SolarEclipse();
- CalculateCelestialTime(lat, longi, d);
- }
-
- ///
- /// Creates a Celestial based on a location and date in the provided Coordinate.
- ///
- /// Coordinate
- /// Celestial
- public static Celestial LoadCelestial(Coordinate c)
- {
- DateTime geoDate = c.GeoDate;
-
- DateTime d = new DateTime(geoDate.Year, geoDate.Month, geoDate.Day, geoDate.Hour, geoDate.Minute, geoDate.Second, DateTimeKind.Utc);
- Celestial cel = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate);
-
- return cel;
- }
-
- ///
- /// Converts Celestial values to local times.
- ///
- /// Coordinate
- /// UTC offset
- ///
- public static Celestial Celestial_LocalTime(Coordinate c, double offset)
- {
- if(offset < -12 || offset > 12) { throw new ArgumentOutOfRangeException("Time offsets cannot be greater 12 or less than -12."); }
- //Probably need to offset initial UTC date so user can op in local
- //Determine best way to do this.
- DateTime d = c.GeoDate.AddHours(offset);
-
- //Get 3 objects for comparison
- Celestial cel = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate);
- Celestial celPre = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate.AddDays(-1));
- Celestial celPost = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate.AddDays(1));
-
- //Slip objects for comparison. Compare with slipped date.
- celPre.Local_Convert(c, offset);
- cel.Local_Convert(c, offset);
- celPost.Local_Convert(c, offset);
-
- //Get SunSet
- int i = Determine_Slipped_Event_Index(cel.SunSet, celPre.SunSet, celPost.SunSet, d);
- cel.sunSet = Get_Correct_Slipped_Date(cel.SunSet, celPre.SunSet, celPost.SunSet, i);
- cel.AdditionalSolarTimes.CivilDusk = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.CivilDusk,
- celPre.AdditionalSolarTimes.CivilDusk, celPost.AdditionalSolarTimes.CivilDusk, i);
- cel.AdditionalSolarTimes.NauticalDusk = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.NauticalDusk,
- celPre.AdditionalSolarTimes.NauticalDusk, celPost.AdditionalSolarTimes.NauticalDusk, i);
- //Get SunRise
- i = Determine_Slipped_Event_Index(cel.SunRise, celPre.SunRise, celPost.SunRise, d);
- cel.sunRise = Get_Correct_Slipped_Date(cel.SunRise, celPre.SunRise, celPost.SunRise, i);
- cel.AdditionalSolarTimes.CivilDawn = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.CivilDawn,
- celPre.AdditionalSolarTimes.CivilDawn, celPost.AdditionalSolarTimes.CivilDawn, i);
- cel.AdditionalSolarTimes.NauticalDawn = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.NauticalDawn,
- celPre.AdditionalSolarTimes.NauticalDawn, celPost.AdditionalSolarTimes.NauticalDawn, i);
-
- //MoonRise
- i = Determine_Slipped_Event_Index(cel.MoonRise, celPre.MoonRise, celPost.MoonRise, d);
- cel.moonRise = Get_Correct_Slipped_Date(cel.MoonRise, celPre.MoonRise, celPost.MoonRise, i);
-
- //MoonSet
- i = Determine_Slipped_Event_Index(cel.MoonSet, celPre.MoonSet, celPost.MoonSet, d);
- cel.moonSet = Get_Correct_Slipped_Date(cel.MoonSet, celPre.MoonSet, celPost.MoonSet, i);
-
- //Local Conditions
- CelestialStatus[] cels = new CelestialStatus[]
- {
- celPre.MoonCondition,cel.MoonCondition,celPost.MoonCondition
- };
- cel.moonCondition = Celestial.GetStatus(cel.MoonRise, cel.MoonSet, cels);
- cels = new CelestialStatus[]
- {
- celPre.SunCondition, cel.SunCondition, celPost.SunCondition
- };
- cel.sunCondition = Celestial.GetStatus(cel.SunRise, cel.SunSet, cels);
-
- //Load IsUp values based on local time with populated Celestial
- Celestial.Calculate_Celestial_IsUp_Booleans(d, cel);
-
- return cel;
- }
-
- private static CelestialStatus GetStatus(DateTime? rise, DateTime? set, CelestialStatus[] cels)
- {
- if (set.HasValue && rise.HasValue) { return CelestialStatus.RiseAndSet; }
- if (set.HasValue && !rise.HasValue) { return CelestialStatus.NoRise; }
- if (!set.HasValue && rise.HasValue) { return CelestialStatus.NoSet; }
- for (int x=0; x < 3;x++)
- {
- if(cels[x] == CelestialStatus.DownAllDay || cels[x] == CelestialStatus.UpAllDay)
- {
- return cels[x];
- }
- }
- return cels[1];
- }
-
- ///
- /// In place time slip
- ///
- /// Coordinate
- /// hour offset
- private void Local_Convert(Coordinate c, double offset)
- {
- //Find new lunar set rise times
- if (MoonSet.HasValue) { moonSet = moonSet.Value.AddHours(offset); }
- if (MoonRise.HasValue) { moonRise = moonRise.Value.AddHours(offset); }
- //Perigee
- Perigee.ConvertTo_Local_Time(offset);
- //Apogee
- Apogee.ConvertTo_Local_Time(offset);
- //Eclipse
- LunarEclipse.ConvertTo_LocalTime(offset);
-
- ////Solar
- if (sunSet.HasValue) { sunSet = sunSet.Value.AddHours(offset); }
- if (SunRise.HasValue) { sunRise = SunRise.Value.AddHours(offset); }
- AdditionalSolarTimes.Convert_To_Local_Time(offset);
-
- //Eclipse
- SolarEclipse.ConvertTo_LocalTime(offset);
- SunCalc.CalculateZodiacSign(c.GeoDate.AddHours(offset), this);
- MoonCalc.GetMoonSign(c.GeoDate.AddHours(offset), this);
-
- }
-
- private PerigeeApogee Get_Correct_Slipped_Date(PerigeeApogee actual, PerigeeApogee pre, PerigeeApogee post, int i)
- {
- switch (i)
- {
- case 0:
- return pre;
- case 1:
- return actual;
- case 2:
- return post;
- default:
- return actual;
- }
- }
- private static DateTime? Get_Correct_Slipped_Date(DateTime? actual, DateTime? pre, DateTime? post, int i)
- {
- switch(i)
- {
- case 0:
- return pre;
- case 1:
- return actual;
- case 2:
- return post;
- default:
- return null;
- }
- }
- private static int Determine_Slipped_Event_Index(DateTime? actual, DateTime? pre, DateTime? post, DateTime d)
- {
-
- if (actual.HasValue)
- {
- if (actual.Value.Day != d.Day)
- {
- if (pre.HasValue)
- {
- if (pre.Value.Day == d.Day) { return 0; }
- }
- if (post.HasValue)
- {
- if (post.Value.Day == d.Day) { return 2; }
- }
- return 3;
- }
- }
- else
- {
- if (pre.HasValue)
- {
- if (pre.Value.Day == d.Day) { return 0; }
- }
- if (post.HasValue)
- {
- if (post.Value.Day == d.Day) { return 2; }
- }
- }
- return 1;
- }
-
- internal DateTime? sunSet;
- internal DateTime? sunRise;
- internal DateTime? moonSet;
- internal DateTime? moonRise;
-
- internal double sunAltitude;
- internal double sunAzimuth;
- internal double moonAltitude;
- internal double moonAzimuth;
-
- internal Distance moonDistance;
-
- internal CelestialStatus sunCondition;
- internal CelestialStatus moonCondition;
-
- internal bool isSunUp;
- internal bool isMoonUp;
-
- internal MoonIllum moonIllum;
- internal Perigee perigee;
- internal Apogee apogee;
- internal AdditionalSolarTimes additionalSolarTimes;
- internal AstrologicalSigns astrologicalSigns;
- internal SolarEclipse solarEclipse;
- internal LunarEclipse lunarEclipse;
-
- ///
- /// Sunset time.
- ///
- public DateTime? SunSet { get { return sunSet; } }
- ///
- /// Sunrise time.
- ///
- public DateTime? SunRise { get { return sunRise; } }
- ///
- /// Moonset time.
- ///
- public DateTime? MoonSet { get { return moonSet; } }
- ///
- /// Moonrise time.
- ///
- public DateTime? MoonRise { get { return moonRise; } }
-
- ///
- /// Sun altitude in degrees (E of N).
- ///
- public double SunAltitude { get { return sunAltitude; } }
- ///
- /// Sun azimuth in degrees (E of N).
- ///
- public double SunAzimuth { get { return sunAzimuth; } }
- ///
- /// Moon altitude in degrees (corrected for parallax and refraction).
- ///
- public double MoonAltitude { get { return moonAltitude; } }
- ///
- /// Moon azimuth in degrees (E of N).
- ///
- public double MoonAzimuth { get { return moonAzimuth; } }
-
- ///
- /// Estimated moon distance from the earth.
- ///
- public Distance MoonDistance { get { return moonDistance; } }
- ///
- /// Sun's Condition based on the provided date.
- ///
- public CelestialStatus SunCondition { get { return sunCondition; } }
- ///
- /// Moon's condition based on the provided date.
- ///
- public CelestialStatus MoonCondition { get { return moonCondition; } }
-
- ///
- /// Determine if the sun is currently up, based on sunset and sunrise time at the provided location and date.
- ///
- public bool IsSunUp{ get { return isSunUp; } }
-
- ///
- /// Determine if the moon is currently up, based on moonset and moonrise time at the provided location and date.
- ///
- public bool IsMoonUp { get { return isMoonUp; } }
-
- ///
- /// Moon ilumination details based on the provided date.
- ///
- ///
- /// Contains phase, phase name, fraction and angle
- ///
- public MoonIllum MoonIllum { get { return moonIllum; } }
- ///
- /// Moons perigee details based on the provided date.
- ///
- public Perigee Perigee { get { return perigee; } }
- ///
- /// Moons apogee details based on the provided date.
- ///
- public Apogee Apogee { get { return apogee; } }
-
- ///
- /// Additional solar event times based on the provided date and location.
- ///
- /// Contains civil and nautical dawn and dusk times.
- public AdditionalSolarTimes AdditionalSolarTimes { get { return additionalSolarTimes; } }
- ///
- /// Astrological signs based on the provided date.
- ///
- ///
- /// Contains zodiac, moon sign and moon name during full moon events
- ///
- public AstrologicalSigns AstrologicalSigns { get { return astrologicalSigns; } }
-
- ///
- /// Returns a SolarEclipse.
- ///
- public SolarEclipse SolarEclipse { get { return solarEclipse; } }
- ///
- /// Returns a LunarEclipse.
- ///
- public LunarEclipse LunarEclipse { get { return lunarEclipse; } }
-
- ///
- /// Calculates all celestial data. Coordinates will notify as changes occur
- ///
- /// Decimal format latitude
- /// Decimal format longitude
- /// Geographic DateTime
- internal void CalculateCelestialTime(double lat, double longi, DateTime date)
- {
- date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
- SunCalc.CalculateSunTime(lat, longi, date, this);
- MoonCalc.GetMoonTimes(date, lat, longi, this);
- MoonCalc.GetMoonDistance(date, this);
-
- SunCalc.CalculateZodiacSign(date, this);
- MoonCalc.GetMoonSign(date, this);
-
- MoonCalc.GetMoonIllumination(date, this,lat,longi);
-
-
- perigee = MoonCalc.GetPerigeeEvents(date);
- apogee = MoonCalc.GetApogeeEvents(date);
-
- Calculate_Celestial_IsUp_Booleans(date, this);
-
- }
- ///
- /// Calculate celestial data based on lat/long and date.
- ///
- /// Decimal format latitude
- /// Decimal format longitude
- /// Geographic DateTime
- /// Fully populated Celestial object
- public static Celestial CalculateCelestialTimes(double lat, double longi, DateTime date)
- {
- date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
-
- Celestial c = new Celestial(false);
-
- SunCalc.CalculateSunTime(lat, longi, date, c);
- MoonCalc.GetMoonTimes(date, lat, longi, c);
- MoonCalc.GetMoonDistance(date, c);
- SunCalc.CalculateZodiacSign(date, c);
- MoonCalc.GetMoonSign(date, c);
- MoonCalc.GetMoonIllumination(date, c,lat,longi);
-
- c.perigee = MoonCalc.GetPerigeeEvents(date);
- c.apogee = MoonCalc.GetApogeeEvents(date);
-
- Calculate_Celestial_IsUp_Booleans(date, c);
-
- return c;
- }
-
- ///
- /// Calculate sun data based on lat/long and date.
- ///
- /// latitude
- /// longitude
- /// DateTime
- /// Celestial (Partially Populated)
- public static Celestial CalculateSunData(double lat, double longi, DateTime date)
- {
- date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
-
- Celestial c = new Celestial(false);
- SunCalc.CalculateSunTime(lat, longi, date, c);
- SunCalc.CalculateZodiacSign(date, c);
-
- return c;
- }
- ///
- /// Calculate moon data based on lat/long and date.
- ///
- /// latitude
- /// longitude
- /// DateTime
- /// Celestial (Partially Populated)
- public static Celestial CalculateMoonData(double lat, double longi, DateTime date)
- {
- date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
-
- Celestial c = new Celestial(false);
-
- MoonCalc.GetMoonTimes(date, lat, longi, c);
- MoonCalc.GetMoonDistance(date, c);
- MoonCalc.GetMoonSign(date, c);
- MoonCalc.GetMoonIllumination(date, c,lat,longi);
-
- c.perigee = MoonCalc.GetPerigeeEvents(date);
- c.apogee = MoonCalc.GetApogeeEvents(date);
-
- return c;
- }
-
- ///
- /// Returns a List containing solar eclipse data for the century.
- /// Century return is based on the date passed.
- ///
- /// latitude
- /// longitude
- /// DateTime
- ///
- public static List Get_Solar_Eclipse_Table(double lat, double longi, DateTime date)
- {
- //Convert to Radians
- double latR = lat * Math.PI / 180;
- double longR = longi * Math.PI / 180;
- //Get solar data based on date
- double[] events = Eclipse.SolarData.SolarDateData_100Year(date);
- //Return list of solar data.
- return SolarEclipseCalc.CalculateSolarEclipse(date, latR, longR, events);
- }
- ///
- /// Returns a List containing solar eclipse data for the century.
- /// Century return is based on the date passed.
- ///
- /// latitude
- /// longitude
- /// DateTime
- ///
- public static List Get_Lunar_Eclipse_Table(double lat, double longi, DateTime date)
- {
- //Convert to Radians
- double latR = lat * Math.PI / 180;
- double longR = longi * Math.PI / 180;
- //Get solar data based on date
- double[] events = Eclipse.LunarData.LunarDateData_100Year(date);
- //Return list of solar data.
- return LunarEclipseCalc.CalculateLunarEclipse(date, latR, longR, events);
- }
-
- ///
- /// Set bool SunIsUp and MoonIsUp values
- ///
- /// Coordinate GeoDate
- /// Celestial Object
- private static void Calculate_Celestial_IsUp_Booleans(DateTime date, Celestial cel)
- {
- //SUN
- switch (cel.SunCondition)
- {
- case CelestialStatus.DownAllDay:
- cel.isSunUp = false;
- break;
- case CelestialStatus.UpAllDay:
- cel.isSunUp = true;
- break;
- case CelestialStatus.NoRise:
- if(date cel.SunRise)
- {
- cel.isSunUp = true;
- }
- else { cel.isSunUp = false; }
- break;
- case CelestialStatus.RiseAndSet:
- if (cel.SunRise < cel.SunSet)
- {
- if (date > cel.SunRise && date < cel.SunSet)
- {
- cel.isSunUp = true;
- }
- else
- {
- cel.isSunUp = false;
- }
- }
- else
- {
- if (date > cel.SunRise || date < cel.SunSet)
- {
- cel.isSunUp = true;
- }
- else
- {
- cel.isSunUp = false;
- }
- }
- break;
- default:
- //Should never be reached. If reached, previous calculations failed somewhere.
- break;
- }
-
- //MOON
- switch (cel.MoonCondition)
- {
- case CelestialStatus.DownAllDay:
- cel.isMoonUp = false;
- break;
- case CelestialStatus.UpAllDay:
- cel.isMoonUp = true;
- break;
- case CelestialStatus.NoRise:
- if (date < cel.MoonSet)
- {
- cel.isMoonUp = true;
- }
- else { cel.isMoonUp = false; }
- break;
- case CelestialStatus.NoSet:
- if (date > cel.MoonRise)
- {
- cel.isMoonUp = true;
- }
- else { cel.isMoonUp = false; }
- break;
- case CelestialStatus.RiseAndSet:
- if (cel.MoonRise < cel.MoonSet)
- {
- if (date > cel.MoonRise && date < cel.MoonSet)
- {
- cel.isMoonUp = true;
- }
- else
- {
- cel.isMoonUp = false;
- }
- }
- else
- {
- if (date > cel.MoonRise || date < cel.MoonSet)
- {
- cel.isMoonUp = true;
- }
- else
- {
- cel.isMoonUp = false;
- }
- }
- break;
- default:
- //Should never be reached. If reached, previous calculations failed somewhere.
- break;
- }
- }
-
- ///
- /// Returns Apogee object containing last and next apogee based on the specified date.
- ///
- /// DateTime
- /// Apogee
- public static Apogee GetApogees(DateTime d)
- {
- return MoonCalc.GetApogeeEvents(d);
- }
- ///
- /// Returns Perigee object containing last and next perigee based on the specified date.
- ///
- /// DateTime
- /// Perigee
- public static Perigee GetPerigees(DateTime d)
- {
- return MoonCalc.GetPerigeeEvents(d);
- }
+ public Celestial() {
+ this.astrologicalSigns = new AstrologicalSigns();
+ this.lunarEclipse = new LunarEclipse();
+ this.solarEclipse = new SolarEclipse();
+ this.CalculateCelestialTime(0, 0, new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc));
}
+ private Celestial(Boolean hasCalcs) {
+
+ this.astrologicalSigns = new AstrologicalSigns();
+ this.lunarEclipse = new LunarEclipse();
+ this.solarEclipse = new SolarEclipse();
+ if (hasCalcs) { this.CalculateCelestialTime(0, 0, new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)); }
+ }
+
+ ///
+ /// Creates a Celestial based on a location and specified date
+ ///
+ /// latitude
+ /// longitude
+ /// DateTime (UTC)
+ public Celestial(Double lat, Double longi, DateTime geoDate) {
+ DateTime d = new DateTime(geoDate.Year, geoDate.Month, geoDate.Day, geoDate.Hour, geoDate.Minute, geoDate.Second, DateTimeKind.Utc);
+ this.astrologicalSigns = new AstrologicalSigns();
+ this.lunarEclipse = new LunarEclipse();
+ this.solarEclipse = new SolarEclipse();
+ this.CalculateCelestialTime(lat, longi, d);
+ }
+
+ ///
+ /// Creates a Celestial based on a location and date in the provided Coordinate.
+ ///
+ /// Coordinate
+ /// Celestial
+ public static Celestial LoadCelestial(Coordinate c) {
+ //DateTime geoDate = c.GeoDate;
+
+ //DateTime d = new DateTime(geoDate.Year, geoDate.Month, geoDate.Day, geoDate.Hour, geoDate.Minute, geoDate.Second, DateTimeKind.Utc);
+ Celestial cel = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate);
+
+ return cel;
+ }
+
+ ///
+ /// Converts Celestial values to local times.
+ ///
+ /// Coordinate
+ /// UTC offset
+ ///
+ public static Celestial Celestial_LocalTime(Coordinate c, Double offset) {
+ if (offset < -12 || offset > 12) { throw new ArgumentOutOfRangeException("Time offsets cannot be greater 12 or less than -12."); }
+ //Probably need to offset initial UTC date so user can op in local
+ //Determine best way to do this.
+ DateTime d = c.GeoDate.AddHours(offset);
+
+ //Get 3 objects for comparison
+ Celestial cel = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate);
+ Celestial celPre = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate.AddDays(-1));
+ Celestial celPost = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate.AddDays(1));
+
+ //Slip objects for comparison. Compare with slipped date.
+ celPre.Local_Convert(c, offset);
+ cel.Local_Convert(c, offset);
+ celPost.Local_Convert(c, offset);
+
+ //Get SunSet
+ Int32 i = Determine_Slipped_Event_Index(cel.SunSet, celPre.SunSet, celPost.SunSet, d);
+ cel.sunSet = Get_Correct_Slipped_Date(cel.SunSet, celPre.SunSet, celPost.SunSet, i);
+ cel.AdditionalSolarTimes.CivilDusk = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.CivilDusk,
+ celPre.AdditionalSolarTimes.CivilDusk, celPost.AdditionalSolarTimes.CivilDusk, i);
+ cel.AdditionalSolarTimes.NauticalDusk = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.NauticalDusk,
+ celPre.AdditionalSolarTimes.NauticalDusk, celPost.AdditionalSolarTimes.NauticalDusk, i);
+ //Get SunRise
+ i = Determine_Slipped_Event_Index(cel.SunRise, celPre.SunRise, celPost.SunRise, d);
+ cel.sunRise = Get_Correct_Slipped_Date(cel.SunRise, celPre.SunRise, celPost.SunRise, i);
+ cel.AdditionalSolarTimes.CivilDawn = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.CivilDawn,
+ celPre.AdditionalSolarTimes.CivilDawn, celPost.AdditionalSolarTimes.CivilDawn, i);
+ cel.AdditionalSolarTimes.NauticalDawn = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.NauticalDawn,
+ celPre.AdditionalSolarTimes.NauticalDawn, celPost.AdditionalSolarTimes.NauticalDawn, i);
+
+ //MoonRise
+ i = Determine_Slipped_Event_Index(cel.MoonRise, celPre.MoonRise, celPost.MoonRise, d);
+ cel.moonRise = Get_Correct_Slipped_Date(cel.MoonRise, celPre.MoonRise, celPost.MoonRise, i);
+
+ //MoonSet
+ i = Determine_Slipped_Event_Index(cel.MoonSet, celPre.MoonSet, celPost.MoonSet, d);
+ cel.moonSet = Get_Correct_Slipped_Date(cel.MoonSet, celPre.MoonSet, celPost.MoonSet, i);
+
+ //Local Conditions
+ CelestialStatus[] cels = new CelestialStatus[]
+ {
+ celPre.MoonCondition,cel.MoonCondition,celPost.MoonCondition
+ };
+ cel.moonCondition = Celestial.GetStatus(cel.MoonRise, cel.MoonSet, cels);
+ cels = new CelestialStatus[]
+ {
+ celPre.SunCondition, cel.SunCondition, celPost.SunCondition
+ };
+ cel.sunCondition = Celestial.GetStatus(cel.SunRise, cel.SunSet, cels);
+
+ //Load IsUp values based on local time with populated Celestial
+ Celestial.Calculate_Celestial_IsUp_Booleans(d, cel);
+
+ return cel;
+ }
+
+ private static CelestialStatus GetStatus(DateTime? rise, DateTime? set, CelestialStatus[] cels) {
+ if (set.HasValue && rise.HasValue) { return CelestialStatus.RiseAndSet; }
+ if (set.HasValue && !rise.HasValue) { return CelestialStatus.NoRise; }
+ if (!set.HasValue && rise.HasValue) { return CelestialStatus.NoSet; }
+ for (Int32 x = 0; x < 3; x++) {
+ if (cels[x] == CelestialStatus.DownAllDay || cels[x] == CelestialStatus.UpAllDay) {
+ return cels[x];
+ }
+ }
+ return cels[1];
+ }
+
+ ///
+ /// In place time slip
+ ///
+ /// Coordinate
+ /// hour offset
+ private void Local_Convert(Coordinate c, Double offset) {
+ //Find new lunar set rise times
+ if (this.MoonSet.HasValue) { this.moonSet = this.moonSet.Value.AddHours(offset); }
+ if (this.MoonRise.HasValue) { this.moonRise = this.moonRise.Value.AddHours(offset); }
+ //Perigee
+ this.Perigee.ConvertTo_Local_Time(offset);
+ //Apogee
+ this.Apogee.ConvertTo_Local_Time(offset);
+ //Eclipse
+ this.LunarEclipse.ConvertTo_LocalTime(offset);
+
+ ////Solar
+ if (this.sunSet.HasValue) { this.sunSet = this.sunSet.Value.AddHours(offset); }
+ if (this.SunRise.HasValue) { this.sunRise = this.SunRise.Value.AddHours(offset); }
+ this.AdditionalSolarTimes.Convert_To_Local_Time(offset);
+
+ //Eclipse
+ this.SolarEclipse.ConvertTo_LocalTime(offset);
+ SunCalc.CalculateZodiacSign(c.GeoDate.AddHours(offset), this);
+ MoonCalc.GetMoonSign(c.GeoDate.AddHours(offset), this);
+
+ }
+
+ /*private PerigeeApogee Get_Correct_Slipped_Date(PerigeeApogee actual, PerigeeApogee pre, PerigeeApogee post, Int32 i)
+ {
+ switch (i)
+ {
+ case 0:
+ return pre;
+ case 1:
+ return actual;
+ case 2:
+ return post;
+ default:
+ return actual;
+ }
+ }*/
+ private static DateTime? Get_Correct_Slipped_Date(DateTime? actual, DateTime? pre, DateTime? post, Int32 i) => i switch
+ {
+ 0 => pre,
+ 1 => actual,
+ 2 => post,
+ _ => null,
+ };
+ private static Int32 Determine_Slipped_Event_Index(DateTime? actual, DateTime? pre, DateTime? post, DateTime d) {
+
+ if (actual.HasValue) {
+ if (actual.Value.Day != d.Day) {
+ if (pre.HasValue) {
+ if (pre.Value.Day == d.Day) { return 0; }
+ }
+ if (post.HasValue) {
+ if (post.Value.Day == d.Day) { return 2; }
+ }
+ return 3;
+ }
+ } else {
+ if (pre.HasValue) {
+ if (pre.Value.Day == d.Day) { return 0; }
+ }
+ if (post.HasValue) {
+ if (post.Value.Day == d.Day) { return 2; }
+ }
+ }
+ return 1;
+ }
+
+ internal DateTime? sunSet;
+ internal DateTime? sunRise;
+ internal DateTime? moonSet;
+ internal DateTime? moonRise;
+
+ internal Double sunAltitude;
+ internal Double sunAzimuth;
+ internal Double moonAltitude;
+ internal Double moonAzimuth;
+
+ internal Distance moonDistance;
+
+ internal CelestialStatus sunCondition;
+ internal CelestialStatus moonCondition;
+
+ internal Boolean isSunUp;
+ internal Boolean isMoonUp;
+
+ internal MoonIllum moonIllum;
+ internal Perigee perigee;
+ internal Apogee apogee;
+ internal AdditionalSolarTimes additionalSolarTimes;
+ internal AstrologicalSigns astrologicalSigns;
+ internal SolarEclipse solarEclipse;
+ internal LunarEclipse lunarEclipse;
+
+ ///
+ /// Sunset time.
+ ///
+ public DateTime? SunSet => this.sunSet;
+ ///
+ /// Sunrise time.
+ ///
+ public DateTime? SunRise => this.sunRise;
+ ///
+ /// Moonset time.
+ ///
+ public DateTime? MoonSet => this.moonSet;
+ ///
+ /// Moonrise time.
+ ///
+ public DateTime? MoonRise => this.moonRise;
+
+ ///
+ /// Sun altitude in degrees (E of N).
+ ///
+ public Double SunAltitude => this.sunAltitude;
+ ///
+ /// Sun azimuth in degrees (E of N).
+ ///
+ public Double SunAzimuth => this.sunAzimuth;
+ ///
+ /// Moon altitude in degrees (corrected for parallax and refraction).
+ ///
+ public Double MoonAltitude => this.moonAltitude;
+ ///
+ /// Moon azimuth in degrees (E of N).
+ ///
+ public Double MoonAzimuth => this.moonAzimuth;
+
+ ///
+ /// Estimated moon distance from the earth.
+ ///
+ public Distance MoonDistance => this.moonDistance;
+ ///
+ /// Sun's Condition based on the provided date.
+ ///
+ public CelestialStatus SunCondition => this.sunCondition;
+ ///
+ /// Moon's condition based on the provided date.
+ ///
+ public CelestialStatus MoonCondition => this.moonCondition;
+
+ ///
+ /// Determine if the sun is currently up, based on sunset and sunrise time at the provided location and date.
+ ///
+ public Boolean IsSunUp => this.isSunUp;
+
+ ///
+ /// Determine if the moon is currently up, based on moonset and moonrise time at the provided location and date.
+ ///
+ public Boolean IsMoonUp => this.isMoonUp;
+
+ ///
+ /// Moon ilumination details based on the provided date.
+ ///
+ ///
+ /// Contains phase, phase name, fraction and angle
+ ///
+ public MoonIllum MoonIllum => this.moonIllum;
+ ///
+ /// Moons perigee details based on the provided date.
+ ///
+ public Perigee Perigee => this.perigee;
+ ///
+ /// Moons apogee details based on the provided date.
+ ///
+ public Apogee Apogee => this.apogee;
+
+ ///
+ /// Additional solar event times based on the provided date and location.
+ ///
+ /// Contains civil and nautical dawn and dusk times.
+ public AdditionalSolarTimes AdditionalSolarTimes => this.additionalSolarTimes;
+ ///
+ /// Astrological signs based on the provided date.
+ ///
+ ///
+ /// Contains zodiac, moon sign and moon name during full moon events
+ ///
+ public AstrologicalSigns AstrologicalSigns => this.astrologicalSigns;
+
+ ///
+ /// Returns a SolarEclipse.
+ ///
+ public SolarEclipse SolarEclipse => this.solarEclipse;
+ ///
+ /// Returns a LunarEclipse.
+ ///
+ public LunarEclipse LunarEclipse => this.lunarEclipse;
+
+ ///
+ /// Calculates all celestial data. Coordinates will notify as changes occur
+ ///
+ /// Decimal format latitude
+ /// Decimal format longitude
+ /// Geographic DateTime
+ internal void CalculateCelestialTime(Double lat, Double longi, DateTime date) {
+ date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
+ SunCalc.CalculateSunTime(lat, longi, date, this);
+ MoonCalc.GetMoonTimes(date, lat, longi, this);
+ MoonCalc.GetMoonDistance(date, this);
+
+ SunCalc.CalculateZodiacSign(date, this);
+ MoonCalc.GetMoonSign(date, this);
+
+ MoonCalc.GetMoonIllumination(date, this, lat, longi);
+
+
+ this.perigee = MoonCalc.GetPerigeeEvents(date);
+ this.apogee = MoonCalc.GetApogeeEvents(date);
+
+ Calculate_Celestial_IsUp_Booleans(date, this);
+
+ }
+ ///
+ /// Calculate celestial data based on lat/long and date.
+ ///
+ /// Decimal format latitude
+ /// Decimal format longitude
+ /// Geographic DateTime
+ /// Fully populated Celestial object
+ public static Celestial CalculateCelestialTimes(Double lat, Double longi, DateTime date) {
+ date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
+
+ Celestial c = new Celestial(false);
+
+ SunCalc.CalculateSunTime(lat, longi, date, c);
+ MoonCalc.GetMoonTimes(date, lat, longi, c);
+ MoonCalc.GetMoonDistance(date, c);
+ SunCalc.CalculateZodiacSign(date, c);
+ MoonCalc.GetMoonSign(date, c);
+ MoonCalc.GetMoonIllumination(date, c, lat, longi);
+
+ c.perigee = MoonCalc.GetPerigeeEvents(date);
+ c.apogee = MoonCalc.GetApogeeEvents(date);
+
+ Calculate_Celestial_IsUp_Booleans(date, c);
+
+ return c;
+ }
+
+ ///
+ /// Calculate sun data based on lat/long and date.
+ ///
+ /// latitude
+ /// longitude
+ /// DateTime
+ /// Celestial (Partially Populated)
+ public static Celestial CalculateSunData(Double lat, Double longi, DateTime date) {
+ date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
+
+ Celestial c = new Celestial(false);
+ SunCalc.CalculateSunTime(lat, longi, date, c);
+ SunCalc.CalculateZodiacSign(date, c);
+
+ return c;
+ }
+ ///
+ /// Calculate moon data based on lat/long and date.
+ ///
+ /// latitude
+ /// longitude
+ /// DateTime
+ /// Celestial (Partially Populated)
+ public static Celestial CalculateMoonData(Double lat, Double longi, DateTime date) {
+ date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
+
+ Celestial c = new Celestial(false);
+
+ MoonCalc.GetMoonTimes(date, lat, longi, c);
+ MoonCalc.GetMoonDistance(date, c);
+ MoonCalc.GetMoonSign(date, c);
+ MoonCalc.GetMoonIllumination(date, c, lat, longi);
+
+ c.perigee = MoonCalc.GetPerigeeEvents(date);
+ c.apogee = MoonCalc.GetApogeeEvents(date);
+
+ return c;
+ }
+
+ ///
+ /// Returns a List containing solar eclipse data for the century.
+ /// Century return is based on the date passed.
+ ///
+ /// latitude
+ /// longitude
+ /// DateTime
+ ///
+ public static List Get_Solar_Eclipse_Table(Double lat, Double longi, DateTime date) {
+ //Convert to Radians
+ Double latR = lat * Math.PI / 180;
+ Double longR = longi * Math.PI / 180;
+ //Get solar data based on date
+ Double[] events = Eclipse.SolarData.SolarDateData_100Year(date);
+ //Return list of solar data.
+ return SolarEclipseCalc.CalculateSolarEclipse(date, latR, longR, events);
+ }
+ ///
+ /// Returns a List containing solar eclipse data for the century.
+ /// Century return is based on the date passed.
+ ///
+ /// latitude
+ /// longitude
+ /// DateTime
+ ///
+ public static List Get_Lunar_Eclipse_Table(Double lat, Double longi, DateTime date) {
+ //Convert to Radians
+ Double latR = lat * Math.PI / 180;
+ Double longR = longi * Math.PI / 180;
+ //Get solar data based on date
+ Double[] events = Eclipse.LunarData.LunarDateData_100Year(date);
+ //Return list of solar data.
+ return LunarEclipseCalc.CalculateLunarEclipse(date, latR, longR, events);
+ }
+
+ ///
+ /// Set bool SunIsUp and MoonIsUp values
+ ///
+ /// Coordinate GeoDate
+ /// Celestial Object
+ private static void Calculate_Celestial_IsUp_Booleans(DateTime date, Celestial cel) {
+ //SUN
+ switch (cel.SunCondition) {
+ case CelestialStatus.DownAllDay:
+ cel.isSunUp = false;
+ break;
+ case CelestialStatus.UpAllDay:
+ cel.isSunUp = true;
+ break;
+ case CelestialStatus.NoRise:
+ cel.isSunUp = date < cel.SunSet;
+ break;
+ case CelestialStatus.NoSet:
+ cel.isSunUp = date > cel.SunRise;
+ break;
+ case CelestialStatus.RiseAndSet:
+ cel.isSunUp = cel.SunRise < cel.SunSet ? date > cel.SunRise && date < cel.SunSet : date > cel.SunRise || date < cel.SunSet;
+ break;
+ default:
+ //Should never be reached. If reached, previous calculations failed somewhere.
+ break;
+ }
+
+ //MOON
+ switch (cel.MoonCondition) {
+ case CelestialStatus.DownAllDay:
+ cel.isMoonUp = false;
+ break;
+ case CelestialStatus.UpAllDay:
+ cel.isMoonUp = true;
+ break;
+ case CelestialStatus.NoRise:
+ cel.isMoonUp = date < cel.MoonSet;
+ break;
+ case CelestialStatus.NoSet:
+ cel.isMoonUp = date > cel.MoonRise;
+ break;
+ case CelestialStatus.RiseAndSet:
+ cel.isMoonUp = cel.MoonRise < cel.MoonSet ? date > cel.MoonRise && date < cel.MoonSet : date > cel.MoonRise || date < cel.MoonSet;
+ break;
+ default:
+ //Should never be reached. If reached, previous calculations failed somewhere.
+ break;
+ }
+ }
+
+ ///
+ /// Returns Apogee object containing last and next apogee based on the specified date.
+ ///
+ /// DateTime
+ /// Apogee
+ public static Apogee GetApogees(DateTime d) => MoonCalc.GetApogeeEvents(d);
+ ///
+ /// Returns Perigee object containing last and next perigee based on the specified date.
+ ///
+ /// DateTime
+ /// Perigee
+ public static Perigee GetPerigees(DateTime d) => MoonCalc.GetPerigeeEvents(d);
+ }
+
}
diff --git a/CoordinateSharp/Coordinate.Assistant.cs b/CoordinateSharp/Coordinate.Assistant.cs
index d4f06ff..5bf1857 100644
--- a/CoordinateSharp/Coordinate.Assistant.cs
+++ b/CoordinateSharp/Coordinate.Assistant.cs
@@ -2,268 +2,233 @@
using System.Collections.Generic;
using System.Linq;
-namespace CoordinateSharp
-{
-
+namespace CoordinateSharp {
-
- ///
- /// Used for UTM/MGRS Conversions
- ///
- [Serializable]
- internal class LatZones
- {
- public static List longZongLetters = new List(new string[]{"C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
+
+
+ ///
+ /// Used for UTM/MGRS Conversions
+ ///
+ [Serializable]
+ internal class LatZones {
+ public static List longZongLetters = new List(new String[]{"C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
"U", "V", "W", "X"});
+ }
+ ///
+ /// Used for handling diagraph determination
+ ///
+ [Serializable]
+ internal class Digraphs {
+ private readonly List digraph1;
+ private readonly List digraph2;
+
+ private readonly String[] digraph1Array = { "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
+
+ private readonly String[] digraph2Array = { "V", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V" };
+
+ public Digraphs() {
+ this.digraph1 = new List();
+ this.digraph2 = new List();
+
+ this.digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
+ this.digraph1.Add(new Digraph() { Zone = 2, Letter = "B" });
+ this.digraph1.Add(new Digraph() { Zone = 3, Letter = "C" });
+ this.digraph1.Add(new Digraph() { Zone = 4, Letter = "D" });
+ this.digraph1.Add(new Digraph() { Zone = 5, Letter = "E" });
+ this.digraph1.Add(new Digraph() { Zone = 6, Letter = "F" });
+ this.digraph1.Add(new Digraph() { Zone = 7, Letter = "G" });
+ this.digraph1.Add(new Digraph() { Zone = 8, Letter = "H" });
+ this.digraph1.Add(new Digraph() { Zone = 9, Letter = "J" });
+ this.digraph1.Add(new Digraph() { Zone = 10, Letter = "K" });
+ this.digraph1.Add(new Digraph() { Zone = 11, Letter = "L" });
+ this.digraph1.Add(new Digraph() { Zone = 12, Letter = "M" });
+ this.digraph1.Add(new Digraph() { Zone = 13, Letter = "N" });
+ this.digraph1.Add(new Digraph() { Zone = 14, Letter = "P" });
+ this.digraph1.Add(new Digraph() { Zone = 15, Letter = "Q" });
+ this.digraph1.Add(new Digraph() { Zone = 16, Letter = "R" });
+ this.digraph1.Add(new Digraph() { Zone = 17, Letter = "S" });
+ this.digraph1.Add(new Digraph() { Zone = 18, Letter = "T" });
+ this.digraph1.Add(new Digraph() { Zone = 19, Letter = "U" });
+ this.digraph1.Add(new Digraph() { Zone = 20, Letter = "V" });
+ this.digraph1.Add(new Digraph() { Zone = 21, Letter = "W" });
+ this.digraph1.Add(new Digraph() { Zone = 22, Letter = "X" });
+ this.digraph1.Add(new Digraph() { Zone = 23, Letter = "Y" });
+ this.digraph1.Add(new Digraph() { Zone = 24, Letter = "Z" });
+ this.digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
+
+ this.digraph2.Add(new Digraph() { Zone = 0, Letter = "V" });
+ this.digraph2.Add(new Digraph() { Zone = 1, Letter = "A" });
+ this.digraph2.Add(new Digraph() { Zone = 2, Letter = "B" });
+ this.digraph2.Add(new Digraph() { Zone = 3, Letter = "C" });
+ this.digraph2.Add(new Digraph() { Zone = 4, Letter = "D" });
+ this.digraph2.Add(new Digraph() { Zone = 5, Letter = "E" });
+ this.digraph2.Add(new Digraph() { Zone = 6, Letter = "F" });
+ this.digraph2.Add(new Digraph() { Zone = 7, Letter = "G" });
+ this.digraph2.Add(new Digraph() { Zone = 8, Letter = "H" });
+ this.digraph2.Add(new Digraph() { Zone = 9, Letter = "J" });
+ this.digraph2.Add(new Digraph() { Zone = 10, Letter = "K" });
+ this.digraph2.Add(new Digraph() { Zone = 11, Letter = "L" });
+ this.digraph2.Add(new Digraph() { Zone = 12, Letter = "M" });
+ this.digraph2.Add(new Digraph() { Zone = 13, Letter = "N" });
+ this.digraph2.Add(new Digraph() { Zone = 14, Letter = "P" });
+ this.digraph2.Add(new Digraph() { Zone = 15, Letter = "Q" });
+ this.digraph2.Add(new Digraph() { Zone = 16, Letter = "R" });
+ this.digraph2.Add(new Digraph() { Zone = 17, Letter = "S" });
+ this.digraph2.Add(new Digraph() { Zone = 18, Letter = "T" });
+ this.digraph2.Add(new Digraph() { Zone = 19, Letter = "U" });
+ this.digraph2.Add(new Digraph() { Zone = 20, Letter = "V" });
}
+
+ internal Int32 GetDigraph1Index(String letter) {
+ for (Int32 i = 0; i < this.digraph1Array.Length; i++) {
+ if (this.digraph1Array[i].Equals(letter)) {
+ return i + 1;
+ }
+ }
+
+ return -1;
+ }
+
+ internal Int32 GetDigraph2Index(String letter) {
+ for (Int32 i = 0; i < this.digraph2Array.Length; i++) {
+ if (this.digraph2Array[i].Equals(letter)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ internal String GetDigraph1(Int32 longZone, Double easting) {
+ Int32 a1 = longZone;
+ Double a2 = 8 * ((a1 - 1) % 3) + 1;
+
+ Double a3 = easting;
+ Double a4 = a2 + (Int32)(a3 / 100000) - 1;
+ return this.digraph1.Where(x => x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
+ }
+
+ internal String GetDigraph2(Int32 longZone, Double northing) {
+ Int32 a1 = longZone;
+ Double a2 = 1 + 5 * ((a1 - 1) % 2);
+ Double a3 = northing;
+ Double a4 = a2 + (Int32)(a3 / 100000);
+ a4 = (a2 + (Int32)(a3 / 100000.0)) % 20;
+ a4 = Math.Floor(a4);
+ if (a4 < 0) {
+ a4 += 19;
+ }
+ return this.digraph2.Where(x => x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
+ }
+
+ }
+ ///
+ /// Diagraph model
+ ///
+ [Serializable]
+ internal class Digraph {
+ public Int32 Zone { get; set; }
+ public String Letter { get; set; }
+ }
+ ///
+ /// Used for setting whether a coordinate part is latitudinal or longitudinal.
+ ///
+ [Serializable]
+ public enum CoordinateType {
///
- /// Used for handling diagraph determination
+ /// Latitude
///
- [Serializable]
- internal class Digraphs
- {
- private List digraph1;
- private List digraph2;
-
- private String[] digraph1Array = { "A", "B", "C", "D", "E", "F", "G", "H",
- "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
- "Y", "Z" };
-
- private String[] digraph2Array = { "V", "A", "B", "C", "D", "E", "F", "G",
- "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V" };
-
- public Digraphs()
- {
- digraph1 = new List();
- digraph2 = new List();
-
- digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
- digraph1.Add(new Digraph() { Zone = 2, Letter = "B" });
- digraph1.Add(new Digraph() { Zone = 3, Letter = "C" });
- digraph1.Add(new Digraph() { Zone = 4, Letter = "D" });
- digraph1.Add(new Digraph() { Zone = 5, Letter = "E" });
- digraph1.Add(new Digraph() { Zone = 6, Letter = "F" });
- digraph1.Add(new Digraph() { Zone = 7, Letter = "G" });
- digraph1.Add(new Digraph() { Zone = 8, Letter = "H" });
- digraph1.Add(new Digraph() { Zone = 9, Letter = "J" });
- digraph1.Add(new Digraph() { Zone = 10, Letter = "K" });
- digraph1.Add(new Digraph() { Zone = 11, Letter = "L" });
- digraph1.Add(new Digraph() { Zone = 12, Letter = "M" });
- digraph1.Add(new Digraph() { Zone = 13, Letter = "N" });
- digraph1.Add(new Digraph() { Zone = 14, Letter = "P" });
- digraph1.Add(new Digraph() { Zone = 15, Letter = "Q" });
- digraph1.Add(new Digraph() { Zone = 16, Letter = "R" });
- digraph1.Add(new Digraph() { Zone = 17, Letter = "S" });
- digraph1.Add(new Digraph() { Zone = 18, Letter = "T" });
- digraph1.Add(new Digraph() { Zone = 19, Letter = "U" });
- digraph1.Add(new Digraph() { Zone = 20, Letter = "V" });
- digraph1.Add(new Digraph() { Zone = 21, Letter = "W" });
- digraph1.Add(new Digraph() { Zone = 22, Letter = "X" });
- digraph1.Add(new Digraph() { Zone = 23, Letter = "Y" });
- digraph1.Add(new Digraph() { Zone = 24, Letter = "Z" });
- digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
-
- digraph2.Add(new Digraph() { Zone = 0, Letter = "V"});
- digraph2.Add(new Digraph() { Zone = 1, Letter = "A" });
- digraph2.Add(new Digraph() { Zone = 2, Letter = "B" });
- digraph2.Add(new Digraph() { Zone = 3, Letter = "C" });
- digraph2.Add(new Digraph() { Zone = 4, Letter = "D" });
- digraph2.Add(new Digraph() { Zone = 5, Letter = "E" });
- digraph2.Add(new Digraph() { Zone = 6, Letter = "F" });
- digraph2.Add(new Digraph() { Zone = 7, Letter = "G" });
- digraph2.Add(new Digraph() { Zone = 8, Letter = "H" });
- digraph2.Add(new Digraph() { Zone = 9, Letter = "J" });
- digraph2.Add(new Digraph() { Zone = 10, Letter = "K" });
- digraph2.Add(new Digraph() { Zone = 11, Letter = "L" });
- digraph2.Add(new Digraph() { Zone = 12, Letter = "M" });
- digraph2.Add(new Digraph() { Zone = 13, Letter = "N" });
- digraph2.Add(new Digraph() { Zone = 14, Letter = "P" });
- digraph2.Add(new Digraph() { Zone = 15, Letter = "Q" });
- digraph2.Add(new Digraph() { Zone = 16, Letter = "R" });
- digraph2.Add(new Digraph() { Zone = 17, Letter = "S" });
- digraph2.Add(new Digraph() { Zone = 18, Letter = "T" });
- digraph2.Add(new Digraph() { Zone = 19, Letter = "U" });
- digraph2.Add(new Digraph() { Zone = 20, Letter = "V" });
- }
-
- internal int getDigraph1Index(String letter)
- {
- for (int i = 0; i < digraph1Array.Length; i++)
- {
- if (digraph1Array[i].Equals(letter))
- {
- return i + 1;
- }
- }
-
- return -1;
- }
-
- internal int getDigraph2Index(String letter)
- {
- for (int i = 0; i < digraph2Array.Length; i++)
- {
- if (digraph2Array[i].Equals(letter))
- {
- return i;
- }
- }
-
- return -1;
- }
-
- internal String getDigraph1(int longZone, double easting)
- {
- int a1 = longZone;
- double a2 = 8 * ((a1 - 1) % 3) + 1;
-
- double a3 = easting;
- double a4 = a2 + ((int)(a3 / 100000)) - 1;
- return digraph1.Where(x=>x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
- }
-
- internal String getDigraph2(int longZone, double northing)
- {
- int a1 = longZone;
- double a2 = 1 + 5 * ((a1 - 1) % 2);
- double a3 = northing;
- double a4 = (a2 + ((int)(a3 / 100000)));
- a4 = (a2 + ((int)(a3 / 100000.0))) % 20;
- a4 = Math.Floor(a4);
- if (a4 < 0)
- {
- a4 = a4 + 19;
- }
- return digraph2.Where(x => x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
- }
-
- }
+ Lat,
///
- /// Diagraph model
+ /// Longitude
///
- [Serializable]
- internal class Digraph
- {
- public int Zone { get; set; }
- public string Letter { get; set; }
- }
+ Long
+ }
+ ///
+ /// Used to set a coordinate part position.
+ ///
+ [Serializable]
+ public enum CoordinatesPosition : Int32 {
///
- /// Used for setting whether a coordinate part is latitudinal or longitudinal.
+ /// North
///
- [Serializable]
- public enum CoordinateType
- {
- ///
- /// Latitude
- ///
- Lat,
- ///
- /// Longitude
- ///
- Long
- }
+ N,
///
- /// Used to set a coordinate part position.
+ /// East
///
- [Serializable]
- public enum CoordinatesPosition :int
- {
- ///
- /// North
- ///
- N,
- ///
- /// East
- ///
- E,
- ///
- /// South
- ///
- S,
- ///
- /// West
- ///
- W
- }
-
-
+ E,
///
- /// Coordinate type datum specification
+ /// South
///
- [Serializable]
- [Flags]
- public enum Coordinate_Datum
- {
- ///
- /// Lat Long GeoDetic
- ///
- LAT_LONG = 1,
- ///
- /// UTM and MGRS
- ///
- UTM_MGRS = 2,
- ///
- /// ECEF
- ///
- ECEF = 4,
- }
-
+ S,
///
- /// Cartesian Coordinate Type
+ /// West
///
- public enum CartesianType
- {
- ///
- /// Spherical Cartesian
- ///
- Cartesian,
- ///
- /// Earth Centered Earth Fixed
- ///
- ECEF,
- }
- ///
- /// Used for easy read math functions
- ///
- [Serializable]
- internal static class ModM
- {
- public static double Mod(double x, double y)
- {
- return x - y * Math.Floor(x / y);
- }
+ W
+ }
- public static double ModLon(double x)
- {
- return Mod(x + Math.PI, 2 * Math.PI) - Math.PI;
- }
- public static double ModCrs(double x)
- {
- return Mod(x, 2 * Math.PI);
- }
-
- public static double ModLat(double x)
- {
- return Mod(x + Math.PI / 2, 2 * Math.PI) - Math.PI / 2;
- }
- }
+ ///
+ /// Coordinate type datum specification
+ ///
+ [Serializable]
+ [Flags]
+ public enum Coordinate_Datum {
///
- /// Earth Shape for Calculations.
+ /// Lat Long GeoDetic
///
+ LAT_LONG = 1,
+ ///
+ /// UTM and MGRS
+ ///
+ UTM_MGRS = 2,
+ ///
+ /// ECEF
+ ///
+ ECEF = 4,
+ }
+
+ ///
+ /// Cartesian Coordinate Type
+ ///
+ public enum CartesianType {
+ ///
+ /// Spherical Cartesian
+ ///
+ Cartesian,
+ ///
+ /// Earth Centered Earth Fixed
+ ///
+ ECEF,
+ }
+ ///
+ /// Used for easy read math functions
+ ///
+ [Serializable]
+ internal static class ModM {
+ public static Double Mod(Double x, Double y) => x - y * Math.Floor(x / y);
+
+ public static Double ModLon(Double x) => Mod(x + Math.PI, 2 * Math.PI) - Math.PI;
+
+ public static Double ModCrs(Double x) => Mod(x, 2 * Math.PI);
+
+ public static Double ModLat(Double x) => Mod(x + Math.PI / 2, 2 * Math.PI) - Math.PI / 2;
+ }
+ ///
+ /// Earth Shape for Calculations.
+ ///
+
+ [Serializable]
+ public enum Shape {
+ ///
+ /// Calculate as sphere (less accurate, more efficient).
+ ///
+ Sphere,
+ ///
+ /// Calculate as ellipsoid (more accurate, less efficient).
+ ///
+ Ellipsoid
+ }
- [Serializable]
- public enum Shape
- {
- ///
- /// Calculate as sphere (less accurate, more efficient).
- ///
- Sphere,
- ///
- /// Calculate as ellipsoid (more accurate, less efficient).
- ///
- Ellipsoid
- }
-
}
diff --git a/CoordinateSharp/Coordinate.Cartesian.cs b/CoordinateSharp/Coordinate.Cartesian.cs
index 4dc981c..7b8ce51 100644
--- a/CoordinateSharp/Coordinate.Cartesian.cs
+++ b/CoordinateSharp/Coordinate.Cartesian.cs
@@ -1,155 +1,135 @@
using System;
using System.ComponentModel;
-namespace CoordinateSharp
-{
+
+namespace CoordinateSharp {
+ ///
+ /// Cartesian (X, Y, Z) Coordinate
+ ///
+ [Serializable]
+ public class Cartesian : INotifyPropertyChanged {
///
- /// Cartesian (X, Y, Z) Coordinate
+ /// Create a Cartesian Object
///
- [Serializable]
- public class Cartesian : INotifyPropertyChanged
- {
- ///
- /// Create a Cartesian Object
- ///
- ///
- public Cartesian(Coordinate c)
- {
- //formulas:
- x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
- y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
- z = Math.Sin(c.Latitude.ToRadians());
- }
- ///
- /// Create a Cartesian Object
- ///
- /// X
- /// Y
- /// Z
- public Cartesian(double xc, double yc, double zc)
- {
- //formulas:
- x = xc;
- y = yc;
- z = zc;
- }
- ///
- /// Updates Cartesian Values
- ///
- ///
- public void ToCartesian(Coordinate c)
- {
- x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
- y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
- z = Math.Sin(c.Latitude.ToRadians());
- }
- private double x;
- private double y;
- private double z;
-
- ///
- /// X Coordinate
- ///
- public double X
- {
- get { return x; }
- set
- {
- if(x != value)
- {
- x = value;
- NotifyPropertyChanged("X");
- }
- }
- }
- ///
- /// y Coordinate
- ///
- public double Y
- {
- get { return y; }
- set
- {
- if (y != value)
- {
- y = value;
- NotifyPropertyChanged("Y");
- }
- }
- }
- ///
- /// Z Coordinate
- ///
- public double Z
- {
- get { return z; }
- set
- {
- if (z != value)
- {
- z = value;
- NotifyPropertyChanged("Z");
- }
- }
- }
- ///
- /// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
- ///
- /// X
- /// Y
- /// Z
- ///
- public static Coordinate CartesianToLatLong(double x, double y, double z)
- {
- double lon = Math.Atan2(y, x);
- double hyp = Math.Sqrt(x * x + y * y);
- double lat = Math.Atan2(z, hyp);
-
- double Lat = lat * (180 / Math.PI);
- double Lon = lon * (180 / Math.PI);
- return new Coordinate(Lat, Lon);
- }
- ///
- /// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
- ///
- /// Cartesian Coordinate
- ///
- public static Coordinate CartesianToLatLong(Cartesian cart)
- {
- double x = cart.X;
- double y = cart.Y;
- double z = cart.Z;
-
- double lon = Math.Atan2(y, x);
- double hyp = Math.Sqrt(x * x + y * y);
- double lat = Math.Atan2(z, hyp);
-
- double Lat = lat * (180 / Math.PI);
- double Lon = lon * (180 / Math.PI);
- return new Coordinate(Lat, Lon);
- }
- ///
- /// Cartesian Default String Format
- ///
- /// Cartesian Formatted Coordinate String
- /// Values rounded to the 8th place
- public override string ToString()
- {
- return Math.Round(x,8).ToString() + " " + Math.Round(y, 8).ToString() + " " + Math.Round(z, 8).ToString();
- }
- ///
- /// Property changed event
- ///
- public event PropertyChangedEventHandler PropertyChanged;
- ///
- /// Notify property changed
- ///
- /// Property name
- public void NotifyPropertyChanged(string propName)
- {
- if (this.PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propName));
- }
- }
+ ///
+ public Cartesian(Coordinate c) {
+ //formulas:
+ this.x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
+ this.y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
+ this.z = Math.Sin(c.Latitude.ToRadians());
}
+ ///
+ /// Create a Cartesian Object
+ ///
+ /// X
+ /// Y
+ /// Z
+ public Cartesian(Double xc, Double yc, Double zc) {
+ //formulas:
+ this.x = xc;
+ this.y = yc;
+ this.z = zc;
+ }
+ ///
+ /// Updates Cartesian Values
+ ///
+ ///
+ public void ToCartesian(Coordinate c) {
+ this.x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
+ this.y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
+ this.z = Math.Sin(c.Latitude.ToRadians());
+ }
+ private Double x;
+ private Double y;
+ private Double z;
+
+ ///
+ /// X Coordinate
+ ///
+ public Double X {
+ get => this.x;
+ set {
+ if (this.x != value) {
+ this.x = value;
+ this.NotifyPropertyChanged("X");
+ }
+ }
+ }
+ ///
+ /// y Coordinate
+ ///
+ public Double Y {
+ get => this.y;
+ set {
+ if (this.y != value) {
+ this.y = value;
+ this.NotifyPropertyChanged("Y");
+ }
+ }
+ }
+ ///
+ /// Z Coordinate
+ ///
+ public Double Z {
+ get => this.z;
+ set {
+ if (this.z != value) {
+ this.z = value;
+ this.NotifyPropertyChanged("Z");
+ }
+ }
+ }
+ ///
+ /// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
+ ///
+ /// X
+ /// Y
+ /// Z
+ ///
+ public static Coordinate CartesianToLatLong(Double x, Double y, Double z) {
+ Double lon = Math.Atan2(y, x);
+ Double hyp = Math.Sqrt(x * x + y * y);
+ Double lat = Math.Atan2(z, hyp);
+
+ Double Lat = lat * (180 / Math.PI);
+ Double Lon = lon * (180 / Math.PI);
+ return new Coordinate(Lat, Lon);
+ }
+ ///
+ /// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
+ ///
+ /// Cartesian Coordinate
+ ///
+ public static Coordinate CartesianToLatLong(Cartesian cart) {
+ Double x = cart.X;
+ Double y = cart.Y;
+ Double z = cart.Z;
+
+ Double lon = Math.Atan2(y, x);
+ Double hyp = Math.Sqrt(x * x + y * y);
+ Double lat = Math.Atan2(z, hyp);
+
+ Double Lat = lat * (180 / Math.PI);
+ Double Lon = lon * (180 / Math.PI);
+ return new Coordinate(Lat, Lon);
+ }
+ ///
+ /// Cartesian Default String Format
+ ///
+ /// Cartesian Formatted Coordinate String
+ /// Values rounded to the 8th place
+ public override String ToString() => Math.Round(this.x, 8).ToString() + " " + Math.Round(this.y, 8).ToString() + " " + Math.Round(this.z, 8).ToString();
+ ///
+ /// Property changed event
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+ ///
+ /// Notify property changed
+ ///
+ /// Property name
+ public void NotifyPropertyChanged(String propName) {
+ if (this.PropertyChanged != null) {
+ PropertyChanged(this, new PropertyChangedEventArgs(propName));
+ }
+ }
+ }
}
diff --git a/CoordinateSharp/Coordinate.ECEF.cs b/CoordinateSharp/Coordinate.ECEF.cs
index 86da2c9..8e789f0 100644
--- a/CoordinateSharp/Coordinate.ECEF.cs
+++ b/CoordinateSharp/Coordinate.ECEF.cs
@@ -1,566 +1,515 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.ComponentModel;
-namespace CoordinateSharp
-{
+
+namespace CoordinateSharp {
+ ///
+ /// Earth Centered - Earth Fixed (X,Y,Z) Coordinate
+ ///
+ [Serializable]
+ public class ECEF : INotifyPropertyChanged {
///
- /// Earth Centered - Earth Fixed (X,Y,Z) Coordinate
+ /// Create an ECEF Object
///
- [Serializable]
- public class ECEF : INotifyPropertyChanged
- {
- ///
- /// Create an ECEF Object
- ///
- /// Coordinate
- public ECEF(Coordinate c)
- {
- equatorial_radius = 6378137.0;
- inverse_flattening = 298.257223563;
- WGS84();
- geodetic_height = new Distance(0);
- double[] ecef = LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, geodetic_height.Kilometers);
- x = ecef[0];
- y = ecef[1];
- z = ecef[2];
- }
- ///
- /// Create an ECEF Object
- ///
- /// Coordinate
- /// Coordinate
- public ECEF(Coordinate c, Distance height)
- {
- equatorial_radius = 6378137.0;
- inverse_flattening = 298.257223563;
- WGS84();
- geodetic_height = height;
- double[] ecef = LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, geodetic_height.Kilometers);
- x = ecef[0];
- y = ecef[1];
- z = ecef[2];
- }
- ///
- /// Create an ECEF Object
- ///
- /// X
- /// Y
- /// Z
- public ECEF(double xc, double yc, double zc)
- {
- equatorial_radius = 6378137.0;
- inverse_flattening = 298.257223563;
- WGS84();
- geodetic_height = new Distance(0);
- x = xc;
- y = yc;
- z = zc;
- }
- ///
- /// Updates ECEF Values
- ///
- /// Coordinate
- public void ToECEF(Coordinate c)
- {
- equatorial_radius = 6378137.0;
- inverse_flattening = 298.257223563;
- WGS84();
- double[] ecef = LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, geodetic_height.Kilometers);
- x = ecef[0];
- y = ecef[1];
- z = ecef[2];
- }
-
- //Globals for calucations
- private double EARTH_A;
- private double EARTH_B;
- private double EARTH_F;
- private double EARTH_Ecc;
- private double EARTH_Esq;
-
- //ECEF Values
- private double x;
- private double y;
- private double z;
- private Distance geodetic_height;
-
- //Datum
- internal double equatorial_radius;
- internal double inverse_flattening;
-
- ///
- /// Datum Equatorial Radius / Semi Major Axis
- ///
- public double Equatorial_Radius
- {
- get { return equatorial_radius; }
- }
-
- ///
- /// Datum Flattening
- ///
- public double Inverse_Flattening
- {
- get { return inverse_flattening; }
- }
-
- ///
- /// X Coordinate
- ///
- public double X
- {
- get { return x; }
- set
- {
- if (x != value)
- {
- x = value;
- NotifyPropertyChanged("X");
- }
- }
- }
- ///
- /// y Coordinate
- ///
- public double Y
- {
- get { return y; }
- set
- {
- if (y != value)
- {
- y = value;
- NotifyPropertyChanged("Y");
- }
- }
- }
- ///
- /// Z Coordinate
- ///
- public double Z
- {
- get { return z; }
- set
- {
- if (z != value)
- {
- z = value;
- NotifyPropertyChanged("Z");
- }
- }
- }
-
- ///
- /// GeoDetic Height from Mean Sea Level.
- /// Used for converting Lat Long / ECEF.
- /// Default value is 0. Adjust as needed.
- ///
- public Distance GeoDetic_Height
- {
- get { return geodetic_height; }
- internal set
- {
- if (geodetic_height != value)
- {
- geodetic_height = value;
- NotifyPropertyChanged("Height");
-
- }
- }
- }
-
- ///
- /// Sets GeoDetic height for ECEF conversion.
- /// Recalculate ECEF Coordinate
- ///
- /// Coordinate
- /// Height
- public void Set_GeoDetic_Height(Coordinate c, Distance dist)
- {
- geodetic_height = dist;
- double[] values = LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, dist.Kilometers);
- x = values[0];
- y = values[1];
- z = values[2];
-
- }
-
- ///
- /// Returns a Geodetic Coordinate object based on the provided ECEF Coordinate
- ///
- /// X
- /// Y
- /// Z
- /// Coordinate
- public static Coordinate ECEFToLatLong(double x, double y, double z)
- {
- ECEF ecef = new ECEF(x, y, z);
- double[] values = ecef.ECEF_To_LatLong(x, y, z);
- ecef.geodetic_height =new Distance(values[2]);
-
- Coordinate c = new Coordinate(values[0], values[1]);
- c.ECEF = ecef;
- return c;
- }
- ///
- /// Returns a Geodetic Coordinate object based on the provided ECEF Coordinate
- ///
- /// ECEF Coordinate
- /// Coordinate
- public static Coordinate ECEFToLatLong(ECEF ecef)
- {
- double[] values = ecef.ECEF_To_LatLong(ecef.X, ecef.Y, ecef.Z);
-
- Coordinate c = new Coordinate(values[0], values[1]);
- Distance height = new Distance(values[2]);
-
- ecef.geodetic_height = new Distance(values[2]);
- c.ECEF = ecef;
-
- return c;
- }
- ///
- /// ECEF Default String Format
- ///
- /// ECEF Formatted Coordinate String
- /// Values rounded to the 3rd place
- public override string ToString()
- {
- return Math.Round(x, 3).ToString() + " km, " + Math.Round(y, 3).ToString() + " km, " + Math.Round(z, 3).ToString() + " km";
- }
-
- ///
- /// Property changed event
- ///
- public event PropertyChangedEventHandler PropertyChanged;
- ///
- /// Notify property changed
- ///
- /// Property name
- public void NotifyPropertyChanged(string propName)
- {
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propName));
- }
- }
-
- //CONVERSION LOGIC
- ///
- /// Initialize EARTH global variables based on the Datum
- ///
- private void WGS84()
- {
- double wgs84a = equatorial_radius / 1000;
- double wgs84f = 1.0 / inverse_flattening;
- double wgs84b = wgs84a * (1.0 - wgs84f);
-
- EarthCon(wgs84a, wgs84b);
- }
-
- ///
- /// Sets Earth Constants as Globals
- ///
- /// a
- /// b
- private void EarthCon(double a, double b)
- {
- double f = 1 - b / a;
- double eccsq = 1 - b * b / (a * a);
- double ecc = Math.Sqrt(eccsq);
-
- EARTH_A = a;
- EARTH_B = b;
- EARTH_F = f;
- EARTH_Ecc = ecc;
- EARTH_Esq = eccsq;
- }
-
- ///
- /// Compute the radii at the geodetic latitude (degrees)
- ///
- /// Latitude in degres
- /// double[]
- private double[] radcur(double lat)
- {
- double[] rrnrm = new double[3];
-
- double dtr = Math.PI / 180.0;
-
- double a = EARTH_A;
- double b = EARTH_B;
-
- double asq = a * a;
- double bsq = b * b;
- double eccsq = 1 - bsq / asq;
- double ecc = Math.Sqrt(eccsq);
-
- double clat = Math.Cos(dtr * lat);
- double slat = Math.Sin(dtr * lat);
-
- double dsq = 1.0 - eccsq * slat * slat;
- double d = Math.Sqrt(dsq);
-
- double rn = a / d;
- double rm = rn * (1.0 - eccsq) / dsq;
-
- double rho = rn * clat;
- double z = (1.0 - eccsq) * rn * slat;
- double rsq = rho * rho + z * z;
- double r = Math.Sqrt(rsq);
-
- rrnrm[0] = r;
- rrnrm[1] = rn;
- rrnrm[2] = rm;
-
- return (rrnrm);
-
- }
-
- ///
- /// Physical radius of the Earth
- ///
- /// Latidude in degrees
- /// double
- private double rearth(double lat)
- {
- double[] rrnrm;
- rrnrm = radcur(lat);
- double r = rrnrm[0];
-
- return r;
- }
-
- ///
- /// Converts geocentric latitude to geodetic latitude
- ///
- /// Geocentric latitude
- /// Altitude in KM
- /// double
- private double gc2gd(double flatgc, double altkm)
- {
- var dtr = Math.PI / 180.0;
- var rtd = 1 / dtr;
-
- double ecc = EARTH_Ecc;
- double esq = ecc * ecc;
-
- //approximation by stages
- //1st use gc-lat as if is gd, then correct alt dependence
-
- double altnow = altkm;
-
- double[] rrnrm = radcur(flatgc);
- double rn = rrnrm[1];
-
- double ratio = 1 - esq * rn / (rn + altnow);
-
- double tlat = Math.Tan(dtr * flatgc) / ratio;
- double flatgd = rtd * Math.Atan(tlat);
-
- //now use this approximation for gd-lat to get rn etc.
-
- rrnrm = radcur(flatgd);
- rn = rrnrm[1];
-
- ratio = 1 - esq * rn / (rn + altnow);
- tlat = Math.Tan(dtr * flatgc) / ratio;
- flatgd = rtd * Math.Atan(tlat);
-
- return flatgd;
- }
-
- ///
- /// Converts geodetic latitude to geocentric latitude
- ///
- /// Geodetic latitude tp geocentric latitide
- /// Altitude in KM
- /// double
- private double gd2gc(double flatgd, double altkm)
- {
- double dtr = Math.PI / 180.0;
- double rtd = 1 / dtr;
-
- double ecc = EARTH_Ecc;
- double esq = ecc * ecc;
-
- double altnow = altkm;
-
- double[] rrnrm = radcur(flatgd);
- double rn = rrnrm[1];
-
- double ratio = 1 - esq * rn / (rn + altnow);
-
- double tlat = Math.Tan(dtr * flatgd) * ratio;
- double flatgc = rtd * Math.Atan(tlat);
-
- return flatgc;
- }
-
- ///
- /// Converts lat / long to east, north, up vectors
- ///
- /// Latitude
- /// Longitude
- /// Array[] of double[]
- private Array[] llenu(double flat, double flon)
- {
- double clat, slat, clon, slon;
- double[] ee = new double[3];
- double[] en = new double[3];
- double[] eu = new double[3];
-
- Array[] enu = new Array[3];
-
- double dtr = Math.PI / 180.0;
-
- clat = Math.Cos(dtr * flat);
- slat = Math.Sin(dtr * flat);
- clon = Math.Cos(dtr * flon);
- slon = Math.Sin(dtr * flon);
-
- ee[0] = -slon;
- ee[1] = clon;
- ee[2] = 0.0;
-
- en[0] = -clon * slat;
- en[1] = -slon * slat;
- en[2] = clat;
-
- eu[0] = clon * clat;
- eu[1] = slon * clat;
- eu[2] = slat;
-
- enu[0] = ee;
- enu[1] = en;
- enu[2] = eu;
-
- return enu;
- }
-
- ///
- /// Gets ECEF vector in KM
- ///
- /// Latitude
- /// Longitude
- /// Altitude in KM
- /// double[]
- private double[] LatLong_To_ECEF(double lat, double longi, double altkm)
- {
- double dtr = Math.PI / 180.0;
-
- double clat = Math.Cos(dtr * lat);
- double slat = Math.Sin(dtr * lat);
- double clon = Math.Cos(dtr * longi);
- double slon = Math.Sin(dtr * longi);
-
- double[] rrnrm = radcur(lat);
- double rn = rrnrm[1];
- double re = rrnrm[0];
-
- double ecc = EARTH_Ecc;
- double esq = ecc * ecc;
-
- double x = (rn + altkm) * clat * clon;
- double y = (rn + altkm) * clat * slon;
- double z = ((1 - esq) * rn + altkm) * slat;
-
- double[] xvec = new double[3];
-
- xvec[0] = x;
- xvec[1] = y;
- xvec[2] = z;
-
- return xvec;
- }
-
- ///
- /// Converts ECEF X, Y, Z to GeoDetic Lat / Long and Height in KM
- ///
- ///
- ///
- ///
- ///
- private double[] ECEF_To_LatLong(double x, double y, double z)
- {
- var dtr = Math.PI / 180.0;
-
- double[] rrnrm = new double[3];
- double[] llhvec = new double[3];
- double slat, tangd, flatn, dlat, clat;
- double flat;
- double altkm;
-
- double esq = EARTH_Esq;
-
- double rp = Math.Sqrt(x * x + y * y + z * z);
-
- double flatgc = Math.Asin(z / rp) / dtr;
- double flon;
- double testval = Math.Abs(x) + Math.Abs(y);
- if (testval < 1.0e-10)
- { flon = 0.0; }
- else
- { flon = Math.Atan2(y, x) / dtr; }
- if (flon < 0.0) { flon = flon + 360.0; }
-
- double p = Math.Sqrt(x * x + y * y);
-
- //Pole special case
-
- if (p < 1.0e-10)
- {
- flat = 90.0;
- if (z < 0.0) { flat = -90.0; }
-
- altkm = rp - rearth(flat);
- llhvec[0] = flat;
- llhvec[1] = flon;
- llhvec[2] = altkm;
-
- return llhvec;
- }
-
- //first iteration, use flatgc to get altitude
- //and alt needed to convert gc to gd lat.
-
- double rnow = rearth(flatgc);
- altkm = rp - rnow;
- flat = gc2gd(flatgc, altkm);
-
- rrnrm = radcur(flat);
- double rn = rrnrm[1];
-
- for (int kount = 0; kount < 5; kount++)
- {
- slat = Math.Sin(dtr * flat);
- tangd = (z + rn * esq * slat) / p;
- flatn = Math.Atan(tangd) / dtr;
-
- dlat = flatn - flat;
- flat = flatn;
- clat = Math.Cos(dtr * flat);
-
- rrnrm = radcur(flat);
- rn = rrnrm[1];
-
- altkm = (p / clat) - rn;
-
- if (Math.Abs(dlat) < 1.0e-12) { break; }
-
- }
- //CONVERTER WORKS IN E LAT ONLY, IF E LAT > 180 LAT IS WEST SO IT MUCST BE CONVERTED TO Decimal
-
- if (flon > 180) { flon = flon - 360; }
- llhvec[0] = flat;
- llhvec[1] = flon;
- llhvec[2] = altkm;
-
- return llhvec;
- }
-
-
+ /// Coordinate
+ public ECEF(Coordinate c) {
+ this.equatorial_radius = 6378137.0;
+ this.inverse_flattening = 298.257223563;
+ this.WGS84();
+ this.geodetic_height = new Distance(0);
+ Double[] ecef = this.LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, this.geodetic_height.Kilometers);
+ this.x = ecef[0];
+ this.y = ecef[1];
+ this.z = ecef[2];
}
+ ///
+ /// Create an ECEF Object
+ ///
+ /// Coordinate
+ /// Coordinate
+ public ECEF(Coordinate c, Distance height) {
+ this.equatorial_radius = 6378137.0;
+ this.inverse_flattening = 298.257223563;
+ this.WGS84();
+ this.geodetic_height = height;
+ Double[] ecef = this.LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, this.geodetic_height.Kilometers);
+ this.x = ecef[0];
+ this.y = ecef[1];
+ this.z = ecef[2];
+ }
+ ///
+ /// Create an ECEF Object
+ ///
+ /// X
+ /// Y
+ /// Z
+ public ECEF(Double xc, Double yc, Double zc) {
+ this.equatorial_radius = 6378137.0;
+ this.inverse_flattening = 298.257223563;
+ this.WGS84();
+ this.geodetic_height = new Distance(0);
+ this.x = xc;
+ this.y = yc;
+ this.z = zc;
+ }
+ ///
+ /// Updates ECEF Values
+ ///
+ /// Coordinate
+ public void ToECEF(Coordinate c) {
+ this.equatorial_radius = 6378137.0;
+ this.inverse_flattening = 298.257223563;
+ this.WGS84();
+ Double[] ecef = this.LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, this.geodetic_height.Kilometers);
+ this.x = ecef[0];
+ this.y = ecef[1];
+ this.z = ecef[2];
+ }
+
+ //Globals for calucations
+ private Double EARTH_A;
+ private Double EARTH_B;
+ //private Double EARTH_F;
+ private Double EARTH_Ecc;
+ private Double EARTH_Esq;
+
+ //ECEF Values
+ private Double x;
+ private Double y;
+ private Double z;
+ private Distance geodetic_height;
+
+ //Datum
+ internal Double equatorial_radius;
+ internal Double inverse_flattening;
+
+ ///
+ /// Datum Equatorial Radius / Semi Major Axis
+ ///
+ public Double Equatorial_Radius => this.equatorial_radius;
+
+ ///
+ /// Datum Flattening
+ ///
+ public Double Inverse_Flattening => this.inverse_flattening;
+
+ ///
+ /// X Coordinate
+ ///
+ public Double X {
+ get => this.x;
+ set {
+ if (this.x != value) {
+ this.x = value;
+ this.NotifyPropertyChanged("X");
+ }
+ }
+ }
+ ///
+ /// y Coordinate
+ ///
+ public Double Y {
+ get => this.y;
+ set {
+ if (this.y != value) {
+ this.y = value;
+ this.NotifyPropertyChanged("Y");
+ }
+ }
+ }
+ ///
+ /// Z Coordinate
+ ///
+ public Double Z {
+ get => this.z;
+ set {
+ if (this.z != value) {
+ this.z = value;
+ this.NotifyPropertyChanged("Z");
+ }
+ }
+ }
+
+ ///
+ /// GeoDetic Height from Mean Sea Level.
+ /// Used for converting Lat Long / ECEF.
+ /// Default value is 0. Adjust as needed.
+ ///
+ public Distance GeoDetic_Height {
+ get => this.geodetic_height;
+ internal set {
+ if (this.geodetic_height != value) {
+ this.geodetic_height = value;
+ this.NotifyPropertyChanged("Height");
+
+ }
+ }
+ }
+
+ ///
+ /// Sets GeoDetic height for ECEF conversion.
+ /// Recalculate ECEF Coordinate
+ ///
+ /// Coordinate
+ /// Height
+ public void Set_GeoDetic_Height(Coordinate c, Distance dist) {
+ this.geodetic_height = dist;
+ Double[] values = this.LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, dist.Kilometers);
+ this.x = values[0];
+ this.y = values[1];
+ this.z = values[2];
+
+ }
+
+ ///
+ /// Returns a Geodetic Coordinate object based on the provided ECEF Coordinate
+ ///
+ /// X
+ /// Y
+ /// Z
+ /// Coordinate
+ public static Coordinate ECEFToLatLong(Double x, Double y, Double z) {
+ ECEF ecef = new ECEF(x, y, z);
+ Double[] values = ecef.ECEF_To_LatLong(x, y, z);
+ ecef.geodetic_height = new Distance(values[2]);
+
+ Coordinate c = new Coordinate(values[0], values[1]) {
+ ECEF = ecef
+ };
+ return c;
+ }
+ ///
+ /// Returns a Geodetic Coordinate object based on the provided ECEF Coordinate
+ ///
+ /// ECEF Coordinate
+ /// Coordinate
+ public static Coordinate ECEFToLatLong(ECEF ecef) {
+ Double[] values = ecef.ECEF_To_LatLong(ecef.X, ecef.Y, ecef.Z);
+
+ Coordinate c = new Coordinate(values[0], values[1]);
+ //Distance height = new Distance(values[2]);
+
+ ecef.geodetic_height = new Distance(values[2]);
+ c.ECEF = ecef;
+
+ return c;
+ }
+ ///
+ /// ECEF Default String Format
+ ///
+ /// ECEF Formatted Coordinate String
+ /// Values rounded to the 3rd place
+ public override String ToString() => Math.Round(this.x, 3).ToString() + " km, " + Math.Round(this.y, 3).ToString() + " km, " + Math.Round(this.z, 3).ToString() + " km";
+
+ ///
+ /// Property changed event
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+ ///
+ /// Notify property changed
+ ///
+ /// Property name
+ public void NotifyPropertyChanged(String propName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
+
+ //CONVERSION LOGIC
+ ///
+ /// Initialize EARTH global variables based on the Datum
+ ///
+ private void WGS84() {
+ Double wgs84a = this.equatorial_radius / 1000;
+ Double wgs84f = 1.0 / this.inverse_flattening;
+ Double wgs84b = wgs84a * (1.0 - wgs84f);
+
+ this.EarthCon(wgs84a, wgs84b);
+ }
+
+ ///
+ /// Sets Earth Constants as Globals
+ ///
+ /// a
+ /// b
+ private void EarthCon(Double a, Double b) {
+ //Double f = 1 - b / a;
+ Double eccsq = 1 - b * b / (a * a);
+ Double ecc = Math.Sqrt(eccsq);
+
+ this.EARTH_A = a;
+ this.EARTH_B = b;
+ //this.EARTH_F = f;
+ this.EARTH_Ecc = ecc;
+ this.EARTH_Esq = eccsq;
+ }
+
+ ///
+ /// Compute the radii at the geodetic latitude (degrees)
+ ///
+ /// Latitude in degres
+ /// double[]
+ private Double[] Radcur(Double lat) {
+ Double[] rrnrm = new Double[3];
+
+ Double dtr = Math.PI / 180.0;
+
+ Double a = this.EARTH_A;
+ Double b = this.EARTH_B;
+
+ Double asq = a * a;
+ Double bsq = b * b;
+ Double eccsq = 1 - bsq / asq;
+ //Double ecc = Math.Sqrt(eccsq);
+
+ Double clat = Math.Cos(dtr * lat);
+ Double slat = Math.Sin(dtr * lat);
+
+ Double dsq = 1.0 - eccsq * slat * slat;
+ Double d = Math.Sqrt(dsq);
+
+ Double rn = a / d;
+ Double rm = rn * (1.0 - eccsq) / dsq;
+
+ Double rho = rn * clat;
+ Double z = (1.0 - eccsq) * rn * slat;
+ Double rsq = rho * rho + z * z;
+ Double r = Math.Sqrt(rsq);
+
+ rrnrm[0] = r;
+ rrnrm[1] = rn;
+ rrnrm[2] = rm;
+
+ return rrnrm;
+
+ }
+
+ ///
+ /// Physical radius of the Earth
+ ///
+ /// Latidude in degrees
+ /// double
+ private Double Rearth(Double lat) {
+ Double[] rrnrm;
+ rrnrm = this.Radcur(lat);
+ Double r = rrnrm[0];
+
+ return r;
+ }
+
+ ///
+ /// Converts geocentric latitude to geodetic latitude
+ ///
+ /// Geocentric latitude
+ /// Altitude in KM
+ /// double
+ private Double Gc2gd(Double flatgc, Double altkm) {
+ Double dtr = Math.PI / 180.0;
+ Double rtd = 1 / dtr;
+
+ Double ecc = this.EARTH_Ecc;
+ Double esq = ecc * ecc;
+
+ //approximation by stages
+ //1st use gc-lat as if is gd, then correct alt dependence
+
+ Double altnow = altkm;
+
+ Double[] rrnrm = this.Radcur(flatgc);
+ Double rn = rrnrm[1];
+
+ Double ratio = 1 - esq * rn / (rn + altnow);
+
+ Double tlat = Math.Tan(dtr * flatgc) / ratio;
+ Double flatgd = rtd * Math.Atan(tlat);
+
+ //now use this approximation for gd-lat to get rn etc.
+
+ rrnrm = this.Radcur(flatgd);
+ rn = rrnrm[1];
+
+ ratio = 1 - esq * rn / (rn + altnow);
+ tlat = Math.Tan(dtr * flatgc) / ratio;
+ flatgd = rtd * Math.Atan(tlat);
+
+ return flatgd;
+ }
+
+ ///
+ /// Converts geodetic latitude to geocentric latitude
+ ///
+ /// Geodetic latitude tp geocentric latitide
+ /// Altitude in KM
+ /// double
+ /*private Double gd2gc(Double flatgd, Double altkm) {
+ Double dtr = Math.PI / 180.0;
+ Double rtd = 1 / dtr;
+
+ Double ecc = this.EARTH_Ecc;
+ Double esq = ecc * ecc;
+
+ Double altnow = altkm;
+
+ Double[] rrnrm = this.Radcur(flatgd);
+ Double rn = rrnrm[1];
+
+ Double ratio = 1 - esq * rn / (rn + altnow);
+
+ Double tlat = Math.Tan(dtr * flatgd) * ratio;
+ Double flatgc = rtd * Math.Atan(tlat);
+
+ return flatgc;
+ }*/
+
+ ///
+ /// Converts lat / long to east, north, up vectors
+ ///
+ /// Latitude
+ /// Longitude
+ /// Array[] of double[]
+ /*private Array[] llenu(Double flat, Double flon) {
+ Double clat, slat, clon, slon;
+ Double[] ee = new Double[3];
+ Double[] en = new Double[3];
+ Double[] eu = new Double[3];
+
+ Array[] enu = new Array[3];
+
+ Double dtr = Math.PI / 180.0;
+
+ clat = Math.Cos(dtr * flat);
+ slat = Math.Sin(dtr * flat);
+ clon = Math.Cos(dtr * flon);
+ slon = Math.Sin(dtr * flon);
+
+ ee[0] = -slon;
+ ee[1] = clon;
+ ee[2] = 0.0;
+
+ en[0] = -clon * slat;
+ en[1] = -slon * slat;
+ en[2] = clat;
+
+ eu[0] = clon * clat;
+ eu[1] = slon * clat;
+ eu[2] = slat;
+
+ enu[0] = ee;
+ enu[1] = en;
+ enu[2] = eu;
+
+ return enu;
+ }*/
+
+ ///
+ /// Gets ECEF vector in KM
+ ///
+ /// Latitude
+ /// Longitude
+ /// Altitude in KM
+ /// double[]
+ private Double[] LatLong_To_ECEF(Double lat, Double longi, Double altkm) {
+ Double dtr = Math.PI / 180.0;
+
+ Double clat = Math.Cos(dtr * lat);
+ Double slat = Math.Sin(dtr * lat);
+ Double clon = Math.Cos(dtr * longi);
+ Double slon = Math.Sin(dtr * longi);
+
+ Double[] rrnrm = this.Radcur(lat);
+ Double rn = rrnrm[1];
+ //Double re = rrnrm[0];
+
+ Double ecc = this.EARTH_Ecc;
+ Double esq = ecc * ecc;
+
+ Double x = (rn + altkm) * clat * clon;
+ Double y = (rn + altkm) * clat * slon;
+ Double z = ((1 - esq) * rn + altkm) * slat;
+
+ Double[] xvec = new Double[3];
+
+ xvec[0] = x;
+ xvec[1] = y;
+ xvec[2] = z;
+
+ return xvec;
+ }
+
+ ///
+ /// Converts ECEF X, Y, Z to GeoDetic Lat / Long and Height in KM
+ ///
+ ///
+ ///
+ ///
+ ///
+ private Double[] ECEF_To_LatLong(Double x, Double y, Double z) {
+ Double dtr = Math.PI / 180.0;
+
+ //_ = new Double[3];
+ Double[] llhvec = new Double[3];
+ Double slat, tangd, flatn, dlat, clat;
+ Double flat;
+ Double altkm;
+
+ Double esq = this.EARTH_Esq;
+
+ Double rp = Math.Sqrt(x * x + y * y + z * z);
+
+ Double flatgc = Math.Asin(z / rp) / dtr;
+ Double flon;
+ Double testval = Math.Abs(x) + Math.Abs(y);
+ flon = testval < 1.0e-10 ? 0.0 : Math.Atan2(y, x) / dtr;
+ if (flon < 0.0) { flon += 360.0; }
+
+ Double p = Math.Sqrt(x * x + y * y);
+
+ //Pole special case
+
+ if (p < 1.0e-10) {
+ flat = 90.0;
+ if (z < 0.0) { flat = -90.0; }
+
+ altkm = rp - this.Rearth(flat);
+ llhvec[0] = flat;
+ llhvec[1] = flon;
+ llhvec[2] = altkm;
+
+ return llhvec;
+ }
+
+ //first iteration, use flatgc to get altitude
+ //and alt needed to convert gc to gd lat.
+
+ Double rnow = this.Rearth(flatgc);
+ altkm = rp - rnow;
+ flat = this.Gc2gd(flatgc, altkm);
+
+ Double[] rrnrm = this.Radcur(flat);
+ Double rn = rrnrm[1];
+
+ for (Int32 kount = 0; kount < 5; kount++) {
+ slat = Math.Sin(dtr * flat);
+ tangd = (z + rn * esq * slat) / p;
+ flatn = Math.Atan(tangd) / dtr;
+
+ dlat = flatn - flat;
+ flat = flatn;
+ clat = Math.Cos(dtr * flat);
+
+ rrnrm = this.Radcur(flat);
+ rn = rrnrm[1];
+
+ altkm = p / clat - rn;
+
+ if (Math.Abs(dlat) < 1.0e-12) { break; }
+
+ }
+ //CONVERTER WORKS IN E LAT ONLY, IF E LAT > 180 LAT IS WEST SO IT MUCST BE CONVERTED TO Decimal
+
+ if (flon > 180) { flon -= 360; }
+ llhvec[0] = flat;
+ llhvec[1] = flon;
+ llhvec[2] = altkm;
+
+ return llhvec;
+ }
+
+
+ }
}
diff --git a/CoordinateSharp/Coordinate.EagerLoad.cs b/CoordinateSharp/Coordinate.EagerLoad.cs
index f535a67..c15c074 100644
--- a/CoordinateSharp/Coordinate.EagerLoad.cs
+++ b/CoordinateSharp/Coordinate.EagerLoad.cs
@@ -1,119 +1,105 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-namespace CoordinateSharp
-{
+namespace CoordinateSharp {
+ ///
+ /// Turn on/off eager loading of certain properties.
+ ///
+ [Serializable]
+ public class EagerLoad {
///
- /// Turn on/off eager loading of certain properties.
+ /// Create an EagerLoad object
///
- [Serializable]
- public class EagerLoad
- {
- ///
- /// Create an EagerLoad object
- ///
- public EagerLoad()
- {
- Celestial = true;
- UTM_MGRS = true;
- Cartesian = true;
- ECEF = true;
- }
-
- ///
- /// Create an EagerLoad object with all options on or off
- ///
- /// Turns EagerLoad on or off
- public EagerLoad(bool isOn)
- {
- Celestial = isOn;
- UTM_MGRS = isOn;
- Cartesian = isOn;
- ECEF = isOn;
- }
-
- ///
- /// Create an EagerLoad object with only the specified flag options turned on.
- ///
- /// EagerLoadType
- public EagerLoad(EagerLoadType et)
- {
- Cartesian = false;
- Celestial = false;
- UTM_MGRS = false;
- ECEF = false;
-
- if (et.HasFlag(EagerLoadType.Cartesian))
- {
- Cartesian = true;
- }
- if (et.HasFlag(EagerLoadType.Celestial))
- {
- Celestial = true;
- }
- if (et.HasFlag(EagerLoadType.UTM_MGRS))
- {
- UTM_MGRS = true;
- }
- if (et.HasFlag(EagerLoadType.ECEF))
- {
- ECEF = true;
- }
- }
-
- ///
- /// Creates an EagerLoad object. Only the specified flags will be set to EagerLoad.
- ///
- /// EagerLoadType
- /// EagerLoad
- public static EagerLoad Create(EagerLoadType et)
- {
- EagerLoad el = new EagerLoad(et);
- return el;
- }
-
- ///
- /// Eager load celestial information.
- ///
- public bool Celestial { get; set; }
- ///
- /// Eager load UTM and MGRS information
- ///
- public bool UTM_MGRS { get; set; }
- ///
- /// Eager load Cartesian information
- ///
- public bool Cartesian { get; set; }
- ///
- /// Eager load ECEF information
- ///
- public bool ECEF { get; set; }
+ public EagerLoad() {
+ this.Celestial = true;
+ this.UTM_MGRS = true;
+ this.Cartesian = true;
+ this.ECEF = true;
}
+
///
- /// EagerLoad Enumerator
+ /// Create an EagerLoad object with all options on or off
///
- [Serializable]
- [Flags]
- public enum EagerLoadType
- {
- ///
- /// UTM and MGRS
- ///
- UTM_MGRS = 1,
- ///
- /// Celestial
- ///
- Celestial = 2,
- ///
- /// Cartesian
- ///
- Cartesian = 4,
- ///
- /// ECEF
- ///
- ECEF = 8
-
+ /// Turns EagerLoad on or off
+ public EagerLoad(Boolean isOn) {
+ this.Celestial = isOn;
+ this.UTM_MGRS = isOn;
+ this.Cartesian = isOn;
+ this.ECEF = isOn;
}
+
+ ///
+ /// Create an EagerLoad object with only the specified flag options turned on.
+ ///
+ /// EagerLoadType
+ public EagerLoad(EagerLoadType et) {
+ this.Cartesian = false;
+ this.Celestial = false;
+ this.UTM_MGRS = false;
+ this.ECEF = false;
+
+ if (et.HasFlag(EagerLoadType.Cartesian)) {
+ this.Cartesian = true;
+ }
+ if (et.HasFlag(EagerLoadType.Celestial)) {
+ this.Celestial = true;
+ }
+ if (et.HasFlag(EagerLoadType.UTM_MGRS)) {
+ this.UTM_MGRS = true;
+ }
+ if (et.HasFlag(EagerLoadType.ECEF)) {
+ this.ECEF = true;
+ }
+ }
+
+ ///
+ /// Creates an EagerLoad object. Only the specified flags will be set to EagerLoad.
+ ///
+ /// EagerLoadType
+ /// EagerLoad
+ public static EagerLoad Create(EagerLoadType et) {
+ EagerLoad el = new EagerLoad(et);
+ return el;
+ }
+
+ ///
+ /// Eager load celestial information.
+ ///
+ public Boolean Celestial { get; set; }
+ ///
+ /// Eager load UTM and MGRS information
+ ///
+ public Boolean UTM_MGRS { get; set; }
+ ///
+ /// Eager load Cartesian information
+ ///
+ public Boolean Cartesian { get; set; }
+ ///
+ /// Eager load ECEF information
+ ///
+ public Boolean ECEF { get; set; }
+ }
+ ///
+ /// EagerLoad Enumerator
+ ///
+ [Serializable]
+ [Flags]
+ public enum EagerLoadType {
+ ///
+ /// UTM and MGRS
+ ///
+ UTM_MGRS = 1,
+ ///
+ /// Celestial
+ ///
+ Celestial = 2,
+ ///
+ /// Cartesian
+ ///
+ Cartesian = 4,
+ ///
+ /// ECEF
+ ///
+ ECEF = 8
+
+ }
}
diff --git a/CoordinateSharp/Coordinate.Formatting.cs b/CoordinateSharp/Coordinate.Formatting.cs
index 2a0084d..e1f300c 100644
--- a/CoordinateSharp/Coordinate.Formatting.cs
+++ b/CoordinateSharp/Coordinate.Formatting.cs
@@ -1,107 +1,100 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-namespace CoordinateSharp
-{
+namespace CoordinateSharp {
+ ///
+ /// Coordinate formatting options for a Coordinate object.
+ ///
+ [Serializable]
+ public class CoordinateFormatOptions {
///
- /// Coordinate formatting options for a Coordinate object.
+ /// Set default values with the constructor.
///
- [Serializable]
- public class CoordinateFormatOptions
- {
- ///
- /// Set default values with the constructor.
- ///
- public CoordinateFormatOptions()
- {
- Format = CoordinateFormatType.Degree_Minutes_Seconds;
- Round = 3;
- Display_Leading_Zeros = false;
- Display_Trailing_Zeros = false;
- Display_Symbols = true;
- Display_Degree_Symbol = true;
- Display_Minute_Symbol = true;
- Display_Seconds_Symbol = true;
- Display_Hyphens = false;
- Position_First = true;
- }
- ///
- /// Coordinate format type.
- ///
- public CoordinateFormatType Format { get; set; }
- ///
- /// Rounds Coordinates to the set value.
- ///
- public int Round { get; set; }
- ///
- /// Displays leading zeros.
- ///
- public bool Display_Leading_Zeros { get; set; }
- ///
- /// Display trailing zeros.
- ///
- public bool Display_Trailing_Zeros { get; set; }
- ///
- /// Allow symbols to display.
- ///
- public bool Display_Symbols { get; set; }
- ///
- /// Display degree symbols.
- ///
- public bool Display_Degree_Symbol { get; set; }
- ///
- /// Display minute symbols.
- ///
- public bool Display_Minute_Symbol { get; set; }
- ///
- /// Display secons symbol.
- ///
- public bool Display_Seconds_Symbol { get; set; }
- ///
- /// Display hyphens between values.
- ///
- public bool Display_Hyphens { get; set; }
- ///
- /// Show coordinate position first.
- /// Will show last if set 'false'.
- ///
- public bool Position_First { get; set; }
+ public CoordinateFormatOptions() {
+ this.Format = CoordinateFormatType.Degree_Minutes_Seconds;
+ this.Round = 3;
+ this.Display_Leading_Zeros = false;
+ this.Display_Trailing_Zeros = false;
+ this.Display_Symbols = true;
+ this.Display_Degree_Symbol = true;
+ this.Display_Minute_Symbol = true;
+ this.Display_Seconds_Symbol = true;
+ this.Display_Hyphens = false;
+ this.Position_First = true;
}
///
- /// Coordinate Format Types.
+ /// Coordinate format type.
///
- [Serializable]
- public enum CoordinateFormatType
- {
- ///
- /// Decimal Degree Format
- ///
- ///
- /// Example: N 40.456 W 75.456
- ///
- Decimal_Degree,
- ///
- /// Decimal Degree Minutes Format
- ///
- ///
- /// Example: N 40º 34.552' W 70º 45.408'
- ///
- Degree_Decimal_Minutes,
- ///
- /// Decimal Degree Minutes Format
- ///
- ///
- /// Example: N 40º 34" 36.552' W 70º 45" 24.408'
- ///
- Degree_Minutes_Seconds,
- ///
- /// Decimal Format
- ///
- ///
- /// Example: 40.57674 -70.46574
- ///
- Decimal
- }
+ public CoordinateFormatType Format { get; set; }
+ ///
+ /// Rounds Coordinates to the set value.
+ ///
+ public Int32 Round { get; set; }
+ ///
+ /// Displays leading zeros.
+ ///
+ public Boolean Display_Leading_Zeros { get; set; }
+ ///
+ /// Display trailing zeros.
+ ///
+ public Boolean Display_Trailing_Zeros { get; set; }
+ ///
+ /// Allow symbols to display.
+ ///
+ public Boolean Display_Symbols { get; set; }
+ ///
+ /// Display degree symbols.
+ ///
+ public Boolean Display_Degree_Symbol { get; set; }
+ ///
+ /// Display minute symbols.
+ ///
+ public Boolean Display_Minute_Symbol { get; set; }
+ ///
+ /// Display secons symbol.
+ ///
+ public Boolean Display_Seconds_Symbol { get; set; }
+ ///
+ /// Display hyphens between values.
+ ///
+ public Boolean Display_Hyphens { get; set; }
+ ///
+ /// Show coordinate position first.
+ /// Will show last if set 'false'.
+ ///
+ public Boolean Position_First { get; set; }
+ }
+ ///
+ /// Coordinate Format Types.
+ ///
+ [Serializable]
+ public enum CoordinateFormatType {
+ ///
+ /// Decimal Degree Format
+ ///
+ ///
+ /// Example: N 40.456 W 75.456
+ ///
+ Decimal_Degree,
+ ///
+ /// Decimal Degree Minutes Format
+ ///
+ ///
+ /// Example: N 40º 34.552' W 70º 45.408'
+ ///
+ Degree_Decimal_Minutes,
+ ///
+ /// Decimal Degree Minutes Format
+ ///
+ ///
+ /// Example: N 40º 34" 36.552' W 70º 45" 24.408'
+ ///
+ Degree_Minutes_Seconds,
+ ///
+ /// Decimal Format
+ ///
+ ///
+ /// Example: 40.57674 -70.46574
+ ///
+ Decimal
+ }
}
diff --git a/CoordinateSharp/Coordinate.MGRS.cs b/CoordinateSharp/Coordinate.MGRS.cs
index d34c5f2..1ee22aa 100644
--- a/CoordinateSharp/Coordinate.MGRS.cs
+++ b/CoordinateSharp/Coordinate.MGRS.cs
@@ -1,293 +1,221 @@
using System;
-using System.Linq;
-using System.Diagnostics;
using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
-namespace CoordinateSharp
-{
+namespace CoordinateSharp {
+ ///
+ /// Military Grid Reference System (MGRS). Uses the WGS 84 Datum.
+ /// Relies upon values from the UniversalTransverseMercator class
+ ///
+ [Serializable]
+ public class MilitaryGridReferenceSystem : INotifyPropertyChanged {
///
- /// Military Grid Reference System (MGRS). Uses the WGS 84 Datum.
- /// Relies upon values from the UniversalTransverseMercator class
+ /// Create an MGRS object with WGS84 datum
///
- [Serializable]
- public class MilitaryGridReferenceSystem : INotifyPropertyChanged
- {
- ///
- /// Create an MGRS object with WGS84 datum
- ///
- /// Lat Zone
- /// Long Zone
- /// Digraph
- /// Easting
- /// Northing
- public MilitaryGridReferenceSystem(string latz, int longz, string d, double e, double n)
- {
- string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
- string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
- if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
- if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
- if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
- if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
- if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
- if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
- latZone = latz;
- longZone = longz;
- digraph = d;
- easting = e;
- northing = n;
- //WGS84
- equatorialRadius = 6378137.0;
- inverseFlattening = 298.257223563;
-
- }
- ///
- /// Create an MGRS object with custom datum
- ///
- /// Lat Zone
- /// Long Zone
- /// Digraph
- /// Easting
- /// Northing
- /// Equatorial Radius
- /// Inverse Flattening
- public MilitaryGridReferenceSystem(string latz, int longz, string d, double e, double n,double rad, double flt)
- {
- string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
- string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
- if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
- if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
- if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
- if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
- if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
- if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
- latZone = latz;
- longZone = longz;
- digraph = d;
- easting = e;
- northing = n;
-
- equatorialRadius = rad;
- inverseFlattening = flt;
- }
+ /// Lat Zone
+ /// Long Zone
+ /// Digraph
+ /// Easting
+ /// Northing
+ public MilitaryGridReferenceSystem(String latz, Int32 longz, String d, Double e, Double n) {
+ String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
+ String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
+ if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
+ if (!this.Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
+ if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
+ if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
+ if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
+ if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
+ this.LatZone = latz;
+ this.LongZone = longz;
+ this.Digraph = d;
+ this.Easting = e;
+ this.Northing = n;
+ //WGS84
+ this.equatorialRadius = 6378137.0;
+ this.inverseFlattening = 298.257223563;
- private double equatorialRadius;
- private double inverseFlattening;
- private string latZone;
- private int longZone;
- private double easting;
- private double northing;
- private string digraph;
-
- private bool withinCoordinateSystemBounds=true;
-
- private bool Verify_Lat_Zone(string l)
- {
- if (LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() != 1)
- {
- return false;
- }
- return true;
- }
-
-
- ///
- /// MGRS Zone Letter
- ///
- public string LatZone
- {
- get { return latZone; }
-
- }
- ///
- /// MGRS Zone Number
- ///
- public int LongZone
- {
- get { return longZone; }
-
- }
- ///
- /// MGRS Easting
- ///
- public double Easting
- {
- get { return easting; }
-
- }
- ///
- /// MGRS Northing
- ///
- public double Northing
- {
- get { return northing; }
-
- }
- ///
- /// MGRS Digraph
- ///
- public string Digraph
- {
- get { return digraph; }
- }
-
- ///
- /// Is MGRS conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
- ///
- public bool WithinCoordinateSystemBounds
- {
- get { return withinCoordinateSystemBounds; }
- }
-
-
- internal MilitaryGridReferenceSystem(UniversalTransverseMercator utm)
- {
- ToMGRS(utm);
- }
- internal void ToMGRS(UniversalTransverseMercator utm)
- {
- Digraphs digraphs = new Digraphs();
-
- string digraph1 = digraphs.getDigraph1(utm.LongZone, utm.Easting);
- string digraph2 = digraphs.getDigraph2(utm.LongZone, utm.Northing);
-
- digraph = digraph1 + digraph2;
- latZone = utm.LatZone;
- longZone = utm.LongZone;
-
- //String easting = String.valueOf((int)_easting);
- string e = ((int)utm.Easting).ToString();
- if (e.Length < 5)
- {
- e = "00000" + ((int)utm.Easting).ToString();
- }
- e = e.Substring(e.Length - 5);
-
- easting = Convert.ToInt32(e);
-
- string n = ((int)utm.Northing).ToString();
- if (n.Length < 5)
- {
- n = "0000" + ((int)utm.Northing).ToString();
- }
- n = n.Substring(n.Length - 5);
-
- northing = Convert.ToInt32(n);
- equatorialRadius = utm.equatorial_radius;
- inverseFlattening = utm.inverse_flattening;
-
- withinCoordinateSystemBounds = utm.WithinCoordinateSystemBounds;
- }
-
- ///
- /// Creates a Coordinate object from an MGRS/NATO UTM Coordinate
- ///
- /// MilitaryGridReferenceSystem
- /// Coordinate object
- public static Coordinate MGRStoLatLong(MilitaryGridReferenceSystem mgrs)
- {
- string latz = mgrs.LatZone;
- string digraph = mgrs.Digraph;
-
- char eltr = digraph[0];
- char nltr = digraph[1];
-
- string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
- string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
- string digraphLettersAll="";
- for (int lt = 1; lt < 25; lt++)
- {
- digraphLettersAll += "ABCDEFGHJKLMNPQRSTUV";
- }
-
- var eidx = digraphLettersE.IndexOf(eltr);
- var nidx = digraphLettersN.IndexOf(nltr);
- if (mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0))
- {
- nidx -= 5; // correction for even numbered zones
- }
-
- var ebase = 100000 * (1 + eidx - 8 * Math.Floor(Convert.ToDouble(eidx) / 8));
- var latBand = digraphLettersE.IndexOf(latz);
- var latBandLow = 8 * latBand - 96;
- var latBandHigh = 8 * latBand - 88;
-
- if (latBand < 2)
- {
- latBandLow = -90;
- latBandHigh = -80;
- }
- else if (latBand == 21)
- {
- latBandLow = 72;
- latBandHigh = 84;
- }
- else if (latBand > 21)
- {
- latBandLow = 84;
- latBandHigh = 90;
- }
-
- var lowLetter = Math.Floor(100 + 1.11 * latBandLow);
- var highLetter = Math.Round(100 + 1.11 * latBandHigh);
-
- string latBandLetters = null;
- int l = Convert.ToInt32(lowLetter);
- int h = Convert.ToInt32(highLetter);
- if (mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0))
- {
- latBandLetters = digraphLettersAll.Substring(l + 5, h + 5).ToString();
- }
- else
- {
- latBandLetters = digraphLettersAll.Substring(l, h).ToString();
- }
- var nbase = 100000 * (lowLetter + latBandLetters.IndexOf(nltr));
- //latBandLetters.IndexOf(nltr) value causing incorrect Northing below -80
- var x = ebase + mgrs.Easting;
- var y = nbase + mgrs.Northing;
- if (y > 10000000)
- {
- y = y - 10000000;
- }
- if (nbase >= 10000000)
- {
- y = nbase + mgrs.northing - 10000000;
- }
-
- var southern = nbase < 10000000;
- UniversalTransverseMercator utm = new UniversalTransverseMercator(mgrs.LatZone, mgrs.LongZone, x, y);
- utm.equatorial_radius = mgrs.equatorialRadius;
- utm.inverse_flattening = mgrs.inverseFlattening;
- Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
-
- c.Set_Datum(mgrs.equatorialRadius, mgrs.inverseFlattening);
-
- return c;
- }
-
- ///
- /// MGRS Default String Format
- ///
- /// MGRS Formatted Coordinate String
- public override string ToString()
- {
- if (!withinCoordinateSystemBounds) { return ""; }//MGRS Coordinate is outside its reliable boundaries. Return empty.
- return longZone.ToString() + LatZone + " " + digraph + " " + ((int)easting).ToString("00000") + " " + ((int)northing).ToString("00000");
- }
- ///
- /// Property changed event
- ///
- public event PropertyChangedEventHandler PropertyChanged;
- ///
- /// Notify property changed
- ///
- /// Property name
- public void NotifyPropertyChanged(string propName)
- {
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propName));
- }
- }
}
+ ///
+ /// Create an MGRS object with custom datum
+ ///
+ /// Lat Zone
+ /// Long Zone
+ /// Digraph
+ /// Easting
+ /// Northing
+ /// Equatorial Radius
+ /// Inverse Flattening
+ public MilitaryGridReferenceSystem(String latz, Int32 longz, String d, Double e, Double n, Double rad, Double flt) {
+ String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
+ String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
+ if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
+ if (!this.Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
+ if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
+ if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
+ if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
+ if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
+ this.LatZone = latz;
+ this.LongZone = longz;
+ this.Digraph = d;
+ this.Easting = e;
+ this.Northing = n;
+
+ this.equatorialRadius = rad;
+ this.inverseFlattening = flt;
+ }
+
+ private Double equatorialRadius;
+ private Double inverseFlattening;
+
+ private Boolean Verify_Lat_Zone(String l) => LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() == 1;
+
+
+ ///
+ /// MGRS Zone Letter
+ ///
+ public String LatZone { get; private set; }
+ ///
+ /// MGRS Zone Number
+ ///
+ public Int32 LongZone { get; private set; }
+ ///
+ /// MGRS Easting
+ ///
+ public Double Easting { get; private set; }
+ ///
+ /// MGRS Northing
+ ///
+ public Double Northing { get; private set; }
+ ///
+ /// MGRS Digraph
+ ///
+ public String Digraph { get; private set; }
+
+ ///
+ /// Is MGRS conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
+ ///
+ public Boolean WithinCoordinateSystemBounds { get; private set; } = true;
+
+
+ internal MilitaryGridReferenceSystem(UniversalTransverseMercator utm) => this.ToMGRS(utm);
+ internal void ToMGRS(UniversalTransverseMercator utm) {
+ Digraphs digraphs = new Digraphs();
+
+ String digraph1 = digraphs.GetDigraph1(utm.LongZone, utm.Easting);
+ String digraph2 = digraphs.GetDigraph2(utm.LongZone, utm.Northing);
+
+ this.Digraph = digraph1 + digraph2;
+ this.LatZone = utm.LatZone;
+ this.LongZone = utm.LongZone;
+
+ //String easting = String.valueOf((int)_easting);
+ String e = ((Int32)utm.Easting).ToString();
+ if (e.Length < 5) {
+ e = "00000" + ((Int32)utm.Easting).ToString();
+ }
+ e = e.Substring(e.Length - 5);
+
+ this.Easting = Convert.ToInt32(e);
+
+ String n = ((Int32)utm.Northing).ToString();
+ if (n.Length < 5) {
+ n = "0000" + ((Int32)utm.Northing).ToString();
+ }
+ n = n.Substring(n.Length - 5);
+
+ this.Northing = Convert.ToInt32(n);
+ this.equatorialRadius = utm.equatorial_radius;
+ this.inverseFlattening = utm.inverse_flattening;
+
+ this.WithinCoordinateSystemBounds = utm.WithinCoordinateSystemBounds;
+ }
+
+ ///
+ /// Creates a Coordinate object from an MGRS/NATO UTM Coordinate
+ ///
+ /// MilitaryGridReferenceSystem
+ /// Coordinate object
+ public static Coordinate MGRStoLatLong(MilitaryGridReferenceSystem mgrs) {
+ String latz = mgrs.LatZone;
+ String digraph = mgrs.Digraph;
+
+ Char eltr = digraph[0];
+ Char nltr = digraph[1];
+
+ String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
+ //String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
+ String digraphLettersAll = "";
+ for (Int32 lt = 1; lt < 25; lt++) {
+ digraphLettersAll += "ABCDEFGHJKLMNPQRSTUV";
+ }
+
+ Int32 eidx = digraphLettersE.IndexOf(eltr);
+ //Int32 nidx = digraphLettersN.IndexOf(nltr);
+ if (mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0)) {
+ //nidx -= 5; // correction for even numbered zones
+ }
+
+ Double ebase = 100000 * (1 + eidx - 8 * Math.Floor(Convert.ToDouble(eidx) / 8));
+ Int32 latBand = digraphLettersE.IndexOf(latz);
+ Int32 latBandLow = 8 * latBand - 96;
+ Int32 latBandHigh = 8 * latBand - 88;
+
+ if (latBand < 2) {
+ latBandLow = -90;
+ latBandHigh = -80;
+ } else if (latBand == 21) {
+ latBandLow = 72;
+ latBandHigh = 84;
+ } else if (latBand > 21) {
+ latBandLow = 84;
+ latBandHigh = 90;
+ }
+
+ Double lowLetter = Math.Floor(100 + 1.11 * latBandLow);
+ Double highLetter = Math.Round(100 + 1.11 * latBandHigh);
+ Int32 l = Convert.ToInt32(lowLetter);
+ Int32 h = Convert.ToInt32(highLetter);
+
+ String latBandLetters = mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0) ? digraphLettersAll.Substring(l + 5, h + 5).ToString() : digraphLettersAll.Substring(l, h).ToString();
+ Double nbase = 100000 * (lowLetter + latBandLetters.IndexOf(nltr));
+ //latBandLetters.IndexOf(nltr) value causing incorrect Northing below -80
+ Double x = ebase + mgrs.Easting;
+ Double y = nbase + mgrs.Northing;
+ if (y > 10000000) {
+ y -= 10000000;
+ }
+ if (nbase >= 10000000) {
+ y = nbase + mgrs.Northing - 10000000;
+ }
+
+ _ = nbase < 10000000;
+ UniversalTransverseMercator utm = new UniversalTransverseMercator(mgrs.LatZone, mgrs.LongZone, x, y) {
+ equatorial_radius = mgrs.equatorialRadius,
+ inverse_flattening = mgrs.inverseFlattening
+ };
+ Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
+
+ c.Set_Datum(mgrs.equatorialRadius, mgrs.inverseFlattening);
+
+ return c;
+ }
+
+ ///
+ /// MGRS Default String Format
+ ///
+ /// MGRS Formatted Coordinate String
+ public override String ToString() => !this.WithinCoordinateSystemBounds ? "" : this.LongZone.ToString() + this.LatZone + " " + this.Digraph + " " + ((Int32)this.Easting).ToString("00000") + " " + ((Int32)this.Northing).ToString("00000");
+ //MGRS Coordinate is outside its reliable boundaries. Return empty.
+ ///
+ /// Property changed event
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+ ///
+ /// Notify property changed
+ ///
+ /// Property name
+ public void NotifyPropertyChanged(String propName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
+ }
}
diff --git a/CoordinateSharp/Coordinate.Parser.cs b/CoordinateSharp/Coordinate.Parser.cs
index 21daad0..f698213 100644
--- a/CoordinateSharp/Coordinate.Parser.cs
+++ b/CoordinateSharp/Coordinate.Parser.cs
@@ -1,925 +1,722 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Text;
using System.Text.RegularExpressions;
-namespace CoordinateSharp
-{
+
+namespace CoordinateSharp {
+ ///
+ /// Type of format a Coordinate parsed from.
+ ///
+ [Serializable]
+ public enum Parse_Format_Type {
///
- /// Type of format a Coordinate parsed from.
+ /// Coordinate was not initialized from a parser method.
///
- [Serializable]
- public enum Parse_Format_Type
- {
- ///
- /// Coordinate was not initialized from a parser method.
- ///
- None,
- ///
- /// Signed Degree
- /// DD.dddd
- ///
- Signed_Degree,
- ///
- /// Decimal Degree
- /// P DD.dddd
- ///
- Decimal_Degree,
- ///
- /// Degree Decimal Minute
- /// P DD MM.sss
- ///
- Degree_Decimal_Minute,
- ///
- /// Degree Minute Second
- /// P DD MM SS.sss
- ///
- Degree_Minute_Second,
- ///
- /// Universal Transverse Mercator
- ///
- UTM,
- ///
- /// Military Grid Reference System
- ///
- MGRS,
- ///
- /// Spherical Cartesian
- ///
- Cartesian_Spherical,
- ///
- /// Earth Centered Earth Fixed
- ///
- Cartesian_ECEF
+ None,
+ ///
+ /// Signed Degree
+ /// DD.dddd
+ ///
+ Signed_Degree,
+ ///
+ /// Decimal Degree
+ /// P DD.dddd
+ ///
+ Decimal_Degree,
+ ///
+ /// Degree Decimal Minute
+ /// P DD MM.sss
+ ///
+ Degree_Decimal_Minute,
+ ///
+ /// Degree Minute Second
+ /// P DD MM SS.sss
+ ///
+ Degree_Minute_Second,
+ ///
+ /// Universal Transverse Mercator
+ ///
+ UTM,
+ ///
+ /// Military Grid Reference System
+ ///
+ MGRS,
+ ///
+ /// Spherical Cartesian
+ ///
+ Cartesian_Spherical,
+ ///
+ /// Earth Centered Earth Fixed
+ ///
+ Cartesian_ECEF
+ }
+
+ internal class FormatFinder {
+ //Add main to Coordinate and tunnel to Format class. Add private methods to format.
+ //WHEN PARSING NO EXCPETIONS FOR OUT OF RANGE ARGS WILL BE THROWN
+ public static Boolean TryParse(String coordString, CartesianType ct, out Coordinate c) {
+ //Turn of eagerload for efficiency
+ EagerLoad eg = new EagerLoad {
+ Cartesian = false,
+ Celestial = false,
+ UTM_MGRS = false
+ };
+
+ _ = new Coordinate(eg);
+ String s = coordString;
+ s = s.Trim(); //Trim all spaces before and after string
+ //Try Signed Degree
+ if (TrySignedDegree(s, out Double[] d)) {
+ try {
+ c = new Coordinate(d[0], d[1], eg) {
+ Parse_Format = Parse_Format_Type.Signed_Degree
+ };
+ return true;
+ } catch {//Parser failed try next method
+ }
+ }
+
+ //Try Decimal Degree
+ if (TryDecimalDegree(s, out d)) {
+ try {
+ c = new Coordinate(d[0], d[1], eg) {
+ Parse_Format = Parse_Format_Type.Decimal_Degree
+ };
+ return true;
+ } catch {//Parser failed try next method
+ }
+ }
+ //Try DDM
+ if (TryDegreeDecimalMinute(s, out d)) {
+ try {
+ //0 Lat Degree
+ //1 Lat Minute
+ //2 Lat Direction (0 = N, 1 = S)
+ //3 Long Degree
+ //4 Long Minute
+ //5 Long Direction (0 = E, 1 = W)
+ CoordinatesPosition latP = CoordinatesPosition.N;
+ CoordinatesPosition lngP = CoordinatesPosition.E;
+ if (d[2] != 0) { latP = CoordinatesPosition.S; }
+ if (d[5] != 0) { lngP = CoordinatesPosition.W; }
+ CoordinatePart lat = new CoordinatePart((Int32)d[0], d[1], latP);
+ CoordinatePart lng = new CoordinatePart((Int32)d[3], d[4], lngP);
+ c = new Coordinate(eg) {
+ Latitude = lat,
+ Longitude = lng,
+ Parse_Format = Parse_Format_Type.Degree_Decimal_Minute
+ };
+ return true;
+ } catch {//Parser failed try next method
+ }
+ }
+ //Try DMS
+ if (TryDegreeMinuteSecond(s, out d)) {
+ try {
+ //0 Lat Degree
+ //1 Lat Minute
+ //2 Lat Second
+ //3 Lat Direction (0 = N, 1 = S)
+ //4 Long Degree
+ //5 Long Minute
+ //6 Long Second
+ //7 Long Direction (0 = E, 1 = W)
+ CoordinatesPosition latP = CoordinatesPosition.N;
+ CoordinatesPosition lngP = CoordinatesPosition.E;
+ if (d[3] != 0) { latP = CoordinatesPosition.S; }
+ if (d[7] != 0) { lngP = CoordinatesPosition.W; }
+
+ CoordinatePart lat = new CoordinatePart((Int32)d[0], (Int32)d[1], d[2], latP);
+ CoordinatePart lng = new CoordinatePart((Int32)d[4], (Int32)d[5], d[6], lngP);
+ c = new Coordinate(eg) {
+ Latitude = lat,
+ Longitude = lng,
+ Parse_Format = Parse_Format_Type.Degree_Minute_Second
+ };
+ return true;
+ } catch {//Parser failed try next method
+ }
+ }
+
+ //Try MGRS
+ if (TryMGRS(s, out String[] um)) {
+ try {
+ Double zone = Convert.ToDouble(um[0]);
+ Double easting = Convert.ToDouble(um[3]);
+ Double northing = Convert.ToDouble(um[4]);
+ MilitaryGridReferenceSystem mgrs = new MilitaryGridReferenceSystem(um[1], (Int32)zone, um[2], easting, northing);
+ c = MilitaryGridReferenceSystem.MGRStoLatLong(mgrs);
+ c.Parse_Format = Parse_Format_Type.MGRS;
+ return true;
+ } catch {//Parser failed try next method
+ }
+ }
+ //Try UTM
+ if (TryUTM(s, out um)) {
+ try {
+ Double zone = Convert.ToDouble(um[0]);
+ Double easting = Convert.ToDouble(um[2]);
+ Double northing = Convert.ToDouble(um[3]);
+ UniversalTransverseMercator utm = new UniversalTransverseMercator(um[1], (Int32)zone, easting, northing);
+ c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
+ c.Parse_Format = Parse_Format_Type.UTM;
+ return true;
+ } catch {//Parser failed try next method
+ }
+ }
+ //Try Cartesian
+ if (TryCartesian(s.ToUpper().Replace("KM", "").Replace("X", "").Replace("Y", "").Replace("Z", ""), out d)) {
+ if (ct == CartesianType.Cartesian) {
+ try {
+ Cartesian cart = new Cartesian(d[0], d[1], d[2]);
+ c = Cartesian.CartesianToLatLong(cart);
+ c.Parse_Format = Parse_Format_Type.Cartesian_Spherical;
+ return true;
+ } catch {//Parser failed try next method
+ }
+ }
+ if (ct == CartesianType.ECEF) {
+ try {
+ ECEF ecef = new ECEF(d[0], d[1], d[2]);
+ c = ECEF.ECEFToLatLong(ecef);
+ c.Parse_Format = Parse_Format_Type.Cartesian_ECEF;
+ return true;
+ } catch {//Parser failed try next method
+ }
+ }
+ }
+
+ c = null;
+ return false;
+ }
+ private static Boolean TrySignedDegree(String s, out Double[] d) {
+ d = null;
+ if (Regex.Matches(s, @"[a-zA-Z]").Count != 0) { return false; } //Should contain no letters
+
+ String[] sA = SpecialSplit(s, false);
+ Double lat;
+ Double lng;
+
+ Double degLat;
+ Double minLat; //Minutes & MinSeconds
+ Double secLat;
+
+ Int32 signLat = 1;
+
+ Double degLng;
+ Double minLng; //Minutes & MinSeconds
+ Double secLng;
+
+ Int32 signLng = 1;
+
+ switch (sA.Count()) {
+ case 2:
+ if (!Double.TryParse(sA[0], out lat)) { return false; }
+ if (!Double.TryParse(sA[1], out lng)) { return false; }
+ d = new Double[] { lat, lng };
+ return true;
+ case 4:
+ if (!Double.TryParse(sA[0], out degLat)) { return false; }
+ if (!Double.TryParse(sA[1], out minLat)) { return false; }
+ if (!Double.TryParse(sA[2], out degLng)) { return false; }
+ if (!Double.TryParse(sA[3], out minLng)) { return false; }
+
+ if (degLat < 0) { signLat = -1; }
+ if (degLng < 0) { signLng = -1; }
+ if (minLat >= 60 || minLat < 0) { return false; } //Handle in parser as degree will be incorrect.
+ if (minLng >= 60 || minLng < 0) { return false; } //Handle in parser as degree will be incorrect.
+ lat = (Math.Abs(degLat) + minLat / 60.0) * signLat;
+ lng = (Math.Abs(degLng) + minLng / 60.0) * signLng;
+ d = new Double[] { lat, lng };
+ return true;
+ case 6:
+ if (!Double.TryParse(sA[0], out degLat)) { return false; }
+ if (!Double.TryParse(sA[1], out minLat)) { return false; }
+ if (!Double.TryParse(sA[2], out secLat)) { return false; }
+ if (!Double.TryParse(sA[3], out degLng)) { return false; }
+ if (!Double.TryParse(sA[4], out minLng)) { return false; }
+ if (!Double.TryParse(sA[5], out secLng)) { return false; }
+ if (degLat < 0) { signLat = -1; }
+ if (degLng < 0) { signLng = -1; }
+ if (minLat >= 60 || minLat < 0) { return false; } //Handle in parser as degree will be incorrect.
+ if (minLng >= 60 || minLng < 0) { return false; } //Handle in parser as degree will be incorrect.
+ if (secLat >= 60 || secLat < 0) { return false; } //Handle in parser as degree will be incorrect.
+ if (secLng >= 60 || secLng < 0) { return false; } //Handle in parser as degree will be incorrect.
+ lat = (Math.Abs(degLat) + minLat / 60.0 + secLat / 3600) * signLat;
+ lng = (Math.Abs(degLng) + minLng / 60.0 + secLng / 3600) * signLng;
+ d = new Double[] { lat, lng };
+ return true;
+ default:
+ return false;
+ }
+ }
+ private static Boolean TryDecimalDegree(String s, out Double[] d) {
+ d = null;
+ if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
+
+ String[] sA = SpecialSplit(s, true);
+ if (sA.Count() == 2 || sA.Count() == 4) {
+
+ Double latR = 1; //Sets negative if South
+ Double lngR = 1; //Sets negative if West
+
+ //Contact get brin directional indicator together with string
+ if (sA.Count() == 4) {
+ sA[0] += sA[1];
+ sA[1] = sA[2] + sA[3];
+ }
+
+ //Find Directions
+ if (!sA[0].Contains("N") && !sA[0].Contains("n")) {
+ if (!sA[0].Contains("S") && !sA[0].Contains("s")) {
+ return false;//No Direction Found
+ }
+ latR = -1;
+ }
+ if (!sA[1].Contains("E") && !sA[1].Contains("e")) {
+ if (!sA[1].Contains("W") && !sA[1].Contains("w")) {
+ return false;//No Direction Found
+ }
+ lngR = -1;
+ }
+
+ sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
+ sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
+
+ if (!Double.TryParse(sA[0], out Double lat)) { return false; }
+ if (!Double.TryParse(sA[1], out Double lng)) { return false; }
+ lat *= latR;
+ lng *= lngR;
+ d = new Double[] { lat, lng };
+ return true;
+ }
+
+ return false;
+ }
+ private static Boolean TryDegreeDecimalMinute(String s, out Double[] d) {
+ d = null;
+ if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
+
+ String[] sA = SpecialSplit(s, true);
+ if (sA.Count() == 4 || sA.Count() == 6) {
+
+ Double latR = 0; //Sets 1 if South
+ Double lngR = 0; //Sets 1 if West
+
+ //Contact get in order to combine directional indicator together with string
+ //Should reduce 6 items to 4
+ if (sA.Count() == 6) {
+ if (Char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; } else if (Char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; } else if (Char.IsLetter(sA[2][0])) { sA[0] += sA[2]; } else { return false; }
+
+ if (Char.IsLetter(sA[3][0])) { sA[3] += sA[4]; sA[4] = sA[5]; } else if (Char.IsLetter(sA[4][0])) { sA[3] += sA[4]; sA[4] = sA[5]; } else if (Char.IsLetter(sA[5][0])) { sA[3] += sA[5]; } else { return false; }
+
+ //Shift values for below logic
+ sA[2] = sA[3];
+ sA[3] = sA[4];
+ }
+
+ //Find Directions
+ if (!sA[0].Contains("N") && !sA[0].Contains("n") && !sA[1].Contains("N") && !sA[1].Contains("n")) {
+ if (!sA[0].Contains("S") && !sA[0].Contains("s") && !sA[1].Contains("S") && !sA[1].Contains("s")) {
+ return false;//No Direction Found
+ }
+ latR = 1;
+ }
+ if (!sA[2].Contains("E") && !sA[2].Contains("e") && !sA[3].Contains("E") && !sA[3].Contains("e")) {
+ if (!sA[2].Contains("W") && !sA[2].Contains("w") && !sA[3].Contains("W") && !sA[3].Contains("w")) {
+ return false;//No Direction Found
+ }
+ lngR = 1;
+ }
+
+ sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
+ sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
+ sA[2] = Regex.Replace(sA[2], "[^0-9.]", "");
+ sA[3] = Regex.Replace(sA[3], "[^0-9.]", "");
+
+ if (!Double.TryParse(sA[0], out Double latD)) { return false; }
+ if (!Double.TryParse(sA[1], out Double latMS)) { return false; }
+ if (!Double.TryParse(sA[2], out Double lngD)) { return false; }
+ if (!Double.TryParse(sA[3], out Double lngMS)) { return false; }
+
+ d = new Double[] { latD, latMS, latR, lngD, lngMS, lngR };
+ return true;
+ }
+ return false;
+ }
+ private static Boolean TryDegreeMinuteSecond(String s, out Double[] d) {
+ d = null;
+ if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
+
+ String[] sA = SpecialSplit(s, true);
+ if (sA.Count() == 6 || sA.Count() == 8) {
+
+ Double latR = 0; //Sets 1 if South
+ Double lngR = 0; //Sets 1 if West
+
+ //Contact get in order to combine directional indicator together with string
+ //Should reduce 8 items to 6
+ if (sA.Count() == 8) {
+ if (Char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; } else if (Char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; } else if (Char.IsLetter(sA[3][0])) { sA[0] += sA[3]; } else { return false; }
+
+ if (Char.IsLetter(sA[4][0])) { sA[4] += sA[5]; sA[5] = sA[6]; sA[6] = sA[7]; } else if (Char.IsLetter(sA[5][0])) { sA[4] += sA[5]; sA[5] = sA[6]; sA[6] = sA[7]; } else if (Char.IsLetter(sA[7][0])) { sA[4] += sA[7]; } else { return false; }
+
+ //Shift values for below logic
+ sA[3] = sA[4];
+ sA[4] = sA[5];
+ sA[5] = sA[6];
+ }
+
+ //Find Directions
+ if (!sA[0].Contains("N") && !sA[0].Contains("n") && !sA[2].Contains("N") && !sA[2].Contains("n")) {
+ if (!sA[0].Contains("S") && !sA[0].Contains("s") && !sA[2].Contains("S") && !sA[2].Contains("s")) {
+ return false;//No Direction Found
+ }
+ latR = 1;
+ }
+ if (!sA[3].Contains("E") && !sA[3].Contains("e") && !sA[5].Contains("E") && !sA[5].Contains("e")) {
+ if (!sA[3].Contains("W") && !sA[3].Contains("w") && !sA[5].Contains("W") && !sA[5].Contains("w")) {
+ return false;//No Direction Found
+ }
+ lngR = 1;
+ }
+ sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
+ sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
+ sA[2] = Regex.Replace(sA[2], "[^0-9.]", "");
+ sA[3] = Regex.Replace(sA[3], "[^0-9.]", "");
+ sA[4] = Regex.Replace(sA[4], "[^0-9.]", "");
+ sA[5] = Regex.Replace(sA[5], "[^0-9.]", "");
+
+ if (!Double.TryParse(sA[0], out Double latD)) { return false; }
+ if (!Double.TryParse(sA[1], out Double latM)) { return false; }
+ if (!Double.TryParse(sA[2], out Double latS)) { return false; }
+ if (!Double.TryParse(sA[3], out Double lngD)) { return false; }
+ if (!Double.TryParse(sA[4], out Double lngM)) { return false; }
+ if (!Double.TryParse(sA[5], out Double lngS)) { return false; }
+
+ d = new Double[] { latD, latM, latS, latR, lngD, lngM, lngS, lngR };
+ return true;
+ }
+ return false;
+ }
+ private static Boolean TryUTM(String s, out String[] utm) {
+ utm = null;
+ String[] sA = SpecialSplit(s, false);
+ if (sA.Count() == 3 || sA.Count() == 4) {
+ String zoneL;
+
+ if (sA.Count() == 4) {
+
+ if (Char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; } else if (Char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; } else { return false; }
+ }
+ zoneL = new String(sA[0].Where(Char.IsLetter).ToArray());
+ if (zoneL == String.Empty) { return false; }
+ sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
+
+ if (!Double.TryParse(sA[0], out Double zone)) { return false; }
+ if (!Double.TryParse(sA[1], out Double easting)) { return false; }
+ if (!Double.TryParse(sA[2], out Double northing)) { return false; }
+
+ utm = new String[] { zone.ToString(), zoneL, easting.ToString(), northing.ToString() };
+ return true;
+ }
+ return false;
+ }
+ private static Boolean TryMGRS(String s, out String[] mgrs) {
+ mgrs = null;
+ String[] sA = SpecialSplit(s, false);
+ if (sA.Count() == 4 || sA.Count() == 5) {
+ String zoneL;
+ String diagraph;
+
+ if (sA.Count() == 5) {
+ if (Char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; } else if (Char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; } else { return false; }
+ }
+ zoneL = new String(sA[0].Where(Char.IsLetter).ToArray());
+ if (zoneL == String.Empty) { return false; }
+ sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
+ diagraph = sA[1];
+ if (!Double.TryParse(sA[0], out Double zone)) { return false; }
+ if (!Double.TryParse(sA[2], out Double easting)) { return false; }
+ if (!Double.TryParse(sA[3], out Double northing)) { return false; }
+
+ mgrs = new String[] { zone.ToString(), zoneL, diagraph, easting.ToString(), northing.ToString() };
+ return true;
+ }
+ return false;
+ }
+ private static Boolean TryCartesian(String s, out Double[] d) {
+ d = null;
+ String[] sA = SpecialSplit(s, false);
+
+ if (sA.Count() == 3) {
+ if (!Double.TryParse(sA[0], out Double x)) { return false; }
+ if (!Double.TryParse(sA[1], out Double y)) { return false; }
+ if (!Double.TryParse(sA[2], out Double z)) { return false; }
+ d = new Double[] { x, y, z };
+ return true;
+ }
+ return false;
}
- internal class FormatFinder
- {
- //Add main to Coordinate and tunnel to Format class. Add private methods to format.
- //WHEN PARSING NO EXCPETIONS FOR OUT OF RANGE ARGS WILL BE THROWN
- public static bool TryParse(string coordString, CartesianType ct, out Coordinate c)
- {
- //Turn of eagerload for efficiency
- EagerLoad eg = new EagerLoad();
- eg.Cartesian = false;
- eg.Celestial = false;
- eg.UTM_MGRS = false;
-
- c = new Coordinate(eg);
- string s = coordString;
- s = s.Trim(); //Trim all spaces before and after string
- double[] d;
- //Try Signed Degree
- if (TrySignedDegree(s, out d))
- {
- try
- {
- c = new Coordinate(d[0], d[1], eg);
- c.Parse_Format = Parse_Format_Type.Signed_Degree;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
-
- //Try Decimal Degree
- if (TryDecimalDegree(s, out d))
- {
- try
- {
- c = new Coordinate(d[0], d[1], eg);
- c.Parse_Format = Parse_Format_Type.Decimal_Degree;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
- //Try DDM
- if (TryDegreeDecimalMinute(s, out d))
- {
- try
- {
- //0 Lat Degree
- //1 Lat Minute
- //2 Lat Direction (0 = N, 1 = S)
- //3 Long Degree
- //4 Long Minute
- //5 Long Direction (0 = E, 1 = W)
- CoordinatesPosition latP = CoordinatesPosition.N;
- CoordinatesPosition lngP = CoordinatesPosition.E;
- if (d[2] != 0) { latP = CoordinatesPosition.S; }
- if (d[5] != 0) { lngP = CoordinatesPosition.W; }
- CoordinatePart lat = new CoordinatePart((int)d[0], d[1], latP);
- CoordinatePart lng = new CoordinatePart((int)d[3], d[4], lngP);
- c = new Coordinate(eg);
- c.Latitude = lat;
- c.Longitude = lng;
- c.Parse_Format = Parse_Format_Type.Degree_Decimal_Minute;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
- //Try DMS
- if (TryDegreeMinuteSecond(s, out d))
- {
- try
- {
- //0 Lat Degree
- //1 Lat Minute
- //2 Lat Second
- //3 Lat Direction (0 = N, 1 = S)
- //4 Long Degree
- //5 Long Minute
- //6 Long Second
- //7 Long Direction (0 = E, 1 = W)
- CoordinatesPosition latP = CoordinatesPosition.N;
- CoordinatesPosition lngP = CoordinatesPosition.E;
- if (d[3] != 0) { latP = CoordinatesPosition.S; }
- if (d[7] != 0) { lngP = CoordinatesPosition.W; }
-
- CoordinatePart lat = new CoordinatePart((int)d[0], (int)d[1], d[2], latP);
- CoordinatePart lng = new CoordinatePart((int)d[4], (int)d[5], d[6], lngP);
- c = new Coordinate(eg);
- c.Latitude = lat;
- c.Longitude = lng;
- c.Parse_Format = Parse_Format_Type.Degree_Minute_Second;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
-
- string[] um;
- //Try MGRS
- if (TryMGRS(s, out um))
- {
- try
- {
- double zone = Convert.ToDouble(um[0]);
- double easting = Convert.ToDouble(um[3]);
- double northing = Convert.ToDouble(um[4]);
- MilitaryGridReferenceSystem mgrs = new MilitaryGridReferenceSystem(um[1], (int)zone, um[2], easting, northing);
- c = MilitaryGridReferenceSystem.MGRStoLatLong(mgrs);
- c.Parse_Format = Parse_Format_Type.MGRS;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
- //Try UTM
- if (TryUTM(s, out um))
- {
- try
- {
- double zone = Convert.ToDouble(um[0]);
- double easting = Convert.ToDouble(um[2]);
- double northing = Convert.ToDouble(um[3]);
- UniversalTransverseMercator utm = new UniversalTransverseMercator(um[1], (int)zone, easting, northing);
- c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
- c.Parse_Format = Parse_Format_Type.UTM;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
- //Try Cartesian
- if (TryCartesian(s.ToUpper().Replace("KM", "").Replace("X","").Replace("Y", "").Replace("Z", ""), out d))
- {
- if (ct == CartesianType.Cartesian)
- {
- try
- {
- Cartesian cart = new Cartesian(d[0], d[1], d[2]);
- c = Cartesian.CartesianToLatLong(cart);
- c.Parse_Format = Parse_Format_Type.Cartesian_Spherical;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
- if (ct == CartesianType.ECEF)
- {
- try
- {
- ECEF ecef = new ECEF(d[0], d[1], d[2]);
- c = ECEF.ECEFToLatLong(ecef);
- c.Parse_Format = Parse_Format_Type.Cartesian_ECEF;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
- }
-
- c = null;
- return false;
- }
- private static bool TrySignedDegree(string s, out double[] d)
- {
- d = null;
- if (Regex.Matches(s, @"[a-zA-Z]").Count != 0) { return false; } //Should contain no letters
-
- string[] sA = SpecialSplit(s,false);
- double lat;
- double lng;
-
- double degLat;
- double minLat; //Minutes & MinSeconds
- double secLat;
-
- int signLat = 1;
-
- double degLng;
- double minLng; //Minutes & MinSeconds
- double secLng;
-
- int signLng = 1;
-
- switch (sA.Count())
- {
- case 2:
- if (!double.TryParse(sA[0], out lat))
- { return false; }
- if (!double.TryParse(sA[1], out lng))
- { return false; }
- d = new double[] { lat, lng };
- return true;
- case 4:
- if (!double.TryParse(sA[0], out degLat))
- { return false; }
- if (!double.TryParse(sA[1], out minLat))
- { return false; }
- if (!double.TryParse(sA[2], out degLng))
- { return false; }
- if (!double.TryParse(sA[3], out minLng))
- { return false; }
-
- if (degLat < 0) { signLat = -1; }
- if (degLng < 0) { signLng = -1; }
- if (minLat >= 60 || minLat < 0) { return false; } //Handle in parser as degree will be incorrect.
- if (minLng >= 60 || minLng < 0) { return false; } //Handle in parser as degree will be incorrect.
- lat = (Math.Abs(degLat) + (minLat / 60.0)) * signLat;
- lng = (Math.Abs(degLng) + (minLng / 60.0)) * signLng;
- d = new double[] { lat, lng };
- return true;
- case 6:
- if (!double.TryParse(sA[0], out degLat))
- { return false; }
- if (!double.TryParse(sA[1], out minLat))
- { return false; }
- if (!double.TryParse(sA[2], out secLat))
- { return false; }
- if (!double.TryParse(sA[3], out degLng))
- { return false; }
- if (!double.TryParse(sA[4], out minLng))
- { return false; }
- if (!double.TryParse(sA[5], out secLng))
- { return false; }
- if (degLat < 0) { signLat = -1; }
- if (degLng < 0) { signLng = -1; }
- if (minLat >= 60 || minLat < 0) { return false; } //Handle in parser as degree will be incorrect.
- if (minLng >= 60 || minLng < 0) { return false; } //Handle in parser as degree will be incorrect.
- if (secLat >= 60 || secLat < 0) { return false; } //Handle in parser as degree will be incorrect.
- if (secLng >= 60 || secLng < 0) { return false; } //Handle in parser as degree will be incorrect.
- lat = (Math.Abs(degLat) + (minLat / 60.0) + (secLat / 3600)) * signLat;
- lng = (Math.Abs(degLng) + (minLng / 60.0) + (secLng / 3600)) * signLng;
- d = new double[] { lat, lng };
- return true;
- default:
- return false;
- }
- }
- private static bool TryDecimalDegree(string s, out double[] d)
- {
- d = null;
- if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
-
- string[] sA = SpecialSplit(s,true);
- if (sA.Count() == 2 || sA.Count() == 4)
- {
- double lat;
- double lng;
-
- double latR = 1; //Sets negative if South
- double lngR = 1; //Sets negative if West
-
- //Contact get brin directional indicator together with string
- if (sA.Count() == 4)
- {
- sA[0] += sA[1];
- sA[1] = sA[2] + sA[3];
- }
-
- //Find Directions
- if (!sA[0].Contains("N") && !sA[0].Contains("n"))
- {
- if (!sA[0].Contains("S") && !sA[0].Contains("s"))
- {
- return false;//No Direction Found
- }
- latR = -1;
- }
- if (!sA[1].Contains("E") && !sA[1].Contains("e"))
- {
- if (!sA[1].Contains("W") && !sA[1].Contains("w"))
- {
- return false;//No Direction Found
- }
- lngR = -1;
- }
-
- sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
- sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
-
- if (!double.TryParse(sA[0], out lat))
- { return false; }
- if (!double.TryParse(sA[1], out lng))
- { return false; }
- lat *= latR;
- lng *= lngR;
- d = new double[] { lat, lng };
- return true;
- }
-
- return false;
- }
- private static bool TryDegreeDecimalMinute(string s, out double[] d)
- {
- d = null;
- if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
-
- string[] sA = SpecialSplit(s,true);
- if (sA.Count() == 4 || sA.Count() == 6)
- {
- double latD;
- double latMS;
- double lngD;
- double lngMS;
-
- double latR = 0; //Sets 1 if South
- double lngR = 0; //Sets 1 if West
-
- //Contact get in order to combine directional indicator together with string
- //Should reduce 6 items to 4
- if (sA.Count() == 6)
- {
- if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; }
- else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; }
- else if (char.IsLetter(sA[2][0])) { sA[0] += sA[2]; }
- else { return false; }
-
- if (char.IsLetter(sA[3][0])) { sA[3] += sA[4]; sA[4] = sA[5]; }
- else if (char.IsLetter(sA[4][0])) { sA[3] += sA[4]; sA[4] = sA[5]; }
- else if (char.IsLetter(sA[5][0])) { sA[3] += sA[5]; }
- else { return false; }
-
- //Shift values for below logic
- sA[2] = sA[3];
- sA[3] = sA[4];
- }
-
- //Find Directions
- if (!sA[0].Contains("N") && !sA[0].Contains("n") && !sA[1].Contains("N") && !sA[1].Contains("n"))
- {
- if (!sA[0].Contains("S") && !sA[0].Contains("s") && !sA[1].Contains("S") && !sA[1].Contains("s"))
- {
- return false;//No Direction Found
- }
- latR = 1;
- }
- if (!sA[2].Contains("E") && !sA[2].Contains("e") && !sA[3].Contains("E") && !sA[3].Contains("e"))
- {
- if (!sA[2].Contains("W") && !sA[2].Contains("w") && !sA[3].Contains("W") && !sA[3].Contains("w"))
- {
- return false;//No Direction Found
- }
- lngR = 1;
- }
-
- sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
- sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
- sA[2] = Regex.Replace(sA[2], "[^0-9.]", "");
- sA[3] = Regex.Replace(sA[3], "[^0-9.]", "");
-
- if (!double.TryParse(sA[0], out latD))
- { return false; }
- if (!double.TryParse(sA[1], out latMS))
- { return false; }
- if (!double.TryParse(sA[2], out lngD))
- { return false; }
- if (!double.TryParse(sA[3], out lngMS))
- { return false; }
-
- d = new double[] { latD, latMS, latR, lngD, lngMS, lngR };
- return true;
- }
- return false;
- }
- private static bool TryDegreeMinuteSecond(string s, out double[] d)
- {
- d = null;
- if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
-
- string[] sA = SpecialSplit(s,true);
- if (sA.Count() == 6 || sA.Count() == 8)
- {
- double latD;
- double latM;
- double latS;
- double lngD;
- double lngM;
- double lngS;
-
- double latR = 0; //Sets 1 if South
- double lngR = 0; //Sets 1 if West
-
- //Contact get in order to combine directional indicator together with string
- //Should reduce 8 items to 6
- if (sA.Count() == 8)
- {
- if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
- else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
- else if (char.IsLetter(sA[3][0])) { sA[0] += sA[3]; }
- else { return false; }
-
- if (char.IsLetter(sA[4][0])) { sA[4] += sA[5]; sA[5] = sA[6]; sA[6] = sA[7]; }
- else if (char.IsLetter(sA[5][0])) { sA[4] += sA[5]; sA[5] = sA[6]; sA[6] = sA[7]; }
- else if (char.IsLetter(sA[7][0])) { sA[4] += sA[7]; }
- else { return false; }
-
- //Shift values for below logic
- sA[3] = sA[4];
- sA[4] = sA[5];
- sA[5] = sA[6];
- }
-
- //Find Directions
- if (!sA[0].Contains("N") && !sA[0].Contains("n") && !sA[2].Contains("N") && !sA[2].Contains("n"))
- {
- if (!sA[0].Contains("S") && !sA[0].Contains("s") && !sA[2].Contains("S") && !sA[2].Contains("s"))
- {
- return false;//No Direction Found
- }
- latR = 1;
- }
- if (!sA[3].Contains("E") && !sA[3].Contains("e") && !sA[5].Contains("E") && !sA[5].Contains("e"))
- {
- if (!sA[3].Contains("W") && !sA[3].Contains("w") && !sA[5].Contains("W") && !sA[5].Contains("w"))
- {
- return false;//No Direction Found
- }
- lngR = 1;
- }
- sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
- sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
- sA[2] = Regex.Replace(sA[2], "[^0-9.]", "");
- sA[3] = Regex.Replace(sA[3], "[^0-9.]", "");
- sA[4] = Regex.Replace(sA[4], "[^0-9.]", "");
- sA[5] = Regex.Replace(sA[5], "[^0-9.]", "");
-
- if (!double.TryParse(sA[0], out latD))
- { return false; }
- if (!double.TryParse(sA[1], out latM))
- { return false; }
- if (!double.TryParse(sA[2], out latS))
- { return false; }
- if (!double.TryParse(sA[3], out lngD))
- { return false; }
- if (!double.TryParse(sA[4], out lngM))
- { return false; }
- if (!double.TryParse(sA[5], out lngS))
- { return false; }
-
- d = new double[] { latD, latM, latS, latR, lngD, lngM, lngS, lngR };
- return true;
- }
- return false;
- }
- private static bool TryUTM(string s, out string[] utm)
- {
- utm = null;
- string[] sA = SpecialSplit(s,false);
- if (sA.Count() == 3 || sA.Count() == 4)
- {
- double zone;
- string zoneL;
- double easting;
- double northing;
-
- if (sA.Count() == 4)
- {
-
- if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
- else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
- else { return false; }
- }
- zoneL = new string(sA[0].Where(Char.IsLetter).ToArray());
- if (zoneL == string.Empty) { return false; }
- sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
-
- if (!double.TryParse(sA[0], out zone))
- { return false; }
- if (!double.TryParse(sA[1], out easting))
- { return false; }
- if (!double.TryParse(sA[2], out northing))
- { return false; }
-
- utm = new string[] { zone.ToString(), zoneL, easting.ToString(), northing.ToString() };
- return true;
- }
- return false;
- }
- private static bool TryMGRS(string s, out string[] mgrs)
- {
- mgrs = null;
- string[] sA = SpecialSplit(s,false);
- if (sA.Count() == 4 || sA.Count() == 5)
- {
- double zone;
- string zoneL;
- string diagraph;
- double easting;
- double northing;
-
- if (sA.Count() == 5)
- {
- if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
- else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
- else { return false; }
- }
- zoneL = new string(sA[0].Where(Char.IsLetter).ToArray());
- if (zoneL == string.Empty) { return false; }
- sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
- diagraph = sA[1];
- if (!double.TryParse(sA[0], out zone))
- { return false; }
- if (!double.TryParse(sA[2], out easting))
- { return false; }
- if (!double.TryParse(sA[3], out northing))
- { return false; }
-
- mgrs = new string[] { zone.ToString(), zoneL, diagraph, easting.ToString(), northing.ToString() };
- return true;
- }
- return false;
- }
- private static bool TryCartesian(string s, out double[] d)
- {
- d = null;
- string[] sA = SpecialSplit(s,false);
-
- if (sA.Count() == 3)
- {
- double x;
- double y;
- double z;
- if (!double.TryParse(sA[0], out x))
- { return false; }
- if (!double.TryParse(sA[1], out y))
- { return false; }
- if (!double.TryParse(sA[2], out z))
- { return false; }
- d = new double[] { x, y, z };
- return true;
- }
- return false;
- }
-
- //KEEP DASHES FOR SIGNED AND CARTESIAN AS THEY ARE USED FOR NEGATVE VALUES
- private static string[] SpecialSplit(string s, bool removeDashes)
- {
- s = s.Replace("°", " ");
- s = s.Replace("º", " ");
- s = s.Replace("'", " ");
- s = s.Replace("\"", " ");
- s = s.Replace(",", " ");
- s = s.Replace("mE", " ");
- s = s.Replace("mN", " ");
- if (removeDashes)
- {
- s = s.Replace("-", " ");
- }
- return s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
- }
+ //KEEP DASHES FOR SIGNED AND CARTESIAN AS THEY ARE USED FOR NEGATVE VALUES
+ private static String[] SpecialSplit(String s, Boolean removeDashes) {
+ s = s.Replace("°", " ");
+ s = s.Replace("º", " ");
+ s = s.Replace("'", " ");
+ s = s.Replace("\"", " ");
+ s = s.Replace(",", " ");
+ s = s.Replace("mE", " ");
+ s = s.Replace("mN", " ");
+ if (removeDashes) {
+ s = s.Replace("-", " ");
+ }
+ return s.Split(new Char[0], StringSplitOptions.RemoveEmptyEntries);
}
- internal class FormatFinder_CoordPart
- {
- //Add main to Coordinate and tunnel to Format class. Add private methods to format.
- //WHEN PARSING NO EXCPETIONS FOR OUT OF RANGE ARGS WILL BE THROWN
- public static bool TryParse(string coordString, out CoordinatePart cp)
- {
- //Turn of eagerload for efficiency
- EagerLoad eg = new EagerLoad();
- int type = 0; //0 = unspecifed, 1 = lat, 2 = long;
- eg.Cartesian = false;
- eg.Celestial = false;
- eg.UTM_MGRS = false;
- cp = null;
- Coordinate c = new Coordinate(eg);
- string s = coordString;
- s = s.Trim(); //Trim all spaces before and after string
- double[] d;
+ }
+ internal class FormatFinder_CoordPart {
+ //Add main to Coordinate and tunnel to Format class. Add private methods to format.
+ //WHEN PARSING NO EXCPETIONS FOR OUT OF RANGE ARGS WILL BE THROWN
+ public static Boolean TryParse(String coordString, out CoordinatePart cp) {
+ //Turn of eagerload for efficiency
+ EagerLoad eg = new EagerLoad();
+ Int32 type = 0; //0 = unspecifed, 1 = lat, 2 = long;
+ eg.Cartesian = false;
+ eg.Celestial = false;
+ eg.UTM_MGRS = false;
+ cp = null;
+ Coordinate c = new Coordinate(eg);
+ String s = coordString;
+ s = s.Trim(); //Trim all spaces before and after string
- if (s[0] == ',')
- {
- type = 2;
- s = s.Replace(",", "");
- s = s.Trim();
- }
- if (s[0] == '*')
- {
- type = 1;
- s = s.Replace("*", "");
- s = s.Trim();
- }
+ if (s[0] == ',') {
+ type = 2;
+ s = s.Replace(",", "");
+ s = s.Trim();
+ }
+ if (s[0] == '*') {
+ type = 1;
+ s = s.Replace("*", "");
+ s = s.Trim();
+ }
- if (TrySignedDegree(s, type, out d))
- {
- try
- {
- switch (type)
- {
- case 0:
- //Attempt Lat first (default for signed)
- try
- {
- cp = new CoordinatePart(d[0], CoordinateType.Lat);
- c.Parse_Format = Parse_Format_Type.Signed_Degree;
- return true;
- }
- catch
- {
- cp = new CoordinatePart(d[0], CoordinateType.Long);
- c.Parse_Format = Parse_Format_Type.Signed_Degree;
- return true;
- }
- case 1:
- //Attempt Lat
- cp = new CoordinatePart(d[0], CoordinateType.Lat);
- c.Parse_Format = Parse_Format_Type.Signed_Degree;
- return true;
- case 2:
- //Attempt long
- cp = new CoordinatePart(d[0], CoordinateType.Long);
- c.Parse_Format = Parse_Format_Type.Signed_Degree;
- return true;
- }
- }
- catch
- {
- //silent fail
- }
- }
- //SIGNED DEGREE FAILED, REMOVE DASHES FOR OTHER FORMATS
- s = s.Replace("-", " ");
-
- //All other formats should contain 1 letter.
- if (Regex.Matches(s, @"[a-zA-Z]").Count != 1) { return false; } //Should only contain 1 letter.
- //Get Coord Direction
- int direction = Find_Position(s);
-
- if (direction == -1)
- {
- return false; //No direction found
- }
- //If Coordinate type int specified, look for mismatch
- if (type == 1 && (direction == 1 || direction == 3))
- {
- return false; //mismatch
- }
- if (type == 2 && (direction == 0 || direction == 2))
- {
- return false; //mismatch
- }
- CoordinateType t;
- if (direction == 0 || direction == 2) { t = CoordinateType.Lat; }
- else { t = CoordinateType.Long; }
-
- s = Regex.Replace(s, "[^0-9. ]", ""); //Remove directional character
- s = s.Trim(); //Trim all spaces before and after string
-
- //Try Decimal Degree with Direction
- if (TryDecimalDegree(s, direction, out d))
- {
- try
- {
- cp = new CoordinatePart(d[0], t);
- c.Parse_Format = Parse_Format_Type.Decimal_Degree;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
- //Try DDM
- if (TryDegreeDecimalMinute(s, out d))
- {
- try
- {
- //0 Degree
- //1 Minute
- //2 Direction (0 = N, 1 = E, 2 = S, 3 = W)
- cp = new CoordinatePart((int)d[0], d[1], (CoordinatesPosition)direction);
- c.Parse_Format = Parse_Format_Type.Degree_Decimal_Minute;
- return true;
- }
- catch
- {
- //Parser failed try next method
- }
- }
- //Try DMS
- if (TryDegreeMinuteSecond(s, out d))
- {
- try
- {
- //0 Degree
- //1 Minute
- //2 Second
- //3 Direction (0 = N, 1 = E, 2 = S, 3 = W)
- cp = new CoordinatePart((int)d[0], (int)d[1], d[2], (CoordinatesPosition)direction);
- c.Parse_Format = Parse_Format_Type.Degree_Minute_Second;
- return true;
- }
- catch
- {//Parser failed try next method
- }
- }
-
- return false;
- }
-
- private static bool TrySignedDegree(string s, int t, out double[] d)
- {
- d = null;
- if (Regex.Matches(s, @"[a-zA-Z]").Count != 0) { return false; } //Should contain no letters
-
- string[] sA = SpecialSplit(s, false);
- double deg;
- double min; //Minutes & MinSeconds
- double sec;
-
- int sign = 1;
- switch (sA.Count())
- {
- case 1:
- if (!double.TryParse(sA[0], out deg))
- { return false; }
- d = new double[] { deg };
- return true;
- case 2:
- if (!double.TryParse(sA[0], out deg))
- { return false; }
- if (!double.TryParse(sA[1], out min))
- { return false; }
-
- if (deg < 0) { sign = -1; }
- if (min >= 60 || min < 0) { return false; } //Handle in parser as degree will be incorrect.
- d = new double[] { (Math.Abs(deg) + (min / 60.0)) * sign };
- return true;
- case 3:
- if (!double.TryParse(sA[0], out deg))
- { return false; }
- if (!double.TryParse(sA[1], out min))
- { return false; }
- if (!double.TryParse(sA[2], out sec))
- { return false; }
- if (min >= 60 || min < 0) { return false; } //Handle in parser as degree will be incorrect.
- if (sec >= 60 || sec < 0) { return false; } //Handle in parser as degree will be incorrect.
-
- if (deg < 0) { sign = -1; }
- d = new double[] { (Math.Abs(deg) + (min / 60.0) + (sec / 3600.0)) * sign };
- return true;
- default:
- return false;
- }
- }
- private static bool TryDecimalDegree(string s, int direction, out double[] d)
- {
- d = null;
- int sign = 1;
- //S or W
- if (direction == 2 || direction == 3)
- {
- sign = -1;
- }
- double coord;
-
- string[] sA = SpecialSplit(s, true);
-
- if (sA.Count() == 1)
- {
- if (!double.TryParse(s, out coord))
- { return false; }
-
- coord *= sign;
- d = new double[] { coord };
+ if (TrySignedDegree(s, type, out Double[] d)) {
+ try {
+ switch (type) {
+ case 0:
+ //Attempt Lat first (default for signed)
+ try {
+ cp = new CoordinatePart(d[0], CoordinateType.Lat);
+ c.Parse_Format = Parse_Format_Type.Signed_Degree;
return true;
- }
-
- return false;
- }
- private static bool TryDegreeDecimalMinute(string s, out double[] d)
- {
- d = null;
-
- double deg;
- double minSec;
-
-
- string[] sA = SpecialSplit(s,true);
- if (sA.Count() == 2)
- {
- if (!double.TryParse(sA[0], out deg))
- { return false; }
- if (!double.TryParse(sA[1], out minSec))
- { return false; }
-
- d = new double[] { deg, minSec };
+ } catch {
+ cp = new CoordinatePart(d[0], CoordinateType.Long);
+ c.Parse_Format = Parse_Format_Type.Signed_Degree;
return true;
- }
- return false;
+ }
+ case 1:
+ //Attempt Lat
+ cp = new CoordinatePart(d[0], CoordinateType.Lat);
+ c.Parse_Format = Parse_Format_Type.Signed_Degree;
+ return true;
+ case 2:
+ //Attempt long
+ cp = new CoordinatePart(d[0], CoordinateType.Long);
+ c.Parse_Format = Parse_Format_Type.Signed_Degree;
+ return true;
+ }
+ } catch {
+ //silent fail
}
- private static bool TryDegreeMinuteSecond(string s, out double[] d)
- {
- d = null;
+ }
+ //SIGNED DEGREE FAILED, REMOVE DASHES FOR OTHER FORMATS
+ s = s.Replace("-", " ");
+ //All other formats should contain 1 letter.
+ if (Regex.Matches(s, @"[a-zA-Z]").Count != 1) { return false; } //Should only contain 1 letter.
+ //Get Coord Direction
+ Int32 direction = Find_Position(s);
- double deg;
- double min;
- double sec;
+ if (direction == -1) {
+ return false; //No direction found
+ }
+ //If Coordinate type int specified, look for mismatch
+ if (type == 1 && (direction == 1 || direction == 3)) {
+ return false; //mismatch
+ }
+ if (type == 2 && (direction == 0 || direction == 2)) {
+ return false; //mismatch
+ }
+ CoordinateType t = direction == 0 || direction == 2 ? CoordinateType.Lat : CoordinateType.Long;
+ s = Regex.Replace(s, "[^0-9. ]", ""); //Remove directional character
+ s = s.Trim(); //Trim all spaces before and after string
- string[] sA = SpecialSplit(s,true);
- if (sA.Count() == 3)
- {
-
- if (!double.TryParse(sA[0], out deg))
- { return false; }
- if (!double.TryParse(sA[1], out min))
- { return false; }
- if (!double.TryParse(sA[2], out sec))
- { return false; }
-
- d = new double[] { deg, min, sec };
- return true;
- }
- return false;
+ //Try Decimal Degree with Direction
+ if (TryDecimalDegree(s, direction, out d)) {
+ try {
+ cp = new CoordinatePart(d[0], t);
+ c.Parse_Format = Parse_Format_Type.Decimal_Degree;
+ return true;
+ } catch {//Parser failed try next method
}
-
- private static int Find_Position(string s)
- {
- //N=0
- //E=1
- //S=2
- //W=3
- //NOPOS = -1
- //Find Directions
-
- int part = -1;
- if (s.Contains("N") || s.Contains("n"))
- {
- part = 0;
- }
- if (s.Contains("E") || s.Contains("e"))
- {
- part = 1;
- }
- if (s.Contains("S") || s.Contains("s"))
- {
- part = 2;
-
- }
- if (s.Contains("W") || s.Contains("w"))
- {
- part = 3;
- }
- return part;
+ }
+ //Try DDM
+ if (TryDegreeDecimalMinute(s, out d)) {
+ try {
+ //0 Degree
+ //1 Minute
+ //2 Direction (0 = N, 1 = E, 2 = S, 3 = W)
+ cp = new CoordinatePart((Int32)d[0], d[1], (CoordinatesPosition)direction);
+ c.Parse_Format = Parse_Format_Type.Degree_Decimal_Minute;
+ return true;
+ } catch {
+ //Parser failed try next method
}
-
- //KEEP DASHES FOR SIGNED AND CARTESIAN AS THEY ARE USED FOR NEGATVE VALUES
- private static string[] SpecialSplit(string s, bool removeDashes)
- {
- s = s.Replace("°", " ");
- s = s.Replace("º", " ");
- s = s.Replace("'", " ");
- s = s.Replace("\"", " ");
- s = s.Replace(",", " ");
- s = s.Replace("mE", " ");
- s = s.Replace("mN", " ");
- if(removeDashes)
- {
- s = s.Replace("-", " ");
- }
- return s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
+ }
+ //Try DMS
+ if (TryDegreeMinuteSecond(s, out d)) {
+ try {
+ //0 Degree
+ //1 Minute
+ //2 Second
+ //3 Direction (0 = N, 1 = E, 2 = S, 3 = W)
+ cp = new CoordinatePart((Int32)d[0], (Int32)d[1], d[2], (CoordinatesPosition)direction);
+ c.Parse_Format = Parse_Format_Type.Degree_Minute_Second;
+ return true;
+ } catch {//Parser failed try next method
}
+ }
+
+ return false;
}
+
+ private static Boolean TrySignedDegree(String s, Int32 _, out Double[] d) {
+ d = null;
+ if (Regex.Matches(s, @"[a-zA-Z]").Count != 0) { return false; } //Should contain no letters
+
+ String[] sA = SpecialSplit(s, false);
+ Double deg;
+ Double min; //Minutes & MinSeconds
+ Double sec;
+
+ Int32 sign = 1;
+ switch (sA.Count()) {
+ case 1:
+ if (!Double.TryParse(sA[0], out deg)) { return false; }
+ d = new Double[] { deg };
+ return true;
+ case 2:
+ if (!Double.TryParse(sA[0], out deg)) { return false; }
+ if (!Double.TryParse(sA[1], out min)) { return false; }
+
+ if (deg < 0) { sign = -1; }
+ if (min >= 60 || min < 0) { return false; } //Handle in parser as degree will be incorrect.
+ d = new Double[] { (Math.Abs(deg) + min / 60.0) * sign };
+ return true;
+ case 3:
+ if (!Double.TryParse(sA[0], out deg)) { return false; }
+ if (!Double.TryParse(sA[1], out min)) { return false; }
+ if (!Double.TryParse(sA[2], out sec)) { return false; }
+ if (min >= 60 || min < 0) { return false; } //Handle in parser as degree will be incorrect.
+ if (sec >= 60 || sec < 0) { return false; } //Handle in parser as degree will be incorrect.
+
+ if (deg < 0) { sign = -1; }
+ d = new Double[] { (Math.Abs(deg) + min / 60.0 + sec / 3600.0) * sign };
+ return true;
+ default:
+ return false;
+ }
+ }
+ private static Boolean TryDecimalDegree(String s, Int32 direction, out Double[] d) {
+ d = null;
+ Int32 sign = 1;
+ //S or W
+ if (direction == 2 || direction == 3) {
+ sign = -1;
+ }
+
+ String[] sA = SpecialSplit(s, true);
+
+ if (sA.Count() == 1) {
+ if (!Double.TryParse(s, out Double coord)) { return false; }
+
+ coord *= sign;
+ d = new Double[] { coord };
+ return true;
+ }
+
+ return false;
+ }
+ private static Boolean TryDegreeDecimalMinute(String s, out Double[] d) {
+ d = null;
+
+
+
+ String[] sA = SpecialSplit(s, true);
+ if (sA.Count() == 2) {
+ if (!Double.TryParse(sA[0], out Double deg)) { return false; }
+ if (!Double.TryParse(sA[1], out Double minSec)) { return false; }
+
+ d = new Double[] { deg, minSec };
+ return true;
+ }
+ return false;
+ }
+ private static Boolean TryDegreeMinuteSecond(String s, out Double[] d) {
+ d = null;
+
+
+
+ String[] sA = SpecialSplit(s, true);
+ if (sA.Count() == 3) {
+
+ if (!Double.TryParse(sA[0], out Double deg)) { return false; }
+ if (!Double.TryParse(sA[1], out Double min)) { return false; }
+ if (!Double.TryParse(sA[2], out Double sec)) { return false; }
+
+ d = new Double[] { deg, min, sec };
+ return true;
+ }
+ return false;
+ }
+
+ private static Int32 Find_Position(String s) {
+ //N=0
+ //E=1
+ //S=2
+ //W=3
+ //NOPOS = -1
+ //Find Directions
+
+ Int32 part = -1;
+ if (s.Contains("N") || s.Contains("n")) {
+ part = 0;
+ }
+ if (s.Contains("E") || s.Contains("e")) {
+ part = 1;
+ }
+ if (s.Contains("S") || s.Contains("s")) {
+ part = 2;
+
+ }
+ if (s.Contains("W") || s.Contains("w")) {
+ part = 3;
+ }
+ return part;
+ }
+
+ //KEEP DASHES FOR SIGNED AND CARTESIAN AS THEY ARE USED FOR NEGATVE VALUES
+ private static String[] SpecialSplit(String s, Boolean removeDashes) {
+ s = s.Replace("°", " ");
+ s = s.Replace("º", " ");
+ s = s.Replace("'", " ");
+ s = s.Replace("\"", " ");
+ s = s.Replace(",", " ");
+ s = s.Replace("mE", " ");
+ s = s.Replace("mN", " ");
+ if (removeDashes) {
+ s = s.Replace("-", " ");
+ }
+ return s.Split(new Char[0], StringSplitOptions.RemoveEmptyEntries);
+ }
+ }
}
diff --git a/CoordinateSharp/Coordinate.UTM.cs b/CoordinateSharp/Coordinate.UTM.cs
index 1add280..1e1dab3 100644
--- a/CoordinateSharp/Coordinate.UTM.cs
+++ b/CoordinateSharp/Coordinate.UTM.cs
@@ -1,592 +1,491 @@
using System;
-using System.Linq;
-using System.Diagnostics;
using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
-namespace CoordinateSharp
-{
+namespace CoordinateSharp {
+ ///
+ /// Universal Transverse Mercator (UTM) coordinate system. Uses the WGS 84 Datum.
+ ///
+ [Serializable]
+ public class UniversalTransverseMercator : INotifyPropertyChanged {
///
- /// Universal Transverse Mercator (UTM) coordinate system. Uses the WGS 84 Datum.
+ /// Creates a UniversalTransverMercator object with a WGS84 Datum.
///
- [Serializable]
- public class UniversalTransverseMercator : INotifyPropertyChanged
- {
- ///
- /// Creates a UniversalTransverMercator object with a WGS84 Datum.
- ///
- /// Latitude zone
- /// Longitude zone
- /// Easting
- /// Northing
- public UniversalTransverseMercator(string latz, int longz, double est, double nrt)
- {
- if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
- if (!Verify_Lat_Zone(latz)) { Debug.WriteLine("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
- if (est < 160000 || est > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. Use with caution."); }
- if (nrt < 0 || nrt > 10000000) { Debug.WriteLine("Northing out of range", "Northing must be between 0-10,000,000."); }
+ /// Latitude zone
+ /// Longitude zone
+ /// Easting
+ /// Northing
+ public UniversalTransverseMercator(String latz, Int32 longz, Double est, Double nrt) {
+ if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
+ if (!this.Verify_Lat_Zone(latz)) { Debug.WriteLine("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
+ if (est < 160000 || est > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. Use with caution."); }
+ if (nrt < 0 || nrt > 10000000) { Debug.WriteLine("Northing out of range", "Northing must be between 0-10,000,000."); }
- latZone = latz;
- longZone =longz;
- easting = est;
- northing = nrt;
+ this.latZone = latz;
+ this.longZone = longz;
+ this.easting = est;
+ this.northing = nrt;
- equatorial_radius = 6378137.0;
- inverse_flattening = 298.257223563;
+ this.equatorial_radius = 6378137.0;
+ this.inverse_flattening = 298.257223563;
+ }
+ ///
+ /// Creates a UniversalTransverMercator object with a custom Datum.
+ ///
+ /// Latitude zone
+ /// Longitude zone
+ /// Easting
+ /// Northing
+ /// Equatorial Radius
+ /// Inverse Flattening
+ public UniversalTransverseMercator(String latz, Int32 longz, Double est, Double nrt, Double radius, Double flaten) {
+ if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
+ if (!this.Verify_Lat_Zone(latz)) { Debug.WriteLine("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
+ if (est < 160000 || est > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. Use with caution."); }
+ if (nrt < 0 || nrt > 10000000) { Debug.WriteLine("Northing out of range", "Northing must be between 0-10,000,000."); }
+
+ this.latZone = latz;
+ this.longZone = longz;
+ this.easting = est;
+ this.northing = nrt;
+
+ this.equatorial_radius = radius;
+ this.inverse_flattening = flaten;
+ }
+
+ //private readonly Coordinate coordinate;
+
+ internal Double equatorial_radius;
+ internal Double inverse_flattening;
+ private String latZone;
+ private Int32 longZone;
+
+ private Double easting;
+ private Double northing;
+
+ ///
+ /// UTM Zone Letter
+ ///
+ public String LatZone {
+ get => this.latZone;
+ set {
+ if (this.latZone != value) {
+ this.latZone = value;
}
- ///
- /// Creates a UniversalTransverMercator object with a custom Datum.
- ///
- /// Latitude zone
- /// Longitude zone
- /// Easting
- /// Northing
- /// Equatorial Radius
- /// Inverse Flattening
- public UniversalTransverseMercator(string latz, int longz, double est, double nrt, double radius, double flaten)
- {
- if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
- if (!Verify_Lat_Zone(latz)) { Debug.WriteLine("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
- if (est < 160000 || est > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. Use with caution."); }
- if (nrt < 0 || nrt > 10000000) { Debug.WriteLine("Northing out of range", "Northing must be between 0-10,000,000."); }
-
- latZone = latz;
- longZone = longz;
- easting = est;
- northing = nrt;
-
- equatorial_radius = radius;
- inverse_flattening = flaten;
+ }
+ }
+ ///
+ /// UTM Zone Number
+ ///
+ public Int32 LongZone {
+ get => this.longZone;
+ set {
+ if (this.longZone != value) {
+ this.longZone = value;
}
-
- private Coordinate coordinate;
-
- internal double equatorial_radius;
- internal double inverse_flattening;
- private string latZone;
- private int longZone;
-
- private double easting;
- private double northing;
-
- private bool withinCoordinateSystemBounds = true;
-
- ///
- /// UTM Zone Letter
- ///
- public string LatZone
- {
- get { return latZone; }
- set
- {
- if (latZone != value)
- {
- latZone = value;
- }
- }
+ }
+ }
+ ///
+ /// UTM Easting
+ ///
+ public Double Easting {
+ get => this.easting;
+ set {
+ if (this.easting != value) {
+ this.easting = value;
}
- ///
- /// UTM Zone Number
- ///
- public int LongZone
- {
- get { return longZone; }
- set
- {
- if (longZone != value)
- {
- longZone = value;
- }
- }
+ }
+ }
+ ///
+ /// UTM Northing
+ ///
+ public Double Northing {
+ get => this.northing;
+ set {
+ if (this.northing != value) {
+ this.northing = value;
}
- ///
- /// UTM Easting
- ///
- public double Easting
- {
- get { return easting; }
- set
- {
- if (easting != value)
- {
- easting = value;
- }
- }
- }
- ///
- /// UTM Northing
- ///
- public double Northing
- {
- get { return northing; }
- set
- {
- if (northing != value)
- {
- northing = value;
- }
- }
- }
-
- ///
- /// Datum Equatorial Radius / Semi Major Axis
- ///
- public double Equatorial_Radius
- {
- get { return equatorial_radius; }
- }
- ///
- /// Datum Flattening
- ///
- public double Inverse_Flattening
- {
- get { return inverse_flattening; }
- }
-
- ///
- /// Is the UTM conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
- ///
- public bool WithinCoordinateSystemBounds
- {
- get { return withinCoordinateSystemBounds; }
- }
-
- ///
- /// Constructs a UTM object based off DD Lat/Long
- ///
- /// DD Latitude
- /// DD Longitide
- /// Parent Coordinate Object
- internal UniversalTransverseMercator(double lat, double longi, Coordinate c)
- {
- //validate coords
-
- //if (lat > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal coordinate decimal cannot be greater than 180."); }
- //if (lat < -180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal coordinate decimal cannot be less than 180."); }
-
- //if (longi > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal coordinate decimal cannot be greater than 90."); }
- //if (longi < -90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal coordinate decimal cannot be less than 90."); }
- equatorial_radius = 6378137.0;
- inverse_flattening = 298.257223563;
- ToUTM(lat, longi, this);
-
- coordinate = c;
- }
- ///
- /// Constructs a UTM object based off DD Lat/Long
- ///
- /// DD Latitude
- /// DD Longitide
- /// Parent Coordinate Object
- /// Equatorial Radius
- /// Flattening
- internal UniversalTransverseMercator(double lat, double longi, Coordinate c,double rad,double flt)
- {
- equatorial_radius = rad;
- inverse_flattening = flt;
- ToUTM(lat, longi, this);
-
- coordinate = c;
- }
- ///
- /// Constructs a UTM object based off a UTM coordinate
- /// Not yet implemented
- ///
- /// Zone Letter
- /// Zone Number
- /// Easting
- /// Northing
- /// Parent Coordinate Object
- /// Equatorial Radius
- /// Inverse Flattening
- internal UniversalTransverseMercator(string latz, int longz, double e, double n, Coordinate c, double rad, double flt)
- {
- //validate utm
- if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
- if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
- if (e < 160000 || e > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. If this is intentional, use with caution."); }
- if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
- equatorial_radius = rad;
- inverse_flattening = flt;
- latZone = latz;
- longZone = longz;
-
- easting = e;
- northing = n;
-
- coordinate = c;
- if (c.Latitude.DecimalDegree <= -80 || c.Latitude.DecimalDegree >= 84) { withinCoordinateSystemBounds = false; }
- else { withinCoordinateSystemBounds = true; }
- }
-
- ///
- /// Verifies Lat zone when convert from UTM to DD Lat/Long
- ///
- /// Zone Letter
- /// boolean
- private bool Verify_Lat_Zone(string l)
- {
- if (LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() != 1)
- {
- return false;
- }
- return true;
- }
- private double degreeToRadian(double degree)
- {
- return degree * Math.PI / 180;
- }
- ///
- /// Assigns UTM values based of Lat/Long
- ///
- /// DD Latitude
- /// DD longitude
- /// UTM Object to modify
- internal void ToUTM(double lat, double longi, UniversalTransverseMercator utm)
- {
- string letter = "";
- double easting = 0;
- double northing = 0;
- int zone = (int)Math.Floor(longi / 6 + 31);
- if (lat < -72)
- letter = "C";
- else if (lat < -64)
- letter = "D";
- else if (lat < -56)
- letter = "E";
- else if (lat < -48)
- letter = "F";
- else if (lat < -40)
- letter = "G";
- else if (lat < -32)
- letter = "H";
- else if (lat < -24)
- letter = "J";
- else if (lat < -16)
- letter = "K";
- else if (lat < -8)
- letter = "L";
- else if (lat < 0)
- letter = "M";
- else if (lat < 8)
- letter = "N";
- else if (lat < 16)
- letter = "P";
- else if (lat < 24)
- letter = "Q";
- else if (lat < 32)
- letter = "R";
- else if (lat < 40)
- letter = "S";
- else if (lat < 48)
- letter = "T";
- else if (lat < 56)
- letter = "U";
- else if (lat < 64)
- letter = "V";
- else if (lat < 72)
- letter = "W";
- else
- letter = "X";
-
- double a = utm.equatorial_radius;
- double f = 1.0 / utm.inverse_flattening;
- double b = a * (1 - f); // polar radius
-
- double e = Math.Sqrt(1 - Math.Pow(b, 2) / Math.Pow(a, 2));
- double e0 = e / Math.Sqrt(1 - Math.Pow(e, 1));
-
- double drad = Math.PI / 180;
- double k0 = 0.9996;
-
- double phi = lat * drad; // convert latitude to radians
- double lng = longi * drad; // convert longitude to radians
- double utmz = 1 + Math.Floor((longi + 180) / 6.0); // longitude to utm zone
- double zcm = 3 + 6.0 * (utmz - 1) - 180; // central meridian of a zone
- // this gives us zone A-B for below 80S
- double esq = (1 - (b / a) * (b / a));
- double e0sq = e * e / (1 - Math.Pow(e, 2));
- double M = 0;
-
- double N = a / Math.Sqrt(1 - Math.Pow(e * Math.Sin(phi), 2));
- double T = Math.Pow(Math.Tan(phi), 2);
- double C = e0sq * Math.Pow(Math.Cos(phi), 2);
- double A = (longi - zcm) * drad * Math.Cos(phi);
-
- // calculate M (USGS style)
- M = phi * (1 - esq * (1.0 / 4.0 + esq * (3.0 / 64.0 + 5.0 * esq / 256.0)));
- M = M - Math.Sin(2.0 * phi) * (esq * (3.0 / 8.0 + esq * (3.0 / 32.0 + 45.0 * esq / 1024.0)));
- M = M + Math.Sin(4.0 * phi) * (esq * esq * (15.0 / 256.0 + esq * 45.0 / 1024.0));
- M = M - Math.Sin(6.0 * phi) * (esq * esq * esq * (35.0 / 3072.0));
- M = M * a;//Arc length along standard meridian
-
- double M0 = 0;// if another point of origin is used than the equator
-
- // Calculate the UTM values...
- // first the easting
- var x = k0 * N * A * (1 + A * A * ((1 - T + C) / 6 + A * A * (5 - 18 * T + T * T + 72.0 * C - 58 * e0sq) / 120.0)); //Easting relative to CM
- x = x + 500000; // standard easting
-
- // Northing
-
- double y = k0 * (M - M0 + N * Math.Tan(phi) * (A * A * (1 / 2.0 + A * A * ((5 - T + 9 * C + 4 * C * C) / 24.0 + A * A * (61 - 58 * T + T * T + 600 * C - 330 * e0sq) / 720.0)))); // first from the equator
- double yg = y + 10000000; //yg = y global, from S. Pole
- if (y < 0)
- {
- y = 10000000 + y; // add in false northing if south of the equator
- }
-
-
- easting = Math.Round(10 * (x)) / 10.0;
- northing = Math.Round(10 * y) / 10.0;
-
- utm.latZone = letter;
- utm.longZone = zone;
- utm.easting = easting;
- utm.northing = northing;
-
- if(lat<=-80 || lat >= 84) { withinCoordinateSystemBounds = false; }
- else { withinCoordinateSystemBounds = true; }
- }
-
- ///
- /// UTM Default String Format
- ///
- /// UTM Formatted Coordinate String
- public override string ToString()
- {
- if (!withinCoordinateSystemBounds) { return ""; }//MGRS Coordinate is outside its reliable boundaries. Return empty.
- return longZone.ToString() + LatZone + " " + (int)easting + "mE " + (int)northing + "mN";
- }
-
- private static Coordinate UTMtoLatLong(double x, double y, double zone, double equatorialRadius, double flattening)
- {
- //x easting
- //y northing
-
- //http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html
- double phif, Nf, Nfpow, nuf2, ep2, tf, tf2, tf4, cf;
- double x1frac, x2frac, x3frac, x4frac, x5frac, x6frac, x7frac, x8frac;
- double x2poly, x3poly, x4poly, x5poly, x6poly, x7poly, x8poly;
-
- double sm_a = equatorialRadius;
- double sm_b = equatorialRadius * (1 - (1.0 / flattening)); //Polar Radius
-
- /* Get the value of phif, the footpoint latitude. */
- phif = FootpointLatitude(y,equatorialRadius,flattening);
-
- /* Precalculate ep2 */
- ep2 = (Math.Pow(sm_a, 2.0) - Math.Pow(sm_b, 2.0))
- / Math.Pow(sm_b, 2.0);
-
- /* Precalculate cos (phif) */
- cf = Math.Cos(phif);
-
- /* Precalculate nuf2 */
- nuf2 = ep2 * Math.Pow(cf, 2.0);
-
- /* Precalculate Nf and initialize Nfpow */
- Nf = Math.Pow(sm_a, 2.0) / (sm_b * Math.Sqrt(1 + nuf2));
- Nfpow = Nf;
-
- /* Precalculate tf */
- tf = Math.Tan(phif);
- tf2 = tf * tf;
- tf4 = tf2 * tf2;
-
- /* Precalculate fractional coefficients for x**n in the equations
- below to simplify the expressions for latitude and longitude. */
- x1frac = 1.0 / (Nfpow * cf);
-
- Nfpow *= Nf; /* now equals Nf**2) */
- x2frac = tf / (2.0 * Nfpow);
-
- Nfpow *= Nf; /* now equals Nf**3) */
- x3frac = 1.0 / (6.0 * Nfpow * cf);
-
- Nfpow *= Nf; /* now equals Nf**4) */
- x4frac = tf / (24.0 * Nfpow);
-
- Nfpow *= Nf; /* now equals Nf**5) */
- x5frac = 1.0 / (120.0 * Nfpow * cf);
-
- Nfpow *= Nf; /* now equals Nf**6) */
- x6frac = tf / (720.0 * Nfpow);
-
- Nfpow *= Nf; /* now equals Nf**7) */
- x7frac = 1.0 / (5040.0 * Nfpow * cf);
-
- Nfpow *= Nf; /* now equals Nf**8) */
- x8frac = tf / (40320.0 * Nfpow);
-
- /* Precalculate polynomial coefficients for x**n.
- -- x**1 does not have a polynomial coefficient. */
- x2poly = -1.0 - nuf2;
-
- x3poly = -1.0 - 2 * tf2 - nuf2;
-
- x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2
- - 3.0 * (nuf2 * nuf2) - 9.0 * tf2 * (nuf2 * nuf2);
-
- x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 * tf2 * nuf2;
-
- x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2
- + 162.0 * tf2 * nuf2;
-
- x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 * tf2);
-
- x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2);
-
- /* Calculate latitude */
- double nLat = phif + x2frac * x2poly * (x * x)
- + x4frac * x4poly * Math.Pow(x, 4.0)
- + x6frac * x6poly * Math.Pow(x, 6.0)
- + x8frac * x8poly * Math.Pow(x, 8.0);
-
- /* Calculate longitude */
- double nLong = zone + x1frac * x
- + x3frac * x3poly * Math.Pow(x, 3.0)
- + x5frac * x5poly * Math.Pow(x, 5.0)
- + x7frac * x7poly * Math.Pow(x, 7.0);
-
- double dLat = RadToDeg(nLat);
- double dLong = RadToDeg(nLong);
- if (dLat > 90) { dLat = 90; }
- if (dLat < -90) { dLat = -90; }
- if (dLong > 180) { dLong = 180; }
- if (dLong < -180) { dLong = -180; }
-
- Coordinate c = new Coordinate(equatorialRadius,flattening, true);
- CoordinatePart cLat = new CoordinatePart(dLat, CoordinateType.Lat);
- CoordinatePart cLng = new CoordinatePart(dLong, CoordinateType.Long);
-
- c.Latitude = cLat;
- c.Longitude = cLng;
-
- return c;
- }
-
- private static double RadToDeg(double rad)
- {
- double pi = 3.14159265358979;
- return (rad / pi * 180.0);
- }
- private static double DegToRad(double deg)
- {
- double pi = 3.14159265358979;
- return (deg / 180.0 * pi);
- }
- private static double FootpointLatitude(double y, double equatorialRadius, double flattening)
- {
- double y_, alpha_, beta_, gamma_, delta_, epsilon_, n;
- double result;
-
-
- /* Ellipsoid model constants (actual values here are for WGS84) */
- double sm_a = equatorialRadius;
- double sm_b = equatorialRadius * (1 - (1.0 / flattening));
-
-
- /* Precalculate n (Eq. 10.18) */
- n = (sm_a - sm_b) / (sm_a + sm_b);
-
- /* Precalculate alpha_ (Eq. 10.22) */
- /* (Same as alpha in Eq. 10.17) */
- alpha_ = ((sm_a + sm_b) / 2.0) * (1 + (Math.Pow(n, 2.0) / 4) + (Math.Pow(n, 4.0) / 64));
-
- /* Precalculate y_ (Eq. 10.23) */
- y_ = y / alpha_;
-
- /* Precalculate beta_ (Eq. 10.22) */
- beta_ = (3.0 * n / 2.0) + (-27.0 * Math.Pow(n, 3.0) / 32.0)
- + (269.0 * Math.Pow(n, 5.0) / 512.0);
-
- /* Precalculate gamma_ (Eq. 10.22) */
- gamma_ = (21.0 * Math.Pow(n, 2.0) / 16.0)
- + (-55.0 * Math.Pow(n, 4.0) / 32.0);
-
- /* Precalculate delta_ (Eq. 10.22) */
- delta_ = (151.0 * Math.Pow(n, 3.0) / 96.0)
- + (-417.0 * Math.Pow(n, 5.0) / 128.0);
-
- /* Precalculate epsilon_ (Eq. 10.22) */
- epsilon_ = (1097.0 * Math.Pow(n, 4.0) / 512.0);
-
- /* Now calculate the sum of the series (Eq. 10.21) */
- result = y_ + (beta_ * Math.Sin(2.0 * y_))
- + (gamma_ * Math.Sin(4.0 * y_))
- + (delta_ * Math.Sin(6.0 * y_))
- + (epsilon_ * Math.Sin(8.0 * y_));
-
- return result;
- }
-
- ///
- /// Converts UTM coordinate to Lat/Long
- ///
- /// utm
- /// Coordinate object
- public static Coordinate ConvertUTMtoLatLong(UniversalTransverseMercator utm)
- {
-
- bool southhemi = false;
- if (utm.latZone == "A" || utm.latZone == "B" || utm.latZone == "C" || utm.latZone == "D" || utm.latZone == "E" || utm.latZone == "F" || utm.latZone == "G" || utm.latZone == "H" || utm.latZone == "J" ||
- utm.latZone == "K" || utm.latZone == "L" || utm.latZone == "M")
- {
- southhemi = true;
- }
-
- double cmeridian;
-
- double x = utm.Easting - 500000.0;
- double UTMScaleFactor = 0.9996;
- x /= UTMScaleFactor;
-
- /* If in southern hemisphere, adjust y accordingly. */
- double y = utm.Northing;
- if (southhemi)
- {
- y -= 10000000.0;
- }
-
- y /= UTMScaleFactor;
-
- cmeridian = UTMCentralMeridian(utm.LongZone);
-
- Coordinate c = UTMtoLatLong(x, y, cmeridian, utm.equatorial_radius, utm.inverse_flattening);
-
- if (c.Latitude.ToDouble() > 85 || c.Latitude.ToDouble() < -85)
- {
- Debug.WriteLine("UTM conversions greater than 85 degrees or less than -85 degree latitude contain major deviations and should be used with caution.");
- }
- return c;
-
-
- }
-
- private static double UTMCentralMeridian(double zone)
- {
- double cmeridian;
-
- cmeridian = DegToRad(-183.0 + (zone * 6.0));
-
- return cmeridian;
- }
-
- ///
- /// Property changed event
- ///
- public event PropertyChangedEventHandler PropertyChanged;
- ///
- /// Notify property changed
- ///
- /// Property name
- public void NotifyPropertyChanged(string propName)
- {
- if (this.PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propName));
- }
- }
- }
-
+ }
+ }
+
+ ///
+ /// Datum Equatorial Radius / Semi Major Axis
+ ///
+ public Double Equatorial_Radius => this.equatorial_radius;
+ ///
+ /// Datum Flattening
+ ///
+ public Double Inverse_Flattening => this.inverse_flattening;
+
+ ///
+ /// Is the UTM conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
+ ///
+ public Boolean WithinCoordinateSystemBounds { get; private set; } = true;
+
+ ///
+ /// Constructs a UTM object based off DD Lat/Long
+ ///
+ /// DD Latitude
+ /// DD Longitide
+ /// Parent Coordinate Object
+ internal UniversalTransverseMercator(Double lat, Double longi, Coordinate _) {
+ //validate coords
+
+ //if (lat > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal coordinate decimal cannot be greater than 180."); }
+ //if (lat < -180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal coordinate decimal cannot be less than 180."); }
+
+ //if (longi > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal coordinate decimal cannot be greater than 90."); }
+ //if (longi < -90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal coordinate decimal cannot be less than 90."); }
+ this.equatorial_radius = 6378137.0;
+ this.inverse_flattening = 298.257223563;
+ this.ToUTM(lat, longi, this);
+
+ //this.coordinate = c;
+ }
+ ///
+ /// Constructs a UTM object based off DD Lat/Long
+ ///
+ /// DD Latitude
+ /// DD Longitide
+ /// Parent Coordinate Object
+ /// Equatorial Radius
+ /// Flattening
+ internal UniversalTransverseMercator(Double lat, Double longi, Coordinate _, Double rad, Double flt) {
+ this.equatorial_radius = rad;
+ this.inverse_flattening = flt;
+ this.ToUTM(lat, longi, this);
+
+ //this.coordinate = c;
+ }
+ ///
+ /// Constructs a UTM object based off a UTM coordinate
+ /// Not yet implemented
+ ///
+ /// Zone Letter
+ /// Zone Number
+ /// Easting
+ /// Northing
+ /// Parent Coordinate Object
+ /// Equatorial Radius
+ /// Inverse Flattening
+ internal UniversalTransverseMercator(String latz, Int32 longz, Double e, Double n, Coordinate c, Double rad, Double flt) {
+ //validate utm
+ if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
+ if (!this.Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
+ if (e < 160000 || e > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. If this is intentional, use with caution."); }
+ if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
+ this.equatorial_radius = rad;
+ this.inverse_flattening = flt;
+ this.latZone = latz;
+ this.longZone = longz;
+
+ this.easting = e;
+ this.northing = n;
+
+ //this.coordinate = c;
+ this.WithinCoordinateSystemBounds = c.Latitude.DecimalDegree > -80 && c.Latitude.DecimalDegree < 84;
+ }
+
+ ///
+ /// Verifies Lat zone when convert from UTM to DD Lat/Long
+ ///
+ /// Zone Letter
+ /// boolean
+ private Boolean Verify_Lat_Zone(String l) => LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() == 1;
+ //private Double degreeToRadian(Double degree) => degree * Math.PI / 180;
+ ///
+ /// Assigns UTM values based of Lat/Long
+ ///
+ /// DD Latitude
+ /// DD longitude
+ /// UTM Object to modify
+ internal void ToUTM(Double lat, Double longi, UniversalTransverseMercator utm) {
+ Int32 zone = (Int32)Math.Floor(longi / 6 + 31);
+ String letter = lat < -72 ? "C"
+ : lat < -64 ? "D"
+ : lat < -56 ? "E"
+ : lat < -48 ? "F"
+ : lat < -40 ? "G"
+ : lat < -32 ? "H"
+ : lat < -24 ? "J"
+ : lat < -16 ? "K"
+ : lat < -8 ? "L"
+ : lat < 0 ? "M"
+ : lat < 8 ? "N"
+ : lat < 16 ? "P"
+ : lat < 24 ? "Q"
+ : lat < 32 ? "R"
+ : lat < 40 ? "S"
+ : lat < 48 ? "T"
+ : lat < 56 ? "U"
+ : lat < 64 ? "V"
+ : lat < 72 ? "W" : "X";
+ Double a = utm.equatorial_radius;
+ Double f = 1.0 / utm.inverse_flattening;
+ Double b = a * (1 - f); // polar radius
+
+ Double e = Math.Sqrt(1 - Math.Pow(b, 2) / Math.Pow(a, 2));
+ _ = e / Math.Sqrt(1 - Math.Pow(e, 1));
+
+ Double drad = Math.PI / 180;
+ Double k0 = 0.9996;
+
+ Double phi = lat * drad; // convert latitude to radians
+ _ = longi * drad; // convert longitude to radians
+ Double utmz = 1 + Math.Floor((longi + 180) / 6.0); // longitude to utm zone
+ Double zcm = 3 + 6.0 * (utmz - 1) - 180; // central meridian of a zone
+ // this gives us zone A-B for below 80S
+ Double esq = 1 - b / a * (b / a);
+ Double e0sq = e * e / (1 - Math.Pow(e, 2));
+ Double N = a / Math.Sqrt(1 - Math.Pow(e * Math.Sin(phi), 2));
+ Double T = Math.Pow(Math.Tan(phi), 2);
+ Double C = e0sq * Math.Pow(Math.Cos(phi), 2);
+ Double A = (longi - zcm) * drad * Math.Cos(phi);
+
+ // calculate M (USGS style)
+ Double M = phi * (1 - esq * (1.0 / 4.0 + esq * (3.0 / 64.0 + 5.0 * esq / 256.0)));
+ M -= Math.Sin(2.0 * phi) * (esq * (3.0 / 8.0 + esq * (3.0 / 32.0 + 45.0 * esq / 1024.0)));
+ M += Math.Sin(4.0 * phi) * (esq * esq * (15.0 / 256.0 + esq * 45.0 / 1024.0));
+ M -= Math.Sin(6.0 * phi) * (esq * esq * esq * (35.0 / 3072.0));
+ M *= a;//Arc length along standard meridian
+
+ Double M0 = 0;// if another point of origin is used than the equator
+
+ // Calculate the UTM values...
+ // first the easting
+ Double x = k0 * N * A * (1 + A * A * ((1 - T + C) / 6 + A * A * (5 - 18 * T + T * T + 72.0 * C - 58 * e0sq) / 120.0)); //Easting relative to CM
+ x += 500000; // standard easting
+
+ // Northing
+
+ Double y = k0 * (M - M0 + N * Math.Tan(phi) * (A * A * (1 / 2.0 + A * A * ((5 - T + 9 * C + 4 * C * C) / 24.0 + A * A * (61 - 58 * T + T * T + 600 * C - 330 * e0sq) / 720.0)))); // first from the equator
+ _ = y + 10000000; //yg = y global, from S. Pole
+ if (y < 0) {
+ y = 10000000 + y; // add in false northing if south of the equator
+ }
+
+
+ Double easting = Math.Round(10 * x) / 10.0;
+ Double northing = Math.Round(10 * y) / 10.0;
+
+ utm.latZone = letter;
+ utm.longZone = zone;
+ utm.easting = easting;
+ utm.northing = northing;
+
+ this.WithinCoordinateSystemBounds = lat > -80 && lat < 84;
+ }
+
+ ///
+ /// UTM Default String Format
+ ///
+ /// UTM Formatted Coordinate String
+ public override String ToString() => !this.WithinCoordinateSystemBounds ? "" : this.longZone.ToString() + this.LatZone + " " + (Int32)this.easting + "mE " + (Int32)this.northing + "mN";
+ //MGRS Coordinate is outside its reliable boundaries. Return empty.
+
+ private static Coordinate UTMtoLatLong(Double x, Double y, Double zone, Double equatorialRadius, Double flattening) {
+ //x easting
+ //y northing
+
+ //http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html
+ Double phif, Nf, Nfpow, nuf2, ep2, tf, tf2, tf4, cf;
+ Double x1frac, x2frac, x3frac, x4frac, x5frac, x6frac, x7frac, x8frac;
+ Double x2poly, x3poly, x4poly, x5poly, x6poly, x7poly, x8poly;
+
+ Double sm_a = equatorialRadius;
+ Double sm_b = equatorialRadius * (1 - 1.0 / flattening); //Polar Radius
+
+ /* Get the value of phif, the footpoint latitude. */
+ phif = FootpointLatitude(y, equatorialRadius, flattening);
+
+ /* Precalculate ep2 */
+ ep2 = (Math.Pow(sm_a, 2.0) - Math.Pow(sm_b, 2.0)) / Math.Pow(sm_b, 2.0);
+
+ /* Precalculate cos (phif) */
+ cf = Math.Cos(phif);
+
+ /* Precalculate nuf2 */
+ nuf2 = ep2 * Math.Pow(cf, 2.0);
+
+ /* Precalculate Nf and initialize Nfpow */
+ Nf = Math.Pow(sm_a, 2.0) / (sm_b * Math.Sqrt(1 + nuf2));
+ Nfpow = Nf;
+
+ /* Precalculate tf */
+ tf = Math.Tan(phif);
+ tf2 = tf * tf;
+ tf4 = tf2 * tf2;
+
+ /* Precalculate fractional coefficients for x**n in the equations
+ below to simplify the expressions for latitude and longitude. */
+ x1frac = 1.0 / (Nfpow * cf);
+
+ Nfpow *= Nf; /* now equals Nf**2) */
+ x2frac = tf / (2.0 * Nfpow);
+
+ Nfpow *= Nf; /* now equals Nf**3) */
+ x3frac = 1.0 / (6.0 * Nfpow * cf);
+
+ Nfpow *= Nf; /* now equals Nf**4) */
+ x4frac = tf / (24.0 * Nfpow);
+
+ Nfpow *= Nf; /* now equals Nf**5) */
+ x5frac = 1.0 / (120.0 * Nfpow * cf);
+
+ Nfpow *= Nf; /* now equals Nf**6) */
+ x6frac = tf / (720.0 * Nfpow);
+
+ Nfpow *= Nf; /* now equals Nf**7) */
+ x7frac = 1.0 / (5040.0 * Nfpow * cf);
+
+ Nfpow *= Nf; /* now equals Nf**8) */
+ x8frac = tf / (40320.0 * Nfpow);
+
+ /* Precalculate polynomial coefficients for x**n.
+ -- x**1 does not have a polynomial coefficient. */
+ x2poly = -1.0 - nuf2;
+
+ x3poly = -1.0 - 2 * tf2 - nuf2;
+
+ x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2 - 3.0 * (nuf2 * nuf2) - 9.0 * tf2 * (nuf2 * nuf2);
+
+ x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 * tf2 * nuf2;
+
+ x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2 + 162.0 * tf2 * nuf2;
+
+ x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 * tf2);
+
+ x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2);
+
+ /* Calculate latitude */
+ Double nLat = phif + x2frac * x2poly * (x * x) + x4frac * x4poly * Math.Pow(x, 4.0) + x6frac * x6poly * Math.Pow(x, 6.0) + x8frac * x8poly * Math.Pow(x, 8.0);
+
+ /* Calculate longitude */
+ Double nLong = zone + x1frac * x + x3frac * x3poly * Math.Pow(x, 3.0) + x5frac * x5poly * Math.Pow(x, 5.0) + x7frac * x7poly * Math.Pow(x, 7.0);
+
+ Double dLat = RadToDeg(nLat);
+ Double dLong = RadToDeg(nLong);
+ if (dLat > 90) { dLat = 90; }
+ if (dLat < -90) { dLat = -90; }
+ if (dLong > 180) { dLong = 180; }
+ if (dLong < -180) { dLong = -180; }
+
+ Coordinate c = new Coordinate(equatorialRadius, flattening, true);
+ CoordinatePart cLat = new CoordinatePart(dLat, CoordinateType.Lat);
+ CoordinatePart cLng = new CoordinatePart(dLong, CoordinateType.Long);
+
+ c.Latitude = cLat;
+ c.Longitude = cLng;
+
+ return c;
+ }
+
+ private static Double RadToDeg(Double rad) {
+ Double pi = 3.14159265358979;
+ return rad / pi * 180.0;
+ }
+ private static Double DegToRad(Double deg) {
+ Double pi = 3.14159265358979;
+ return deg / 180.0 * pi;
+ }
+ private static Double FootpointLatitude(Double y, Double equatorialRadius, Double flattening) {
+ Double y_, alpha_, beta_, gamma_, delta_, epsilon_, n;
+ Double result;
+
+
+ /* Ellipsoid model constants (actual values here are for WGS84) */
+ Double sm_a = equatorialRadius;
+ Double sm_b = equatorialRadius * (1 - 1.0 / flattening);
+
+
+ /* Precalculate n (Eq. 10.18) */
+ n = (sm_a - sm_b) / (sm_a + sm_b);
+
+ /* Precalculate alpha_ (Eq. 10.22) */
+ /* (Same as alpha in Eq. 10.17) */
+ alpha_ = (sm_a + sm_b) / 2.0 * (1 + Math.Pow(n, 2.0) / 4 + Math.Pow(n, 4.0) / 64);
+
+ /* Precalculate y_ (Eq. 10.23) */
+ y_ = y / alpha_;
+
+ /* Precalculate beta_ (Eq. 10.22) */
+ beta_ = 3.0 * n / 2.0 + -27.0 * Math.Pow(n, 3.0) / 32.0 + 269.0 * Math.Pow(n, 5.0) / 512.0;
+
+ /* Precalculate gamma_ (Eq. 10.22) */
+ gamma_ = 21.0 * Math.Pow(n, 2.0) / 16.0 + -55.0 * Math.Pow(n, 4.0) / 32.0;
+
+ /* Precalculate delta_ (Eq. 10.22) */
+ delta_ = 151.0 * Math.Pow(n, 3.0) / 96.0 + -417.0 * Math.Pow(n, 5.0) / 128.0;
+
+ /* Precalculate epsilon_ (Eq. 10.22) */
+ epsilon_ = 1097.0 * Math.Pow(n, 4.0) / 512.0;
+
+ /* Now calculate the sum of the series (Eq. 10.21) */
+ result = y_ + beta_ * Math.Sin(2.0 * y_) + gamma_ * Math.Sin(4.0 * y_) + delta_ * Math.Sin(6.0 * y_) + epsilon_ * Math.Sin(8.0 * y_);
+
+ return result;
+ }
+
+ ///
+ /// Converts UTM coordinate to Lat/Long
+ ///
+ /// utm
+ /// Coordinate object
+ public static Coordinate ConvertUTMtoLatLong(UniversalTransverseMercator utm) {
+
+ Boolean southhemi = false;
+ if (utm.latZone == "A" || utm.latZone == "B" || utm.latZone == "C" || utm.latZone == "D" || utm.latZone == "E" || utm.latZone == "F" || utm.latZone == "G" || utm.latZone == "H" || utm.latZone == "J" || utm.latZone == "K" || utm.latZone == "L" || utm.latZone == "M") {
+ southhemi = true;
+ }
+
+ Double cmeridian;
+
+ Double x = utm.Easting - 500000.0;
+ Double UTMScaleFactor = 0.9996;
+ x /= UTMScaleFactor;
+
+ /* If in southern hemisphere, adjust y accordingly. */
+ Double y = utm.Northing;
+ if (southhemi) {
+ y -= 10000000.0;
+ }
+
+ y /= UTMScaleFactor;
+
+ cmeridian = UTMCentralMeridian(utm.LongZone);
+
+ Coordinate c = UTMtoLatLong(x, y, cmeridian, utm.equatorial_radius, utm.inverse_flattening);
+
+ if (c.Latitude.ToDouble() > 85 || c.Latitude.ToDouble() < -85) {
+ Debug.WriteLine("UTM conversions greater than 85 degrees or less than -85 degree latitude contain major deviations and should be used with caution.");
+ }
+ return c;
+
+
+ }
+
+ private static Double UTMCentralMeridian(Double zone) {
+ Double cmeridian;
+
+ cmeridian = DegToRad(-183.0 + zone * 6.0);
+
+ return cmeridian;
+ }
+
+ ///
+ /// Property changed event
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+ ///
+ /// Notify property changed
+ ///
+ /// Property name
+ public void NotifyPropertyChanged(String propName) {
+ if (this.PropertyChanged != null) {
+ PropertyChanged(this, new PropertyChangedEventArgs(propName));
+ }
+ }
+ }
+
}
diff --git a/CoordinateSharp/Coordinate.cs b/CoordinateSharp/Coordinate.cs
index d03d76c..af37e20 100644
--- a/CoordinateSharp/Coordinate.cs
+++ b/CoordinateSharp/Coordinate.cs
@@ -34,8 +34,7 @@ SOFTWARE.
using System;
using System.ComponentModel;
-namespace CoordinateSharp
-{
+namespace CoordinateSharp {
///
/// Observable class for handling all location based information.
/// This is the main class for CoordinateSharp.
@@ -44,16 +43,14 @@ namespace CoordinateSharp
/// All information should be pulled from this class to include celestial information
///
[Serializable]
- public class Coordinate : INotifyPropertyChanged
- {
+ public class Coordinate : INotifyPropertyChanged {
///
/// Creates an empty Coordinate.
///
///
/// Values will need to be provided to latitude/longitude CoordinateParts manually
///
- public Coordinate()
- {
+ public Coordinate() {
this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(CoordinateType.Lat);
@@ -77,8 +74,7 @@ namespace CoordinateSharp
///
/// Values will need to be provided to latitude/longitude CoordinateParts manually
///
- internal Coordinate(Double equatorialRadius, Double inverseFlattening, Boolean t)
- {
+ internal Coordinate(Double equatorialRadius, Double inverseFlattening, Boolean _) {
this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(CoordinateType.Lat);
@@ -102,8 +98,7 @@ namespace CoordinateSharp
///
/// Geodate will default to 1/1/1900 GMT until provided
///
- public Coordinate(Double lat, Double longi)
- {
+ public Coordinate(Double lat, Double longi) {
this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
@@ -126,8 +121,7 @@ namespace CoordinateSharp
/// latitude
/// longitude
/// DateTime (UTC)
- public Coordinate(Double lat, Double longi, DateTime date)
- {
+ public Coordinate(Double lat, Double longi, DateTime date) {
this.FormatOptions = new CoordinateFormatOptions();
this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
this.longitude = new CoordinatePart(longi, CoordinateType.Long);
@@ -152,8 +146,7 @@ namespace CoordinateSharp
/// Values will need to be provided to latitude/longitude manually
///
/// Eager loading options
- public Coordinate(EagerLoad eagerLoad)
- {
+ public Coordinate(EagerLoad eagerLoad) {
this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(CoordinateType.Lat);
@@ -188,8 +181,7 @@ namespace CoordinateSharp
/// latitude
/// longitude
/// Eager loading options
- public Coordinate(Double lat, Double longi, EagerLoad eagerLoad)
- {
+ public Coordinate(Double lat, Double longi, EagerLoad eagerLoad) {
this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
@@ -223,8 +215,7 @@ namespace CoordinateSharp
/// Decimal format longitude
/// DateTime you wish to use for celestial calculation
/// Eager loading options
- public Coordinate(Double lat, Double longi, DateTime date, EagerLoad eagerLoad)
- {
+ public Coordinate(Double lat, Double longi, DateTime date, EagerLoad eagerLoad) {
this.FormatOptions = new CoordinateFormatOptions();
this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
this.longitude = new CoordinatePart(longi, CoordinateType.Long);
@@ -261,8 +252,7 @@ namespace CoordinateSharp
///
/// Latitudinal Coordinate Part
///
- public CoordinatePart Latitude
- {
+ public CoordinatePart Latitude {
get => this.latitude;
set {
if (this.latitude != value) {
@@ -292,8 +282,7 @@ namespace CoordinateSharp
///
/// Longitudinal Coordinate Part
///
- public CoordinatePart Longitude
- {
+ public CoordinatePart Longitude {
get => this.longitude;
set {
if (this.longitude != value) {
@@ -325,8 +314,7 @@ namespace CoordinateSharp
///
/// Assumes all times are in UTC
///
- public DateTime GeoDate
- {
+ public DateTime GeoDate {
get => this.geoDate;
set {
if (this.geoDate != value) {
@@ -357,8 +345,7 @@ namespace CoordinateSharp
/// Uses Ellipsoidal height with no geoid model included.
/// 0 = Mean Sea Level based on the provided Datum.
///
- public ECEF ECEF
- {
+ public ECEF ECEF {
get => this.ecef;
//Required due to GeoDetic Height
@@ -376,8 +363,7 @@ namespace CoordinateSharp
/// Used to determine what format the coordinate was parsed from.
/// Will equal "None" if Coordinate was not initialzed via a TryParse() method.
///
- public Parse_Format_Type Parse_Format
- {
+ public Parse_Format_Type Parse_Format {
get => this.parse_Format;
internal set {
if (this.parse_Format != value) {
@@ -399,8 +385,7 @@ namespace CoordinateSharp
///
/// Initialize UTM and MGRS information (required if eager loading is turned off).
///
- public void LoadUTM_MGRS_Info()
- {
+ public void LoadUTM_MGRS_Info() {
this.UTM = new UniversalTransverseMercator(this.latitude.ToDouble(), this.longitude.ToDouble(), this);
this.MGRS = new MilitaryGridReferenceSystem(this.UTM);
}
@@ -431,8 +416,7 @@ namespace CoordinateSharp
/// Overridden Coordinate ToString() method.
///
/// string (formatted).
- public override String ToString()
- {
+ public override String ToString() {
String latString = this.latitude.ToString();
String longSting = this.longitude.ToString();
return latString + " " + longSting;
@@ -444,8 +428,7 @@ namespace CoordinateSharp
///
/// CoordinateFormatOptions
/// Custom formatted coordinate
- public String ToString(CoordinateFormatOptions options)
- {
+ public String ToString(CoordinateFormatOptions options) {
String latString = this.latitude.ToString(options);
String longSting = this.longitude.ToString(options);
return latString + " " + longSting;
@@ -458,8 +441,7 @@ namespace CoordinateSharp
///
/// Equatorial Radius
/// Inverse Flattening
- public void Set_Datum(Double radius, Double flat)
- {
+ public void Set_Datum(Double radius, Double flat) {
//WGS84
//RADIUS 6378137.0;
//FLATTENING 298.257223563;
@@ -487,8 +469,7 @@ namespace CoordinateSharp
/// Equatorial Radius
/// Inverse Flattening
/// Coordinate_Datum
- public void Set_Datum(Double radius, Double flat, Coordinate_Datum cd)
- {
+ public void Set_Datum(Double radius, Double flat, Coordinate_Datum cd) {
//WGS84
//RADIUS 6378137.0;
//FLATTENING 298.257223563;
@@ -554,8 +535,7 @@ namespace CoordinateSharp
/// //New Coordinate - N 25º 4' 54.517" E 24º 57' 29.189"
///
///
- public void Move(Double distance, Double bearing, Shape shape)
- {
+ public void Move(Double distance, Double bearing, Shape shape) {
//Convert to Radians for formula
Double lat1 = this.latitude.ToRadians();
Double lon1 = this.longitude.ToRadians();
@@ -605,8 +585,7 @@ namespace CoordinateSharp
/// //New Coordinate - N 24º 56' 21.526" E 25º 4' 23.944"
///
///
- public void Move(Coordinate target, Double distance, Shape shape)
- {
+ public void Move(Coordinate target, Double distance, Shape shape) {
Distance d = new Distance(this, target, shape);
//Convert to Radians for formula
Double lat1 = this.latitude.ToRadians();
@@ -656,8 +635,7 @@ namespace CoordinateSharp
/// //New Coordinate - N 25º 4' 54.517" E 24º 57' 29.189"
///
///
- public void Move(Distance distance, Double bearing, Shape shape)
- {
+ public void Move(Distance distance, Double bearing, Shape shape) {
//Convert to Radians for formula
Double lat1 = this.latitude.ToRadians();
Double lon1 = this.longitude.ToRadians();
@@ -708,8 +686,7 @@ namespace CoordinateSharp
/// //New Coordinate - N 24º 56' 21.526" E 25º 4' 23.944"
///
///
- public void Move(Coordinate target, Distance distance, Shape shape)
- {
+ public void Move(Coordinate target, Distance distance, Shape shape) {
Distance d = new Distance(this, target, shape);
//Convert to Radians for formula
Double lat1 = this.latitude.ToRadians();
@@ -752,9 +729,7 @@ namespace CoordinateSharp
/// }
///
///
- public static Boolean TryParse(String s, out Coordinate c)
- {
- c = null;
+ public static Boolean TryParse(String s, out Coordinate c) {
if (FormatFinder.TryParse(s, CartesianType.Cartesian, out c)) {
Parse_Format_Type pft = c.Parse_Format;
c = new Coordinate(c.Latitude.ToDouble(), c.Longitude.ToDouble()) {
@@ -781,9 +756,7 @@ namespace CoordinateSharp
/// }
///
///
- public static Boolean TryParse(String s, DateTime geoDate, out Coordinate c)
- {
- c = null;
+ public static Boolean TryParse(String s, DateTime geoDate, out Coordinate c) {
if (FormatFinder.TryParse(s, CartesianType.Cartesian, out c)) {
Parse_Format_Type pft = c.Parse_Format;
c = new Coordinate(c.Latitude.ToDouble(), c.Longitude.ToDouble(), geoDate) {
@@ -810,9 +783,7 @@ namespace CoordinateSharp
/// }
///
///
- public static Boolean TryParse(String s, CartesianType ct, out Coordinate c)
- {
- c = null;
+ public static Boolean TryParse(String s, CartesianType ct, out Coordinate c) {
if (FormatFinder.TryParse(s, ct, out c)) {
Parse_Format_Type pft = c.Parse_Format;
if (ct == CartesianType.ECEF) {
@@ -845,9 +816,7 @@ namespace CoordinateSharp
/// }
///
///
- public static Boolean TryParse(String s, DateTime geoDate, CartesianType ct, out Coordinate c)
- {
- c = null;
+ public static Boolean TryParse(String s, DateTime geoDate, CartesianType ct, out Coordinate c) {
if (FormatFinder.TryParse(s, ct, out c)) {
Parse_Format_Type pft = c.Parse_Format;
if (ct == CartesianType.ECEF) {
@@ -872,8 +841,7 @@ namespace CoordinateSharp
/// Notify property changed
///
/// Property name
- public void NotifyPropertyChanged(String propName)
- {
+ public void NotifyPropertyChanged(String propName) {
switch (propName) {
case "CelestialInfo":
if (!this.EagerLoadSettings.Celestial || this.CelestialInfo == null) { return; } //Prevent Null Exceptions and calls while eagerloading is off
@@ -913,8 +881,7 @@ namespace CoordinateSharp
/// Objects can be passed to Coordinate object Latitude and Longitude properties.
///
[Serializable]
- public class CoordinatePart : INotifyPropertyChanged
- {
+ public class CoordinatePart : INotifyPropertyChanged {
//Defaults:
//Format: Degrees Minutes Seconds
//Rounding: Dependent upon selected format
@@ -941,8 +908,7 @@ namespace CoordinateSharp
///
/// Observable decimal format coordinate.
///
- public Double DecimalDegree
- {
+ public Double DecimalDegree {
get => this.decimalDegree;
set {
//If changing, notify the needed property changes
@@ -1018,8 +984,7 @@ namespace CoordinateSharp
///
/// Observable decimal format minute.
///
- public Double DecimalMinute
- {
+ public Double DecimalMinute {
get => this.decimalMinute;
set {
if (this.decimalMinute != value) {
@@ -1048,7 +1013,7 @@ namespace CoordinateSharp
Decimal newDM = decValue / 60; //divide decimalMinute by 60 to get storage value
Decimal newDD = this.degrees + newDM;//Add new decimal value to the floor degree value to get new decimalDegree;
- if (this.decimalDegree < 0) { newDD = newDD * -1; } //Restore negative if needed
+ if (this.decimalDegree < 0) { newDD *= -1; } //Restore negative if needed
this.decimalDegree = Convert.ToDouble(newDD); //Convert back to double for storage
@@ -1064,8 +1029,7 @@ namespace CoordinateSharp
///
/// Observable coordinate degree.
///
- public Int32 Degrees
- {
+ public Int32 Degrees {
get => this.degrees;
set {
//Validate Value
@@ -1105,8 +1069,7 @@ namespace CoordinateSharp
///
/// Observable coordinate minute.
///
- public Int32 Minutes
- {
+ public Int32 Minutes {
get => this.minutes;
set {
if (this.minutes != value) {
@@ -1114,9 +1077,9 @@ namespace CoordinateSharp
//Validate the minutes
Decimal vMin = Convert.ToDecimal(value);
if (this.type == CoordinateType.Lat) {
- if (this.degrees + (vMin / 60) > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal degrees cannot be greater than 90"); }
+ if (this.degrees + vMin / 60 > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal degrees cannot be greater than 90"); }
} else {
- if (this.degrees + (vMin / 60) > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal degrees cannot be greater than 180"); }
+ if (this.degrees + vMin / 60 > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal degrees cannot be greater than 180"); }
}
if (value >= 60) {
throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60");
@@ -1154,8 +1117,7 @@ namespace CoordinateSharp
///
/// Observable coordinate second.
///
- public Double Seconds
- {
+ public Double Seconds {
get => this.seconds;
set {
if (value < 0) { value *= -1; }//Adjust accidental negative input
@@ -1182,9 +1144,9 @@ namespace CoordinateSharp
this.seconds = value;
- Double degABS = Math.Abs(this.decimalDegree); //Make decimalDegree positive
- Double degFloor = Math.Truncate(degABS); //Truncate the number left of the decimal
- Decimal f = Convert.ToDecimal(degFloor); //Convert to decimal to keep precision
+ //Double degABS = Math.Abs(this.decimalDegree); //Make decimalDegree positive
+ //Double degFloor = Math.Truncate(degABS); //Truncate the number left of the decimal
+ //Decimal f = Convert.ToDecimal(degFloor); //Convert to decimal to keep precision
Decimal secs = Convert.ToDecimal(this.seconds); //Convert seconds to decimal for calculations
secs /= 60; //Convert to storage format
@@ -1207,8 +1169,7 @@ namespace CoordinateSharp
///
/// Observable coordinate position.
///
- public CoordinatesPosition Position
- {
+ public CoordinatesPosition Position {
get => this.position;
set {
if (this.position != value) {
@@ -1231,8 +1192,7 @@ namespace CoordinateSharp
/// CoordinateType
/// Parent Coordinate object
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")]
- public CoordinatePart(CoordinateType t, Coordinate c)
- {
+ public CoordinatePart(CoordinateType t, Coordinate c) {
this.parent = c;
this.type = t;
this.decimalDegree = 0;
@@ -1248,8 +1208,7 @@ namespace CoordinateSharp
/// Coordinate type
/// Parent Coordinate object
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")]
- public CoordinatePart(Double value, CoordinateType t, Coordinate c)
- {
+ public CoordinatePart(Double value, CoordinateType t, Coordinate c) {
this.parent = c;
this.type = t;
@@ -1287,8 +1246,7 @@ namespace CoordinateSharp
/// Coordinate Part Position
/// Parent Coordinate
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")]
- public CoordinatePart(Int32 deg, Int32 min, Double sec, CoordinatesPosition pos, Coordinate c)
- {
+ public CoordinatePart(Int32 deg, Int32 min, Double sec, CoordinatesPosition pos, Coordinate c) {
this.parent = c;
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
@@ -1308,12 +1266,12 @@ namespace CoordinateSharp
minD += secD; //Decimal Minutes
if (this.type == CoordinateType.Long) {
- if (deg + (minD / 60) > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal Degrees cannot be greater than 180."); }
+ if (deg + minD / 60 > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal Degrees cannot be greater than 180."); }
} else {
- if (deg + (minD / 60) > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal Degrees cannot be greater than 90."); }
+ if (deg + minD / 60 > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal Degrees cannot be greater than 90."); }
}
this.decimalMinute = Convert.ToDouble(minD);
- Decimal dd = Convert.ToDecimal(deg) + (minD / 60);
+ Decimal dd = Convert.ToDecimal(deg) + minD / 60;
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
@@ -1329,8 +1287,7 @@ namespace CoordinateSharp
/// Coordinate Part Position
/// Parent Coordinate object
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")]
- public CoordinatePart(Int32 deg, Double minSec, CoordinatesPosition pos, Coordinate c)
- {
+ public CoordinatePart(Int32 deg, Double minSec, CoordinatesPosition pos, Coordinate c) {
this.parent = c;
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
@@ -1341,9 +1298,9 @@ namespace CoordinateSharp
if (minSec >= 60) { throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60."); }
if (this.type == CoordinateType.Lat) {
- if (deg + (minSec / 60) > 90) { throw new ArgumentOutOfRangeException("Degree out of range", "Latitudinal degrees cannot be greater than 90."); }
+ if (deg + minSec / 60 > 90) { throw new ArgumentOutOfRangeException("Degree out of range", "Latitudinal degrees cannot be greater than 90."); }
} else {
- if (deg + (minSec / 60) > 180) { throw new ArgumentOutOfRangeException("Degree out of range", "Longitudinal degrees cannot be greater than 180."); }
+ if (deg + minSec / 60 > 180) { throw new ArgumentOutOfRangeException("Degree out of range", "Longitudinal degrees cannot be greater than 180."); }
}
this.degrees = deg;
this.decimalMinute = minSec;
@@ -1356,7 +1313,7 @@ namespace CoordinateSharp
sec *= 60;
Decimal secD = Convert.ToDecimal(sec);
this.seconds = Convert.ToDouble(secD);
- Decimal dd = deg + (minD / 60);
+ Decimal dd = deg + minD / 60;
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
dd *= -1;
@@ -1368,8 +1325,7 @@ namespace CoordinateSharp
/// Creates an empty CoordinatePart.
///
/// CoordinateType
- public CoordinatePart(CoordinateType t)
- {
+ public CoordinatePart(CoordinateType t) {
this.type = t;
this.decimalDegree = 0;
this.degrees = 0;
@@ -1382,8 +1338,7 @@ namespace CoordinateSharp
///
/// Coordinate decimal value
/// Coordinate type
- public CoordinatePart(Double value, CoordinateType t)
- {
+ public CoordinatePart(Double value, CoordinateType t) {
this.type = t;
if (this.type == CoordinateType.Long) {
@@ -1418,8 +1373,7 @@ namespace CoordinateSharp
/// Minutes
/// Seconds
/// Coordinate Part Position
- public CoordinatePart(Int32 deg, Int32 min, Double sec, CoordinatesPosition pos)
- {
+ public CoordinatePart(Int32 deg, Int32 min, Double sec, CoordinatesPosition pos) {
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
if (deg < 0) { throw new ArgumentOutOfRangeException("Degrees out of range", "Degrees cannot be less than 0."); }
@@ -1438,12 +1392,12 @@ namespace CoordinateSharp
minD += secD; //Decimal Minutes
if (this.type == CoordinateType.Long) {
- if (deg + (minD / 60) > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal Degrees cannot be greater than 180."); }
+ if (deg + minD / 60 > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal Degrees cannot be greater than 180."); }
} else {
- if (deg + (minD / 60) > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal Degrees cannot be greater than 90."); }
+ if (deg + minD / 60 > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal Degrees cannot be greater than 90."); }
}
this.decimalMinute = Convert.ToDouble(minD);
- Decimal dd = Convert.ToDecimal(deg) + (minD / 60);
+ Decimal dd = Convert.ToDecimal(deg) + minD / 60;
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
@@ -1457,8 +1411,7 @@ namespace CoordinateSharp
/// Degrees
/// Decimal Minutes
/// Coordinate Part Position
- public CoordinatePart(Int32 deg, Double minSec, CoordinatesPosition pos)
- {
+ public CoordinatePart(Int32 deg, Double minSec, CoordinatesPosition pos) {
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
if (deg < 0) { throw new ArgumentOutOfRangeException("Degree out of range", "Degree cannot be less than 0."); }
@@ -1467,9 +1420,9 @@ namespace CoordinateSharp
if (minSec >= 60) { throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60."); }
if (this.type == CoordinateType.Lat) {
- if (deg + (minSec / 60) > 90) { throw new ArgumentOutOfRangeException("Degree out of range", "Latitudinal degrees cannot be greater than 90."); }
+ if (deg + minSec / 60 > 90) { throw new ArgumentOutOfRangeException("Degree out of range", "Latitudinal degrees cannot be greater than 90."); }
} else {
- if (deg + (minSec / 60) > 180) { throw new ArgumentOutOfRangeException("Degree out of range", "Longitudinal degrees cannot be greater than 180."); }
+ if (deg + minSec / 60 > 180) { throw new ArgumentOutOfRangeException("Degree out of range", "Longitudinal degrees cannot be greater than 180."); }
}
this.degrees = deg;
this.decimalMinute = minSec;
@@ -1482,7 +1435,7 @@ namespace CoordinateSharp
sec *= 60;
Decimal secD = Convert.ToDecimal(sec);
this.seconds = Convert.ToDouble(secD);
- Decimal dd = deg + (minD / 60);
+ Decimal dd = deg + minD / 60;
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
dd *= -1;
@@ -1513,46 +1466,25 @@ namespace CoordinateSharp
///
/// CoordinateFormatOptions
/// Formatted coordinate part string
- private String FormatString(CoordinateFormatOptions options)
- {
- ToStringType type = ToStringType.Degree_Minute_Second;
- Int32? rounding = null;
- Boolean lead = false;
- Boolean trail = false;
- Boolean hyphen = false;
- Boolean symbols = true;
- Boolean degreeSymbol = true;
- Boolean minuteSymbol = true;
- Boolean secondsSymbol = true;
- Boolean positionFirst = true;
-
+ private String FormatString(CoordinateFormatOptions options) {
#region Assign Formatting Rules
- switch (options.Format) {
- case CoordinateFormatType.Degree_Minutes_Seconds:
- type = ToStringType.Degree_Minute_Second;
- break;
- case CoordinateFormatType.Degree_Decimal_Minutes:
- type = ToStringType.Degree_Decimal_Minute;
- break;
- case CoordinateFormatType.Decimal_Degree:
- type = ToStringType.Decimal_Degree;
- break;
- case CoordinateFormatType.Decimal:
- type = ToStringType.Decimal;
- break;
- default:
- type = ToStringType.Degree_Minute_Second;
- break;
- }
- rounding = options.Round;
- lead = options.Display_Leading_Zeros;
- trail = options.Display_Trailing_Zeros;
- symbols = options.Display_Symbols;
- degreeSymbol = options.Display_Degree_Symbol;
- minuteSymbol = options.Display_Minute_Symbol;
- secondsSymbol = options.Display_Seconds_Symbol;
- hyphen = options.Display_Hyphens;
- positionFirst = options.Position_First;
+ ToStringType type = options.Format switch
+ {
+ CoordinateFormatType.Degree_Minutes_Seconds => ToStringType.Degree_Minute_Second,
+ CoordinateFormatType.Degree_Decimal_Minutes => ToStringType.Degree_Decimal_Minute,
+ CoordinateFormatType.Decimal_Degree => ToStringType.Decimal_Degree,
+ CoordinateFormatType.Decimal => ToStringType.Decimal,
+ _ => ToStringType.Degree_Minute_Second,
+ };
+ Int32? rounding = options.Round;
+ Boolean lead = options.Display_Leading_Zeros;
+ Boolean trail = options.Display_Trailing_Zeros;
+ Boolean symbols = options.Display_Symbols;
+ Boolean degreeSymbol = options.Display_Degree_Symbol;
+ Boolean minuteSymbol = options.Display_Minute_Symbol;
+ Boolean secondsSymbol = options.Display_Seconds_Symbol;
+ Boolean hyphen = options.Display_Hyphens;
+ Boolean positionFirst = options.Position_First;
#endregion
switch (type) {
@@ -1576,8 +1508,7 @@ namespace CoordinateSharp
return String.Empty;
}
//DMS Coordinate Format
- private String ToDegreeMinuteSecondString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean minuteSymbol, Boolean secondSymbol, Boolean hyphen, Boolean positionFirst)
- {
+ private String ToDegreeMinuteSecondString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean minuteSymbol, Boolean secondSymbol, Boolean hyphen, Boolean positionFirst) {
String leadString = this.Leading_Trailing_Format(lead, false, rounding, this.Position);
String d = String.Format(leadString, this.Degrees); // Degree String
@@ -1602,8 +1533,7 @@ namespace CoordinateSharp
: d + ds + hs + minute + ms + hs + second + ss + hs + this.Position.ToString();
}
//DDM Coordinate Format
- private String ToDegreeDecimalMinuteString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean minuteSymbol, Boolean hyphen, Boolean positionFirst)
- {
+ private String ToDegreeDecimalMinuteString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean minuteSymbol, Boolean hyphen, Boolean positionFirst) {
String leadString = "{0:0";
if (lead) {
if (this.Position == CoordinatesPosition.E || this.Position == CoordinatesPosition.W) {
@@ -1646,8 +1576,7 @@ namespace CoordinateSharp
}
////DD Coordinate Format
- private String ToDecimalDegreeString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean positionFirst, Boolean hyphen)
- {
+ private String ToDecimalDegreeString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean positionFirst, Boolean hyphen) {
String degreeS = "";
String hyph = " ";
if (degreeSymbol) { degreeS = "º"; }
@@ -1672,15 +1601,14 @@ namespace CoordinateSharp
}
leadTrail += "}";
- Double result = (this.Degrees) + (Convert.ToDouble(this.Minutes)) / 60 + (Convert.ToDouble(this.Seconds)) / 3600;
+ Double result = this.Degrees + Convert.ToDouble(this.Minutes) / 60 + Convert.ToDouble(this.Seconds) / 3600;
result = Math.Round(result, rounding);
String d = String.Format(leadTrail, Math.Abs(result));
return positionFirst ? this.Position.ToString() + hyph + d + degreeS : d + degreeS + hyph + this.Position.ToString();
}
- private String Leading_Trailing_Format(Boolean isLead, Boolean isTrail, Int32 rounding, CoordinatesPosition? p = null)
- {
+ private String Leading_Trailing_Format(Boolean isLead, Boolean isTrail, Int32 rounding, CoordinatesPosition? p = null) {
String leadString = "{0:0";
if (isLead) {
if (p != null) {
@@ -1706,18 +1634,16 @@ namespace CoordinateSharp
}
- private String FormatError(String argument, String rule) => "'" + argument + "' is not a valid argument for string format rule: " + rule + ".";
+ //private String FormatError(String argument, String rule) => "'" + argument + "' is not a valid argument for string format rule: " + rule + ".";
- private enum ToStringType
- {
+ private enum ToStringType {
Decimal_Degree, Degree_Decimal_Minute, Degree_Minute_Second, Decimal
}
///
/// Notify the correct properties and parent properties.
///
/// Property Type
- private void NotifyProperties(PropertyTypes p)
- {
+ private void NotifyProperties(PropertyTypes p) {
switch (p) {
case PropertyTypes.DecimalDegree:
this.NotifyPropertyChanged("DecimalDegree");
@@ -1786,8 +1712,7 @@ namespace CoordinateSharp
///
/// Used for notifying the correct properties.
///
- private enum PropertyTypes
- {
+ private enum PropertyTypes {
DecimalDegree, DecimalMinute, Position, Degree, Minute, Second, FormatChange
}
@@ -1811,12 +1736,7 @@ namespace CoordinateSharp
/// }
///
///
- public static Boolean TryParse(String s, out CoordinatePart cp)
- {
- cp = null;
-
- return FormatFinder_CoordPart.TryParse(s, out cp) ? true : false;
- }
+ public static Boolean TryParse(String s, out CoordinatePart cp) => FormatFinder_CoordPart.TryParse(s, out cp) ? true : false;
///
/// Attempts to parse a string into a CoordinatePart.
///
@@ -1833,9 +1753,7 @@ namespace CoordinateSharp
/// }
///
///
- public static Boolean TryParse(String s, CoordinateType t, out CoordinatePart cp)
- {
- cp = null;
+ public static Boolean TryParse(String s, CoordinateType t, out CoordinatePart cp) {
//Comma at beginning parses to long
//Asterik forces lat
s = t == CoordinateType.Long ? "," + s : "*" + s;
diff --git a/CoordinateSharp/CoordinateSharp_Core.csproj b/CoordinateSharp/CoordinateSharp_Core.csproj
new file mode 100644
index 0000000..186478d
--- /dev/null
+++ b/CoordinateSharp/CoordinateSharp_Core.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netcoreapp3.0
+ CoordinateSharp
+ CoordinateSharp
+ A simple .NET standard library that is designed to assist with geographic coordinate conversions, formatting and location based celestial calculations.
+ Copyright 2019
+ 1.1.5.2
+
+
+
diff --git a/CoordinateSharp/Distance.cs b/CoordinateSharp/Distance.cs
index 43434af..463acc3 100644
--- a/CoordinateSharp/Distance.cs
+++ b/CoordinateSharp/Distance.cs
@@ -1,442 +1,382 @@
using System;
using System.Diagnostics;
-namespace CoordinateSharp
-{
+
+namespace CoordinateSharp {
+ ///
+ /// Contains distance values between two coordinates.
+ ///
+ [Serializable]
+ public class Distance {
+
///
- /// Contains distance values between two coordinates.
+ /// Initializes a distance object using Haversine (Spherical Earth).
///
- [Serializable]
- public class Distance
- {
- private double kilometers;
- private double miles;
- private double feet;
- private double meters;
- private double bearing;
- private double nauticalMiles;
-
- ///
- /// Initializes a distance object using Haversine (Spherical Earth).
- ///
- /// Coordinate 1
- /// Coordinate 2
- public Distance(Coordinate c1, Coordinate c2)
- {
- Haversine(c1, c2);
- }
- ///
- /// Initializes a distance object using Haversine (Spherical Earth) or Vincenty (Elliptical Earth).
- ///
- /// Coordinate 1
- /// Coordinate 2
- /// Shape of earth
- public Distance(Coordinate c1, Coordinate c2, Shape shape)
- {
- if (shape == Shape.Sphere)
- {
- Haversine(c1, c2);
- }
- else
- {
- Vincenty(c1, c2);
- }
- }
- ///
- /// Initializes distance object based on distance in KM
- ///
- /// Kilometers
- public Distance(double km)
- {
- kilometers = km;
- meters = km * 1000;
- feet = meters * 3.28084;
- miles = meters * 0.000621371;
- nauticalMiles = meters * 0.0005399565;
- bearing = 0;//None specified
- }
- ///
- /// Initializaes distance object based on specified distance and measurement type
- ///
- /// Distance
- /// Measurement type
-
- public Distance(double distance, DistanceType type)
- {
- bearing = 0;
- switch (type)
- {
- case DistanceType.Feet:
- feet = distance;
- meters = feet * 0.3048;
- kilometers = meters / 1000;
- miles = meters * 0.000621371;
- nauticalMiles = meters * 0.0005399565;
- break;
- case DistanceType.Kilometers:
- kilometers = distance;
- meters = kilometers * 1000;
- feet = meters * 3.28084;
- miles = meters * 0.000621371;
- nauticalMiles = meters * 0.0005399565;
- break;
- case DistanceType.Meters:
- meters = distance;
- kilometers = meters / 1000;
- feet = meters * 3.28084;
- miles = meters * 0.000621371;
- nauticalMiles = meters * 0.0005399565;
- break;
- case DistanceType.Miles:
- miles = distance;
- meters = miles * 1609.344;
- feet = meters * 3.28084;
- kilometers = meters / 1000;
- nauticalMiles = meters * 0.0005399565;
- break;
- case DistanceType.NauticalMiles:
- nauticalMiles = distance;
- meters = nauticalMiles * 1852.001;
- feet = meters * 3.28084;
- kilometers = meters / 1000;
- miles = meters * 0.000621371;
- break;
- default:
- kilometers = distance;
- meters = distance * 1000;
- feet = meters * 3.28084;
- miles = meters * 0.000621371;
- nauticalMiles = meters * 0.0005399565;
- break;
- }
- }
- private void Vincenty(Coordinate coord1, Coordinate coord2)
- {
- double lat1, lat2, lon1, lon2;
- double d, crs12, crs21;
-
-
- lat1 = coord1.Latitude.ToRadians();
- lat2 = coord2.Latitude.ToRadians();
- lon1 = coord1.Longitude.ToRadians() * -1; //REVERSE FOR CALC 2.1.1.1
- lon2 = coord2.Longitude.ToRadians() * -1; //REVERSE FOR CALC 2.1.1.1
-
- //Ensure datums match between coords
- if ((coord1.equatorial_radius != coord2.equatorial_radius) || (coord1.inverse_flattening != coord2.inverse_flattening))
- {
- throw new InvalidOperationException("The datum set does not match between Coordinate objects.");
- }
- double[] ellipse = new double[] { coord1.equatorial_radius, coord1.inverse_flattening };
-
-
- // elliptic code
- double[] cde = Distance_Assistant.Dist_Ell(lat1, -lon1, lat2, -lon2, ellipse); // ellipse uses East negative
- crs12 = cde[1] * (180 / Math.PI); //Bearing
- crs21 = cde[2] * (180 / Math.PI); //Reverse Bearing
- d = cde[0]; //Distance
-
- bearing = crs12;
- //reverseBearing = crs21;
- meters = d;
- kilometers = d / 1000;
- feet = d * 3.28084;
- miles = d * 0.000621371;
- nauticalMiles = d * 0.0005399565;
-
- }
-
- private void Haversine(Coordinate coord1, Coordinate coord2)
- {
- ////RADIANS
- double lat1 = coord1.Latitude.ToRadians();
- double long1 = coord1.Longitude.ToRadians();
- double lat2 = coord2.Latitude.ToRadians();
- double long2 = coord2.Longitude.ToRadians();
-
- //Distance Calcs
- double R = 6371000; //6378137.0;//6371e3; //meters
- double latRad = coord2.Latitude.ToRadians() - coord1.Latitude.ToRadians();
- double longRad = coord2.Longitude.ToRadians() - coord1.Longitude.ToRadians();
-
- double a = Math.Sin(latRad / 2.0) * Math.Sin(latRad / 2.0) +
- Math.Cos(lat1) * Math.Cos(lat2) * Math.Sin(longRad / 2.0) * Math.Sin(longRad / 2.0);
- double cl = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
- double dist = R * cl;
-
- //Get bearing
- double dLong = long2 - long1;
- double y = Math.Sin(dLong) * Math.Cos(lat2);
- double x = Math.Cos(lat1) * Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(dLong);
- double brng = Math.Atan2(y, x) * (180 / Math.PI); //Convert bearing back to degrees.
-
- //if (brng < 0) { brng -= 180; brng = Math.Abs(brng); }
- brng = (brng + 360) % 360; //v2.1.1.1 NORMALIZE HEADING
-
- kilometers = dist / 1000;
- meters = dist;
- feet = dist * 3.28084;
- miles = dist * 0.000621371;
- nauticalMiles = dist * 0.0005399565;
- bearing = brng;
- }
- ///
- /// Distance in Kilometers
- ///
- public double Kilometers
- {
- get { return kilometers; }
- }
- ///
- /// Distance in Statute Miles
- ///
- public double Miles
- {
- get { return miles; }
- }
- ///
- /// Distance in Nautical Miles
- ///
- public double NauticalMiles
- {
- get { return nauticalMiles; }
- }
- ///
- /// Distance in Meters
- ///
- public double Meters
- {
- get { return meters; }
- }
- ///
- /// Distance in Feet
- ///
- public double Feet
- {
- get { return feet; }
- }
- ///
- /// Initial Bearing from Coordinate 1 to Coordinate 2
- ///
- public double Bearing
- {
- get { return bearing; }
- }
+ /// Coordinate 1
+ /// Coordinate 2
+ public Distance(Coordinate c1, Coordinate c2) => this.Haversine(c1, c2);
+ ///
+ /// Initializes a distance object using Haversine (Spherical Earth) or Vincenty (Elliptical Earth).
+ ///
+ /// Coordinate 1
+ /// Coordinate 2
+ /// Shape of earth
+ public Distance(Coordinate c1, Coordinate c2, Shape shape) {
+ if (shape == Shape.Sphere) {
+ this.Haversine(c1, c2);
+ } else {
+ this.Vincenty(c1, c2);
+ }
}
///
- /// Distance measurement type
+ /// Initializes distance object based on distance in KM
///
- public enum DistanceType
- {
- ///
- /// Distance in Meters
- ///
- Meters,
- ///
- /// Distance in Kilometers
- ///
- Kilometers,
- ///
- /// Distance in Feet
- ///
- Feet,
- ///
- /// Distance in Statute Miles
- ///
- Miles,
- ///
- /// Distance in Nautical Miles
- ///
- NauticalMiles
+ /// Kilometers
+ public Distance(Double km) {
+ this.Kilometers = km;
+ this.Meters = km * 1000;
+ this.Feet = this.Meters * 3.28084;
+ this.Miles = this.Meters * 0.000621371;
+ this.NauticalMiles = this.Meters * 0.0005399565;
+ this.Bearing = 0;//None specified
+ }
+ ///
+ /// Initializaes distance object based on specified distance and measurement type
+ ///
+ /// Distance
+ /// Measurement type
+
+ public Distance(Double distance, DistanceType type) {
+ this.Bearing = 0;
+ switch (type) {
+ case DistanceType.Feet:
+ this.Feet = distance;
+ this.Meters = this.Feet * 0.3048;
+ this.Kilometers = this.Meters / 1000;
+ this.Miles = this.Meters * 0.000621371;
+ this.NauticalMiles = this.Meters * 0.0005399565;
+ break;
+ case DistanceType.Kilometers:
+ this.Kilometers = distance;
+ this.Meters = this.Kilometers * 1000;
+ this.Feet = this.Meters * 3.28084;
+ this.Miles = this.Meters * 0.000621371;
+ this.NauticalMiles = this.Meters * 0.0005399565;
+ break;
+ case DistanceType.Meters:
+ this.Meters = distance;
+ this.Kilometers = this.Meters / 1000;
+ this.Feet = this.Meters * 3.28084;
+ this.Miles = this.Meters * 0.000621371;
+ this.NauticalMiles = this.Meters * 0.0005399565;
+ break;
+ case DistanceType.Miles:
+ this.Miles = distance;
+ this.Meters = this.Miles * 1609.344;
+ this.Feet = this.Meters * 3.28084;
+ this.Kilometers = this.Meters / 1000;
+ this.NauticalMiles = this.Meters * 0.0005399565;
+ break;
+ case DistanceType.NauticalMiles:
+ this.NauticalMiles = distance;
+ this.Meters = this.NauticalMiles * 1852.001;
+ this.Feet = this.Meters * 3.28084;
+ this.Kilometers = this.Meters / 1000;
+ this.Miles = this.Meters * 0.000621371;
+ break;
+ default:
+ this.Kilometers = distance;
+ this.Meters = distance * 1000;
+ this.Feet = this.Meters * 3.28084;
+ this.Miles = this.Meters * 0.000621371;
+ this.NauticalMiles = this.Meters * 0.0005399565;
+ break;
+ }
+ }
+ private void Vincenty(Coordinate coord1, Coordinate coord2) {
+ Double lat1, lat2, lon1, lon2;
+ Double d, crs12;
+
+
+ lat1 = coord1.Latitude.ToRadians();
+ lat2 = coord2.Latitude.ToRadians();
+ lon1 = coord1.Longitude.ToRadians() * -1; //REVERSE FOR CALC 2.1.1.1
+ lon2 = coord2.Longitude.ToRadians() * -1; //REVERSE FOR CALC 2.1.1.1
+
+ //Ensure datums match between coords
+ if (coord1.equatorial_radius != coord2.equatorial_radius || coord1.inverse_flattening != coord2.inverse_flattening) {
+ throw new InvalidOperationException("The datum set does not match between Coordinate objects.");
+ }
+ Double[] ellipse = new Double[] { coord1.equatorial_radius, coord1.inverse_flattening };
+
+
+ // elliptic code
+ Double[] cde = Distance_Assistant.Dist_Ell(lat1, -lon1, lat2, -lon2, ellipse); // ellipse uses East negative
+ crs12 = cde[1] * (180 / Math.PI); //Bearing
+ _ = cde[2] * (180 / Math.PI); //Reverse Bearing
+ d = cde[0]; //Distance
+
+ this.Bearing = crs12;
+ //reverseBearing = crs21;
+ this.Meters = d;
+ this.Kilometers = d / 1000;
+ this.Feet = d * 3.28084;
+ this.Miles = d * 0.000621371;
+ this.NauticalMiles = d * 0.0005399565;
+
}
- [Serializable]
- internal class Distance_Assistant
- {
- ///
- /// Returns new geodetic coordinate in radians
- ///
- /// Latitude in Radians
- /// Longitude in Radians
- /// Bearing
- /// Distance
- /// Earth Ellipse Values
- /// double[]
- public static double[] Direct_Ell(double glat1, double glon1, double faz, double s, double[] ellipse)
- {
- glon1 *= -1; //REVERSE LONG FOR CALC 2.1.1.1
- double EPS = 0.00000000005;//Used to determine if starting at pole.
- double r, tu, sf, cf, b, cu, su, sa, c2a, x, c, d, y, sy = 0, cy = 0, cz = 0, e = 0;
- double glat2, glon2, f;
+ private void Haversine(Coordinate coord1, Coordinate coord2) {
+ ////RADIANS
+ Double lat1 = coord1.Latitude.ToRadians();
+ Double long1 = coord1.Longitude.ToRadians();
+ Double lat2 = coord2.Latitude.ToRadians();
+ Double long2 = coord2.Longitude.ToRadians();
- //Determine if near pole
- if ((Math.Abs(Math.Cos(glat1)) < EPS) && !(Math.Abs(Math.Sin(faz)) < EPS))
- {
- Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
- }
+ //Distance Calcs
+ Double R = 6371000; //6378137.0;//6371e3; //meters
+ Double latRad = coord2.Latitude.ToRadians() - coord1.Latitude.ToRadians();
+ Double longRad = coord2.Longitude.ToRadians() - coord1.Longitude.ToRadians();
+ Double a = Math.Sin(latRad / 2.0) * Math.Sin(latRad / 2.0) +
+ Math.Cos(lat1) * Math.Cos(lat2) * Math.Sin(longRad / 2.0) * Math.Sin(longRad / 2.0);
+ Double cl = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
+ Double dist = R * cl;
- double a = ellipse[0];//Equitorial Radius
- f = 1 / ellipse[1];//Flattening
- r = 1 - f;
- tu = r * Math.Tan(glat1);
- sf = Math.Sin(faz);
- cf = Math.Cos(faz);
- if (cf == 0)
- {
- b = 0.0;
- }
- else
- {
- b = 2.0 * Math.Atan2(tu, cf);
- }
- cu = 1.0 / Math.Sqrt(1 + tu * tu);
- su = tu * cu;
- sa = cu * sf;
- c2a = 1 - sa * sa;
- x = 1.0 + Math.Sqrt(1.0 + c2a * (1.0 / (r * r) - 1.0));
- x = (x - 2.0) / x;
- c = 1.0 - x;
- c = (x * x / 4.0 + 1.0) / c;
- d = (0.375 * x * x - 1.0) * x;
- tu = s / (r * a * c);
- y = tu;
- c = y + 1;
- while (Math.Abs(y - c) > EPS)
- {
- sy = Math.Sin(y);
- cy = Math.Cos(y);
- cz = Math.Cos(b + y);
- e = 2.0 * cz * cz - 1.0;
- c = y;
- x = e * cy;
- y = e + e - 1.0;
- y = (((sy * sy * 4.0 - 3.0) * y * cz * d / 6.0 + x) *
- d / 4.0 - cz) * sy * d + tu;
- }
+ //Get bearing
+ Double dLong = long2 - long1;
+ Double y = Math.Sin(dLong) * Math.Cos(lat2);
+ Double x = Math.Cos(lat1) * Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(dLong);
+ Double brng = Math.Atan2(y, x) * (180 / Math.PI); //Convert bearing back to degrees.
- b = cu * cy * cf - su * sy;
- c = r * Math.Sqrt(sa * sa + b * b);
- d = su * cy + cu * sy * cf;
+ //if (brng < 0) { brng -= 180; brng = Math.Abs(brng); }
+ brng = (brng + 360) % 360; //v2.1.1.1 NORMALIZE HEADING
- glat2 = ModM.ModLat(Math.Atan2(d, c));
- c = cu * cy - su * sy * cf;
- x = Math.Atan2(sy * sf, c);
- c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
- d = ((e * cy * c + cz) * sy * c + y) * sa;
- glon2 = ModM.ModLon(glon1 + x - (1.0 - c) * d * f); //Adjust for IDL
- //baz = ModM.ModCrs(Math.Atan2(sa, b) + Math.PI);
- return new double[] { glat2, glon2 };
- }
- ///
- /// Returns new geodetic coordinate in radians
- ///
- /// Latitude in radians
- /// Longitude in radians
- /// Bearing
- /// Distance
- /// double[]
- public static double[] Direct(double lat1, double lon1, double crs12, double d12)
- {
- lon1 *= -1; //REVERSE LONG FOR CALC 2.1.1.1
- var EPS = 0.00000000005;//Used to determine if near pole.
- double dlon, lat, lon;
- d12 = d12 * 0.0005399565; //convert meter to nm
- d12 = d12 / (180 * 60 / Math.PI);//Convert to Radian
- //Determine if near pole
- if ((Math.Abs(Math.Cos(lat1)) < EPS) && !(Math.Abs(Math.Sin(crs12)) < EPS))
- {
- Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
- }
-
- lat = Math.Asin(Math.Sin(lat1) * Math.Cos(d12) +
- Math.Cos(lat1) * Math.Sin(d12) * Math.Cos(crs12));
- if (Math.Abs(Math.Cos(lat)) < EPS)
- {
- lon = 0.0; //endpoint a pole
- }
- else
- {
- dlon = Math.Atan2(Math.Sin(crs12) * Math.Sin(d12) * Math.Cos(lat1),
- Math.Cos(d12) - Math.Sin(lat1) * Math.Sin(lat));
- lon = ModM.Mod(lon1 - dlon + Math.PI, 2 * Math.PI) - Math.PI;
- }
-
- return new double[] { lat, lon };
- }
- public static double[] Dist_Ell(double glat1, double glon1, double glat2, double glon2, double[] ellipse)
- {
- double a = ellipse[0]; //Equitorial Radius
- double f = 1 / ellipse[1]; //Flattening
-
- double r, tu1, tu2, cu1, su1, cu2, s1, b1, f1;
- double x = 0, sx = 0, cx = 0, sy = 0, cy = 0, y = 0, sa = 0, c2a = 0, cz = 0, e = 0, c = 0, d = 0;
- double EPS = 0.00000000005;
- double faz, baz, s;
- double iter = 1;
- double MAXITER = 100;
- if ((glat1 + glat2 == 0.0) && (Math.Abs(glon1 - glon2) == Math.PI))
- {
- Debug.WriteLine("Warning: Course and distance between antipodal points is undefined");
- glat1 = glat1 + 0.00001; // allow algorithm to complete
- }
- if (glat1 == glat2 && (glon1 == glon2 || Math.Abs(Math.Abs(glon1 - glon2) - 2 * Math.PI) < EPS))
- {
- Debug.WriteLine("Warning: Points 1 and 2 are identical- course undefined");
- //D
- //crs12
- //crs21
- return new double[] { 0, 0, Math.PI };
- }
- r = 1 - f;
- tu1 = r * Math.Tan(glat1);
- tu2 = r * Math.Tan(glat2);
- cu1 = 1.0 / Math.Sqrt(1.0 + tu1 * tu1);
- su1 = cu1 * tu1;
- cu2 = 1.0 / Math.Sqrt(1.0 + tu2 * tu2);
- s1 = cu1 * cu2;
- b1 = s1 * tu2;
- f1 = b1 * tu1;
- x = glon2 - glon1;
- d = x + 1; // force one pass
- while ((Math.Abs(d - x) > EPS) && (iter < MAXITER))
- {
- iter = iter + 1;
- sx = Math.Sin(x);
- cx = Math.Cos(x);
- tu1 = cu2 * sx;
- tu2 = b1 - su1 * cu2 * cx;
- sy = Math.Sqrt(tu1 * tu1 + tu2 * tu2);
- cy = s1 * cx + f1;
- y = Math.Atan2(sy, cy);
- sa = s1 * sx / sy;
- c2a = 1 - sa * sa;
- cz = f1 + f1;
- if (c2a > 0.0)
- {
- cz = cy - cz / c2a;
- }
- e = cz * cz * 2.0 - 1.0;
- c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
- d = x;
- x = ((e * cy * c + cz) * sy * c + y) * sa;
- x = (1.0 - c) * x * f + glon2 - glon1;
- }
- faz = ModM.ModCrs(Math.Atan2(tu1, tu2));
- baz = ModM.ModCrs(Math.Atan2(cu1 * sx, b1 * cx - su1 * cu2) + Math.PI);
- x = Math.Sqrt((1 / (r * r) - 1) * c2a + 1);
- x += 1;
- x = (x - 2.0) / x;
- c = 1.0 - x;
- c = (x * x / 4.0 + 1.0) / c;
- d = (0.375 * x * x - 1.0) * x;
- x = e * cy;
- s = ((((sy * sy * 4.0 - 3.0) * (1.0 - e - e) * cz * d / 6.0 - x) * d / 4.0 + cz) * sy * d + y) * c * a * r;
-
- if (Math.Abs(iter - MAXITER) < EPS)
- {
- Debug.WriteLine("Warning: Distance algorithm did not converge");
- }
-
- return new double[] { s, faz, baz };
- }
+ this.Kilometers = dist / 1000;
+ this.Meters = dist;
+ this.Feet = dist * 3.28084;
+ this.Miles = dist * 0.000621371;
+ this.NauticalMiles = dist * 0.0005399565;
+ this.Bearing = brng;
}
+ ///
+ /// Distance in Kilometers
+ ///
+ public Double Kilometers { get; private set; }
+ ///
+ /// Distance in Statute Miles
+ ///
+ public Double Miles { get; private set; }
+ ///
+ /// Distance in Nautical Miles
+ ///
+ public Double NauticalMiles { get; private set; }
+ ///
+ /// Distance in Meters
+ ///
+ public Double Meters { get; private set; }
+ ///
+ /// Distance in Feet
+ ///
+ public Double Feet { get; private set; }
+ ///
+ /// Initial Bearing from Coordinate 1 to Coordinate 2
+ ///
+ public Double Bearing { get; private set; }
+ }
+ ///
+ /// Distance measurement type
+ ///
+ public enum DistanceType {
+ ///
+ /// Distance in Meters
+ ///
+ Meters,
+ ///
+ /// Distance in Kilometers
+ ///
+ Kilometers,
+ ///
+ /// Distance in Feet
+ ///
+ Feet,
+ ///
+ /// Distance in Statute Miles
+ ///
+ Miles,
+ ///
+ /// Distance in Nautical Miles
+ ///
+ NauticalMiles
+ }
+
+ [Serializable]
+ internal class Distance_Assistant {
+ ///
+ /// Returns new geodetic coordinate in radians
+ ///
+ /// Latitude in Radians
+ /// Longitude in Radians
+ /// Bearing
+ /// Distance
+ /// Earth Ellipse Values
+ /// double[]
+ public static Double[] Direct_Ell(Double glat1, Double glon1, Double faz, Double s, Double[] ellipse) {
+ glon1 *= -1; //REVERSE LONG FOR CALC 2.1.1.1
+ Double EPS = 0.00000000005;//Used to determine if starting at pole.
+ Double r, tu, sf, cf, b, cu, su, sa, c2a, x, c, d, y, sy = 0, cy = 0, cz = 0, e = 0;
+ Double glat2, glon2, f;
+
+ //Determine if near pole
+ if (Math.Abs(Math.Cos(glat1)) < EPS && !(Math.Abs(Math.Sin(faz)) < EPS)) {
+ Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
+ }
+
+
+ Double a = ellipse[0];//Equitorial Radius
+ f = 1 / ellipse[1];//Flattening
+ r = 1 - f;
+ tu = r * Math.Tan(glat1);
+ sf = Math.Sin(faz);
+ cf = Math.Cos(faz);
+ b = cf == 0 ? 0.0 : 2.0 * Math.Atan2(tu, cf);
+ cu = 1.0 / Math.Sqrt(1 + tu * tu);
+ su = tu * cu;
+ sa = cu * sf;
+ c2a = 1 - sa * sa;
+ x = 1.0 + Math.Sqrt(1.0 + c2a * (1.0 / (r * r) - 1.0));
+ x = (x - 2.0) / x;
+ c = 1.0 - x;
+ c = (x * x / 4.0 + 1.0) / c;
+ d = (0.375 * x * x - 1.0) * x;
+ tu = s / (r * a * c);
+ y = tu;
+ c = y + 1;
+ while (Math.Abs(y - c) > EPS) {
+ sy = Math.Sin(y);
+ cy = Math.Cos(y);
+ cz = Math.Cos(b + y);
+ e = 2.0 * cz * cz - 1.0;
+ c = y;
+ x = e * cy;
+ y = e + e - 1.0;
+ y = (((sy * sy * 4.0 - 3.0) * y * cz * d / 6.0 + x) *
+ d / 4.0 - cz) * sy * d + tu;
+ }
+
+ b = cu * cy * cf - su * sy;
+ c = r * Math.Sqrt(sa * sa + b * b);
+ d = su * cy + cu * sy * cf;
+
+ glat2 = ModM.ModLat(Math.Atan2(d, c));
+ c = cu * cy - su * sy * cf;
+ x = Math.Atan2(sy * sf, c);
+ c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
+ d = ((e * cy * c + cz) * sy * c + y) * sa;
+ glon2 = ModM.ModLon(glon1 + x - (1.0 - c) * d * f); //Adjust for IDL
+ //baz = ModM.ModCrs(Math.Atan2(sa, b) + Math.PI);
+ return new Double[] { glat2, glon2 };
+ }
+ ///
+ /// Returns new geodetic coordinate in radians
+ ///
+ /// Latitude in radians
+ /// Longitude in radians
+ /// Bearing
+ /// Distance
+ /// double[]
+ public static Double[] Direct(Double lat1, Double lon1, Double crs12, Double d12) {
+ lon1 *= -1; //REVERSE LONG FOR CALC 2.1.1.1
+ Double EPS = 0.00000000005;//Used to determine if near pole.
+ Double dlon, lat, lon;
+ d12 *= 0.0005399565; //convert meter to nm
+ d12 /= 180 * 60 / Math.PI;//Convert to Radian
+ //Determine if near pole
+ if (Math.Abs(Math.Cos(lat1)) < EPS && !(Math.Abs(Math.Sin(crs12)) < EPS)) {
+ Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
+ }
+
+ lat = Math.Asin(Math.Sin(lat1) * Math.Cos(d12) +
+ Math.Cos(lat1) * Math.Sin(d12) * Math.Cos(crs12));
+ if (Math.Abs(Math.Cos(lat)) < EPS) {
+ lon = 0.0; //endpoint a pole
+ } else {
+ dlon = Math.Atan2(Math.Sin(crs12) * Math.Sin(d12) * Math.Cos(lat1),
+ Math.Cos(d12) - Math.Sin(lat1) * Math.Sin(lat));
+ lon = ModM.Mod(lon1 - dlon + Math.PI, 2 * Math.PI) - Math.PI;
+ }
+
+ return new Double[] { lat, lon };
+ }
+ public static Double[] Dist_Ell(Double glat1, Double glon1, Double glat2, Double glon2, Double[] ellipse) {
+ Double a = ellipse[0]; //Equitorial Radius
+ Double f = 1 / ellipse[1]; //Flattening
+
+ Double r, tu1, tu2, cu1, su1, cu2, s1, b1, f1;
+ Double sx = 0, cx = 0, sy = 0, cy = 0, y = 0, c2a = 0, cz = 0, e = 0;
+ Double EPS = 0.00000000005;
+ Double faz, baz, s;
+ Double iter = 1;
+ Double MAXITER = 100;
+ if (glat1 + glat2 == 0.0 && Math.Abs(glon1 - glon2) == Math.PI) {
+ Debug.WriteLine("Warning: Course and distance between antipodal points is undefined");
+ glat1 += 0.00001; // allow algorithm to complete
+ }
+ if (glat1 == glat2 && (glon1 == glon2 || Math.Abs(Math.Abs(glon1 - glon2) - 2 * Math.PI) < EPS)) {
+ Debug.WriteLine("Warning: Points 1 and 2 are identical- course undefined");
+ //D
+ //crs12
+ //crs21
+ return new Double[] { 0, 0, Math.PI };
+ }
+ r = 1 - f;
+ tu1 = r * Math.Tan(glat1);
+ tu2 = r * Math.Tan(glat2);
+ cu1 = 1.0 / Math.Sqrt(1.0 + tu1 * tu1);
+ su1 = cu1 * tu1;
+ cu2 = 1.0 / Math.Sqrt(1.0 + tu2 * tu2);
+ s1 = cu1 * cu2;
+ b1 = s1 * tu2;
+ f1 = b1 * tu1;
+ Double x = glon2 - glon1;
+ Double d = x + 1;
+ Double c;
+ while (Math.Abs(d - x) > EPS && iter < MAXITER) {
+ iter += 1;
+ sx = Math.Sin(x);
+ cx = Math.Cos(x);
+ tu1 = cu2 * sx;
+ tu2 = b1 - su1 * cu2 * cx;
+ sy = Math.Sqrt(tu1 * tu1 + tu2 * tu2);
+ cy = s1 * cx + f1;
+ y = Math.Atan2(sy, cy);
+ Double sa = s1 * sx / sy;
+ c2a = 1 - sa * sa;
+ cz = f1 + f1;
+ if (c2a > 0.0) {
+ cz = cy - cz / c2a;
+ }
+ e = cz * cz * 2.0 - 1.0;
+ c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
+ d = x;
+ x = ((e * cy * c + cz) * sy * c + y) * sa;
+ x = (1.0 - c) * x * f + glon2 - glon1;
+ }
+ faz = ModM.ModCrs(Math.Atan2(tu1, tu2));
+ baz = ModM.ModCrs(Math.Atan2(cu1 * sx, b1 * cx - su1 * cu2) + Math.PI);
+ x = Math.Sqrt((1 / (r * r) - 1) * c2a + 1);
+ x += 1;
+ x = (x - 2.0) / x;
+ c = 1.0 - x;
+ c = (x * x / 4.0 + 1.0) / c;
+ d = (0.375 * x * x - 1.0) * x;
+ x = e * cy;
+ s = ((((sy * sy * 4.0 - 3.0) * (1.0 - e - e) * cz * d / 6.0 - x) * d / 4.0 + cz) * sy * d + y) * c * a * r;
+
+ if (Math.Abs(iter - MAXITER) < EPS) {
+ Debug.WriteLine("Warning: Distance algorithm did not converge");
+ }
+
+ return new Double[] { s, faz, baz };
+ }
+ }
}
diff --git a/CoordinateSharp/Eclipse/LunarData.cs b/CoordinateSharp/Eclipse/LunarData.cs
index 1630fdd..20356f7 100644
--- a/CoordinateSharp/Eclipse/LunarData.cs
+++ b/CoordinateSharp/Eclipse/LunarData.cs
@@ -2,11 +2,9 @@
using System.Collections.Generic;
using System.Linq;
-namespace CoordinateSharp.Eclipse
-{
- internal class LunarData
- {
- static double[] LE1601 = new double[] {
+namespace CoordinateSharp.Eclipse {
+ internal class LunarData {
+ static readonly Double[] LE1601 = new Double[] {
// 1601 1 18
2305831.105839, 15.0, 117.3, 0.033, -0.978, 3,
-1.13536, 0.98335, 0.26794,
@@ -1501,8 +1499,8 @@ namespace CoordinateSharp.Eclipse
-3.09161, -1.92390, -0.82385, 0.02344, 0.87082, 1.97089, 3.13800,
337.8589683, 0.48164, -1.510e-04,
-9.4195702, 0.13945, 3.390e-04 };
- static double[] LE1701 = new double[]
- {
+ static readonly Double[] LE1701 = new Double[]
+ {
// 1701 2 22
2342390.479120, 23.0, 8.2, 1.428, 0.463, 2,
-14.82816, 1.02374, 0.27894,
@@ -3039,9 +3037,9 @@ namespace CoordinateSharp.Eclipse
-2.69377, -1.12653, 0.00000, -0.22214, 0.00000, 0.67926, 2.24840,
9.1688605, 0.46956, -7.000e-05,
3.0790301, 0.25315, -2.000e-04
- };
- static double[] LE1801 = new double[]
- {
+ };
+ static readonly Double[] LE1801 = new Double[]
+ {
// 1801 3 30
2378949.725057, 5.0, 13.0, 2.857, 1.840, 1,
-6.52639, 0.96247, 0.26225,
@@ -4536,9 +4534,9 @@ namespace CoordinateSharp.Eclipse
-1.50705, 0.00000, 0.00000, 0.44149, 0.00000, 0.00000, 2.38825,
72.2570493, 0.64062, -1.660e-04,
21.3680795, 0.01873, -1.222e-03
- };
- static double[] LE1901 = new double[]
- {
+ };
+ static readonly Double[] LE1901 = new Double[]
+ {
// 1901 5 3
2415508.271269, 19.0, -0.9, 1.043, -0.033, 3,
-14.26838, 0.90110, 0.24553,
@@ -5913,9 +5911,9 @@ namespace CoordinateSharp.Eclipse
-3.17609, -2.02249, -0.94259, -0.05589, 0.83086, 1.91081, 3.06398,
296.2552752, 0.52835, -1.150e-04,
-21.2212594, 0.04170, 8.250e-04
- };
- static double[] LE2001 = new double[]
- {
+ };
+ static readonly Double[] LE2001 = new Double[]
+ {
// 2001 1 9
2451919.348374, 20.0, 64.1, 2.162, 1.189, 1,
3.29475, 1.02253, 0.27861,
@@ -7284,9 +7282,9 @@ namespace CoordinateSharp.Eclipse
-2.37000, 0.00000, 0.00000, -0.25042, 0.00000, 0.00000, 1.86680,
329.8184696, 0.49978, -6.760e-04,
-13.3626205, 0.22960, 3.990e-04
- };
- static double[] LE2101 = new double[]
- {
+ };
+ static readonly Double[] LE2101 = new Double[]
+ {
// 2101 2 14
2488478.618055, 3.0, 205.1, 2.218, 1.183, 1,
12.59941, 0.95660, 0.26065,
@@ -8715,9 +8713,9 @@ namespace CoordinateSharp.Eclipse
-2.67458, -1.48697, 0.00000, -0.25460, 0.00000, 0.97583, 2.16508,
28.0294400, 0.59158, 9.000e-05,
10.7019400, 0.15900, -6.160e-04
- };
- static double[] LE2201 = new double[]
- {
+ };
+ static readonly Double[] LE2201 = new Double[]
+ {
// 2201 3 20
2525037.204912, 17.0, 444.3, 0.532, -0.560, 3,
4.85759, 0.90005, 0.24524,
@@ -10230,9 +10228,9 @@ namespace CoordinateSharp.Eclipse
-2.66449, -1.75055, -0.80821, 0.00923, 0.82677, 1.76918, 2.68236,
63.0500500, 0.65278, 8.590e-04,
21.0508309, 0.17085, -1.218e-03
- };
- static double[] LE2301 = new double[]
- {
+ };
+ static readonly Double[] LE2301 = new Double[]
+ {
// 2301 5 23
2561625.186996, 16.0, 720.0, 1.809, 0.754, 2,
8.04603, 0.91666, 0.24977,
@@ -11751,8 +11749,8 @@ namespace CoordinateSharp.Eclipse
-2.07354, -0.65576, 0.00000, 0.44265, 0.00000, 1.54366, 2.95874,
101.2753539, 0.59275, -1.730e-04,
23.7726800, -0.09243, -1.170e-03
- };
- static double[] LE2401 = new double[] {
+ };
+ static readonly Double[] LE2401 = new Double[] {
// 2401 6 26
2598183.958214, 11.0, 1059.4, 2.107, 1.139, 1,
5.31800, 0.99489, 0.27108,
@@ -13176,7 +13174,7 @@ namespace CoordinateSharp.Eclipse
348.3334732, 0.58130, -3.870e-04,
-5.5431301, 0.18349, 2.190e-04
};
- static double[] LE2501 = new double[] {
+ static readonly Double[] LE2501 = new Double[] {
// 2501 3 6
2634595.801080, 7.0, 1461.0, 0.491, -0.599, 3,
17.93340, 0.90700, 0.24714,
@@ -14541,70 +14539,49 @@ namespace CoordinateSharp.Eclipse
8.0835801, 0.28700, -3.300e-04
};
- public static double[] LunarDateData(DateTime d)
- {
- //Return combined 100 year arrays so in order to grab Last and Next exlipLE.
- List data = new List()
- {
+ public static Double[] LunarDateData(DateTime d) {
+ //Return combined 100 year arrays so in order to grab Last and Next exlipLE.
+ List data = new List()
+ {
LE1601, LE1701,LE1801, LE1901, LE2001,
LE2101,LE2201, LE2301, LE2401, LE2501
};
- double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
- int index = GetIndex(cent); //Gets index for calling data list.
+ Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
+ Int32 index = GetIndex(cent); //Gets index for calling data list.
- if (index == -1) { return new double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
+ if (index == -1) { return new Double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
- //Determine data to LEnd if year is near beginning or end of databaLE
- int halfCent = d.Year - (int)cent;
- if (index == 0 || index == data.Count - 1)
- {
- if (index == 0)
- {
- if (halfCent <= 50) { return data[0]; }
- else { return data[0].Concat(data[1]).ToArray(); }
- }
- else
- {
- if (halfCent <= 50) { return data[index - 1].Concat(data[index]).ToArray(); }
- else { return data[index]; }
- }
- }
- else
- {
- if (halfCent <= 50) { return data[index - 1].Concat(data[index]).ToArray(); }
- else { return data[index].Concat(data[index + 1]).ToArray(); }
- }
+ //Determine data to LEnd if year is near beginning or end of databaLE
+ Int32 halfCent = d.Year - (Int32)cent;
+ return index == 0 || index == data.Count - 1 ? index == 0 ? halfCent <= 50 ? data[0] : data[0].Concat(data[1]).ToArray() : halfCent <= 50 ? data[index - 1].Concat(data[index]).ToArray() : data[index] : halfCent <= 50 ? data[index - 1].Concat(data[index]).ToArray() : data[index].Concat(data[index + 1]).ToArray();
- }
- public static double[] LunarDateData_100Year(DateTime d)
- {
- //Return combined 100 year arrays
- List data = new List()
- {
- LE1601, LE1701,LE1801, LE1901, LE2001,
- LE2101,LE2201, LE2301, LE2401, LE2501
- };
- double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
- int index = GetIndex(cent); //Gets index for calling data list.
-
- if (index == -1) { return new double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
- //Return proper 100 year table.
- return data[index];
-
- }
- private static int GetIndex(double cent)
- {
- int dex = 0;
- int c = Convert.ToInt32(cent * .01);
- //START CENTURY 16
- //END CENTRURY 26
- //AJDUST AS DATABALE GROWS
- for (int i = 16; i < 26; i++)
- {
- if (i == c) { return dex; }
- dex++;
- }
- return -1;
- }
}
+ public static Double[] LunarDateData_100Year(DateTime d) {
+ //Return combined 100 year arrays
+ List data = new List()
+ {
+ LE1601, LE1701,LE1801, LE1901, LE2001,
+ LE2101,LE2201, LE2301, LE2401, LE2501
+ };
+ Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
+ Int32 index = GetIndex(cent); //Gets index for calling data list.
+
+ if (index == -1) { return new Double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
+ //Return proper 100 year table.
+ return data[index];
+
+ }
+ private static Int32 GetIndex(Double cent) {
+ Int32 dex = 0;
+ Int32 c = Convert.ToInt32(cent * .01);
+ //START CENTURY 16
+ //END CENTRURY 26
+ //AJDUST AS DATABALE GROWS
+ for (Int32 i = 16; i < 26; i++) {
+ if (i == c) { return dex; }
+ dex++;
+ }
+ return -1;
+ }
+ }
}
diff --git a/CoordinateSharp/Eclipse/SolarData.cs b/CoordinateSharp/Eclipse/SolarData.cs
index ac92053..d892729 100644
--- a/CoordinateSharp/Eclipse/SolarData.cs
+++ b/CoordinateSharp/Eclipse/SolarData.cs
@@ -2,13 +2,11 @@
using System.Collections.Generic;
using System.Linq;
-namespace CoordinateSharp.Eclipse
-{
- internal class SolarData
- {
- //ECLIPSE DATA FROM 1701-2400
- static double[] SE1601 = new double[]
- {
+namespace CoordinateSharp.Eclipse {
+ internal class SolarData {
+ //ECLIPSE DATA FROM 1701-2400
+ static readonly Double[] SE1601 = new Double[]
+ {
// 1601 1 4
2305817.017109, 12.0, -4.0, 4.0, 117.4, 117.4,
-0.2585420, 0.5087563, -7.100e-06, -6.160e-06,
@@ -2241,9 +2239,9 @@ namespace CoordinateSharp.Eclipse
0.5346340, 0.0000437, -1.270e-05,
-0.0114460, 0.0000434, -1.270e-05,
0.0046524, 0.0046293
- };
- static double[] SE1701 = new double[]
- {
+ };
+ static readonly Double[] SE1701 = new Double[]
+ {
// 1701 2 7
2342375.461729, 23.0, -4.0, 4.0, 8.2, 8.2,
-0.1836620, 0.4942406, -1.910e-05, -5.580e-06,
@@ -4504,8 +4502,8 @@ namespace CoordinateSharp.Eclipse
-0.0039760, -0.0000963, -1.230e-05,
0.0046973, 0.0046739
};
- static double[] SE1801 = new double[]
- {
+ static readonly Double[] SE1801 = new Double[]
+ {
// 1801 3 14
2378934.156652, 16.0, -4.0, 4.0, 13.0, 13.0,
0.8100150, 0.4830337, -6.270e-05, -6.820e-06,
@@ -6684,8 +6682,8 @@ namespace CoordinateSharp.Eclipse
0.5676560, -0.0000826, -1.030e-05,
0.0214110, -0.0000822, -1.030e-05,
0.0047365, 0.0047129};
- static double[] SE1901 = new double[]
- {
+ static readonly Double[] SE1901 = new Double[]
+ {
// 1901 5 18
2415522.731807, 6.0, -4.0, 4.0, -0.9, -0.9,
0.3000790, 0.5746928, -4.400e-06, -9.600e-06,
@@ -8738,9 +8736,9 @@ namespace CoordinateSharp.Eclipse
0.5730920, 0.0000514, -1.000e-05,
0.0268200, 0.0000511, -1.000e-05,
0.0047553, 0.0047316
- };
- static double[] SE2001 = new double[]
- {
+ };
+ static readonly Double[] SE2001 = new Double[]
+ {
// 2001 6 21
2452082.003314, 12.0, -4.0, 4.0, 64.2, 64.2,
0.0103400, 0.5653861, 2.920e-05, -8.860e-06,
@@ -10757,9 +10755,9 @@ namespace CoordinateSharp.Eclipse
0.5398730, -0.0001031, -1.210e-05,
-0.0062330, -0.0001026, -1.200e-05,
0.0046346, 0.0046116
- };
- static double[] SE2101 = new double[]
- {
+ };
+ static readonly Double[] SE2101 = new Double[]
+ {
// 2101 2 28
2488492.594741, 2.0, -4.0, 4.0, 205.2, 205.2,
-0.5934920, 0.4746287, -1.290e-05, -6.230e-06,
@@ -12875,9 +12873,9 @@ namespace CoordinateSharp.Eclipse
0.5652510, -0.0000740, -1.020e-05,
0.0190180, -0.0000736, -1.010e-05,
0.0046769, 0.0046536
- };
- static double[] SE2201 = new double[]
- {
+ };
+ static readonly Double[] SE2201 = new Double[]
+ {
// 2201 4 4
2525051.763849, 6.0, -4.0, 4.0, 444.4, 444.4,
-0.1405310, 0.5551418, 1.180e-05, -9.340e-06,
@@ -15110,9 +15108,9 @@ namespace CoordinateSharp.Eclipse
0.5747280, 0.0000236, -9.900e-06,
0.0284480, 0.0000235, -9.800e-06,
0.0047462, 0.0047226
- };
- static double[] SE2301 = new double[]
- {
+ };
+ static readonly Double[] SE2301 = new Double[]
+ {
// 2301 5 9
2561611.084014, 14.0, -4.0, 4.0, 719.9, 719.9,
0.2556460, 0.5255338, 4.360e-05, -8.080e-06,
@@ -17345,8 +17343,8 @@ namespace CoordinateSharp.Eclipse
0.5389710, -0.0001064, -1.190e-05,
-0.0071310, -0.0001059, -1.190e-05,
0.0046006, 0.0045776
- };
- static double[] SE2401 = new double[] {
+ };
+ static readonly Double[] SE2401 = new Double[] {
// 2401 1 14
2598021.427310, 22.0, -4.0, 4.0, 1057.8, 1057.8,
-0.2870830, 0.5189539, -4.590e-05, -7.000e-06,
@@ -19481,7 +19479,7 @@ namespace CoordinateSharp.Eclipse
0.0163870, -0.0000706, -1.000e-05,
0.0046201, 0.0045971
};
- static double[] SE2501 = new double[] {
+ static readonly Double[] SE2501 = new Double[] {
// 2501 2 19
2634580.691215, 5.0, -4.0, 4.0, 1460.8, 1460.8,
0.1813720, 0.5619451, -3.330e-05, -9.490e-06,
@@ -21508,71 +21506,50 @@ namespace CoordinateSharp.Eclipse
0.0248230, 0.0000365, -9.800e-06,
0.0046944, 0.0046710 };
- public static double[] SolarDateData(DateTime d)
- {
- //Return combined 100 year arrays so in order to grab Last and Next exlipse.
- List data = new List()
- {
+ public static Double[] SolarDateData(DateTime d) {
+ //Return combined 100 year arrays so in order to grab Last and Next exlipse.
+ List data = new List()
+ {
SE1601, SE1701, SE1801, SE1901, SE2001,
SE2101, SE2201, SE2301, SE2401, SE2501
};
- double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
- int index = GetIndex(cent); //Gets index for calling data list.
+ Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
+ Int32 index = GetIndex(cent); //Gets index for calling data list.
- if (index == -1) { return new double[] { };} //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
+ if (index == -1) { return new Double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
- //Determine data to send if year is near beginning or end of database
- int halfCent = d.Year - (int)cent;
-
- if (index == 0 || index == data.Count - 1)
- {
- if(index == 0)
- {
- if (halfCent <= 50) { return data[0]; }
- else { return data[0].Concat(data[1]).ToArray(); }
- }
- else
- {
- if (halfCent <= 50) { return data[index - 1].Concat(data[index]).ToArray(); }
- else { return data[index]; }
- }
- }
- else
- {
- if (halfCent <= 50) { return data[index - 1].Concat(data[index]).ToArray(); }
- else { return data[index].Concat(data[index+1]).ToArray(); }
- }
-
- }
- public static double[] SolarDateData_100Year(DateTime d)
- {
- //Return combined 100 year arrays
- List data = new List()
- {
- SE1601, SE1701, SE1801, SE1901, SE2001,
- SE2101, SE2201, SE2301, SE2401, SE2501
- };
- double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
- int index = GetIndex(cent); //Gets index for calling data list.
+ //Determine data to send if year is near beginning or end of database
+ Int32 halfCent = d.Year - (Int32)cent;
- if (index == -1) { return new double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
- //Return proper 100 year table.
- return data[index];
+ return index == 0 || index == data.Count - 1 ? index == 0 ? halfCent <= 50 ? data[0] : data[0].Concat(data[1]).ToArray() : halfCent <= 50 ? data[index - 1].Concat(data[index]).ToArray() : data[index] : halfCent <= 50 ? data[index - 1].Concat(data[index]).ToArray() : data[index].Concat(data[index + 1]).ToArray();
- }
- private static int GetIndex(double cent)
- {
- int dex = 0;
- int c = Convert.ToInt32(cent * .01);
- //START CENTURY 16
- //END CENTRURY 26
- //AJDUST AS DATABASE GROWS
- for(int i = 16; i<26;i++)
- {
- if(i == c) { return dex; }
- dex++;
- }
- return -1;
- }
}
+ public static Double[] SolarDateData_100Year(DateTime d) {
+ //Return combined 100 year arrays
+ List data = new List()
+ {
+ SE1601, SE1701, SE1801, SE1901, SE2001,
+ SE2101, SE2201, SE2301, SE2401, SE2501
+ };
+ Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
+ Int32 index = GetIndex(cent); //Gets index for calling data list.
+
+ if (index == -1) { return new Double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
+ //Return proper 100 year table.
+ return data[index];
+
+ }
+ private static Int32 GetIndex(Double cent) {
+ Int32 dex = 0;
+ Int32 c = Convert.ToInt32(cent * .01);
+ //START CENTURY 16
+ //END CENTRURY 26
+ //AJDUST AS DATABASE GROWS
+ for (Int32 i = 16; i < 26; i++) {
+ if (i == c) { return dex; }
+ dex++;
+ }
+ return -1;
+ }
+ }
}
diff --git a/CoordinateSharp/GeoFence.cs b/CoordinateSharp/GeoFence.cs
index b576cd7..a238857 100644
--- a/CoordinateSharp/GeoFence.cs
+++ b/CoordinateSharp/GeoFence.cs
@@ -1,161 +1,138 @@
-using System.Collections.Generic;
-using System.Linq;
+using System;
+using System.Collections.Generic;
+
+namespace CoordinateSharp {
+ ///
+ /// Geo Fence class. It helps to check if points/coordinates are inside a polygon,
+ /// Next to a polyline, and counting...
+ ///
+ public class GeoFence {
+ #region Fields
+ private readonly List _points = new List();
+ #endregion
-namespace CoordinateSharp
-{
///
- /// Geo Fence class. It helps to check if points/coordinates are inside a polygon,
- /// Next to a polyline, and counting...
+ /// Prepare GeoFence with a list of points
///
- public class GeoFence
- {
- #region Fields
- private List _points = new List();
- #endregion
+ /// List of points
+ public GeoFence(List points) => this._points = points;
- ///
- /// Prepare GeoFence with a list of points
- ///
- /// List of points
- public GeoFence(List points)
- {
- _points = points;
- }
-
- ///
- /// Prepare Geofence with a list of coordinates
- ///
- /// List of coordinates
- public GeoFence(List coordinates)
- {
- foreach (var c in coordinates)
- {
- _points.Add(new Point { Latitude = c.Latitude.ToDouble(), Longitude = c.Longitude.ToDouble() });
- }
- }
-
- #region Utils
- private Coordinate ClosestPointOnSegment(Point a, Point b, Coordinate p)
- {
- var d = new Point
- {
- Longitude = b.Longitude - a.Longitude,
- Latitude = b.Latitude - a.Latitude,
- };
-
- double number = (p.Longitude.ToDouble() - a.Longitude) * d.Longitude + (p.Latitude.ToDouble() - a.Latitude) * d.Latitude;
-
- if (number <= 0.0)
- return new Coordinate(a.Latitude, a.Longitude);
-
- double denom = d.Longitude * d.Longitude + d.Latitude * d.Latitude;
-
- if (number >= denom)
- return new Coordinate(b.Latitude, b.Longitude);
-
- return new Coordinate(a.Latitude + (number / denom) * d.Latitude, a.Longitude + (number / denom) * d.Longitude);
- }
- #endregion
-
- ///
- /// The function will return true if the point x,y is inside the polygon, or
- /// false if it is not. If the point is exactly on the edge of the polygon,
- /// then the function may return true or false.
- ///
- /// The point to test
- /// bool
- public bool IsPointInPolygon(Coordinate point)
- {
- if (point == null)
- return false;
-
- double latitude = point.Latitude.ToDouble();
- double longitude = point.Longitude.ToDouble();
- int sides = _points.Count;
- int j = sides - 1;
- bool pointStatus = false;
- for (int i = 0; i < sides; i++)
- {
- if (_points[i].Latitude < latitude && _points[j].Latitude >= latitude || _points[j].Latitude < latitude && _points[i].Latitude >= latitude)
- {
- if (_points[i].Longitude + (latitude - _points[i].Latitude) / (_points[j].Latitude - _points[i].Latitude) * (_points[j].Longitude - _points[i].Longitude) < longitude)
- {
- pointStatus = !pointStatus;
- }
- }
- j = i;
- }
- return pointStatus;
- }
-
- ///
- /// The function will return true if the point x,y is next the given range of
- /// the polyline, or false if it is not.
- ///
- /// The point to test
- /// The range in meters
- /// bool
- public bool IsPointInRangeOfLine(Coordinate point, double range)
- {
- if (point == null)
- return false;
-
- for (int i = 0; i < _points.Count - 1; i++)
- {
- Coordinate c = ClosestPointOnSegment(_points[i], _points[i + 1], point);
- if (c.Get_Distance_From_Coordinate(point).Meters <= range)
- return true;
- }
-
- return false;
- }
-
- ///
- /// The function will return true if the point x,y is next the given range of
- /// the polyline, or false if it is not.
- ///
- /// The point to test
- /// The range is a distance object
- /// bool
- public bool IsPointInRangeOfLine(Coordinate point, Distance range)
- {
- if (point == null || range == null)
- return false;
-
- return IsPointInRangeOfLine(point, range.Meters);
- }
-
- ///
- /// This class is a help class to simplify GeoFence calculus
- ///
- public class Point
- {
-
- ///
- /// Initialize empty point
- ///
- public Point()
- {
-
- }
- ///
- /// Initialize point with defined Latitude and Longitude
- ///
- /// Latitude (signed)
- /// Longitude (signed)
- public Point(double lat, double lng)
- {
- Latitude = lat;
- Longitude = lng;
- }
- ///
- /// The longitude in degrees
- ///
- public double Longitude;
- ///
- /// The latitude in degrees
- ///
- public double Latitude;
- }
+ ///
+ /// Prepare Geofence with a list of coordinates
+ ///
+ /// List of coordinates
+ public GeoFence(List coordinates) {
+ foreach (Coordinate c in coordinates) {
+ this._points.Add(new Point { Latitude = c.Latitude.ToDouble(), Longitude = c.Longitude.ToDouble() });
+ }
}
+
+ #region Utils
+ private Coordinate ClosestPointOnSegment(Point a, Point b, Coordinate p) {
+ Point d = new Point {
+ Longitude = b.Longitude - a.Longitude,
+ Latitude = b.Latitude - a.Latitude,
+ };
+
+ Double number = (p.Longitude.ToDouble() - a.Longitude) * d.Longitude + (p.Latitude.ToDouble() - a.Latitude) * d.Latitude;
+
+ if (number <= 0.0) {
+ return new Coordinate(a.Latitude, a.Longitude);
+ }
+
+ Double denom = d.Longitude * d.Longitude + d.Latitude * d.Latitude;
+
+ return number >= denom ? new Coordinate(b.Latitude, b.Longitude) : new Coordinate(a.Latitude + number / denom * d.Latitude, a.Longitude + number / denom * d.Longitude);
+ }
+ #endregion
+
+ ///
+ /// The function will return true if the point x,y is inside the polygon, or
+ /// false if it is not. If the point is exactly on the edge of the polygon,
+ /// then the function may return true or false.
+ ///
+ /// The point to test
+ /// bool
+ public Boolean IsPointInPolygon(Coordinate point) {
+ if (point == null) {
+ return false;
+ }
+
+ Double latitude = point.Latitude.ToDouble();
+ Double longitude = point.Longitude.ToDouble();
+ Int32 sides = this._points.Count;
+ Int32 j = sides - 1;
+ Boolean pointStatus = false;
+ for (Int32 i = 0; i < sides; i++) {
+ if (this._points[i].Latitude < latitude && this._points[j].Latitude >= latitude || this._points[j].Latitude < latitude && this._points[i].Latitude >= latitude) {
+ if (this._points[i].Longitude + (latitude - this._points[i].Latitude) / (this._points[j].Latitude - this._points[i].Latitude) * (this._points[j].Longitude - this._points[i].Longitude) < longitude) {
+ pointStatus = !pointStatus;
+ }
+ }
+ j = i;
+ }
+ return pointStatus;
+ }
+
+ ///
+ /// The function will return true if the point x,y is next the given range of
+ /// the polyline, or false if it is not.
+ ///
+ /// The point to test
+ /// The range in meters
+ /// bool
+ public Boolean IsPointInRangeOfLine(Coordinate point, Double range) {
+ if (point == null) {
+ return false;
+ }
+
+ for (Int32 i = 0; i < this._points.Count - 1; i++) {
+ Coordinate c = this.ClosestPointOnSegment(this._points[i], this._points[i + 1], point);
+ if (c.Get_Distance_From_Coordinate(point).Meters <= range) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// The function will return true if the point x,y is next the given range of
+ /// the polyline, or false if it is not.
+ ///
+ /// The point to test
+ /// The range is a distance object
+ /// bool
+ public Boolean IsPointInRangeOfLine(Coordinate point, Distance range) => point == null || range == null ? false : this.IsPointInRangeOfLine(point, range.Meters);
+
+ ///
+ /// This class is a help class to simplify GeoFence calculus
+ ///
+ public class Point {
+
+ ///
+ /// Initialize empty point
+ ///
+ public Point() {
+
+ }
+ ///
+ /// Initialize point with defined Latitude and Longitude
+ ///
+ /// Latitude (signed)
+ /// Longitude (signed)
+ public Point(Double lat, Double lng) {
+ this.Latitude = lat;
+ this.Longitude = lng;
+ }
+ ///
+ /// The longitude in degrees
+ ///
+ public Double Longitude;
+ ///
+ /// The latitude in degrees
+ ///
+ public Double Latitude;
+ }
+ }
}
\ No newline at end of file
diff --git a/CoordinateSharp/Properties/AssemblyInfo.cs b/CoordinateSharp/Properties/AssemblyInfo.cs
index 1c1f393..fae1d09 100644
--- a/CoordinateSharp/Properties/AssemblyInfo.cs
+++ b/CoordinateSharp/Properties/AssemblyInfo.cs
@@ -1,4 +1,5 @@
-using System.Reflection;
+#if !NETCOREAPP
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -34,3 +35,4 @@ using System.Runtime.InteropServices;
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.5.2")]
[assembly: AssemblyFileVersion("1.1.5.2")]
+#endif
\ No newline at end of file
diff --git a/CoordinateSharp_Core.sln b/CoordinateSharp_Core.sln
new file mode 100644
index 0000000..96bf25b
--- /dev/null
+++ b/CoordinateSharp_Core.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29519.87
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoordinateSharp", "CoordinateSharp\CoordinateSharp_Core.csproj", "{127E1C0F-06DC-492C-B124-19A89D44B47C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {127E1C0F-06DC-492C-B124-19A89D44B47C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {127E1C0F-06DC-492C-B124-19A89D44B47C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {127E1C0F-06DC-492C-B124-19A89D44B47C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {127E1C0F-06DC-492C-B124-19A89D44B47C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {667C979D-42C3-4EE8-9B2B-D85EFC09940A}
+ EndGlobalSection
+EndGlobal