Add netcore

This commit is contained in:
Philip Schell 2019-12-09 14:46:34 +01:00
parent 2b0fbff159
commit 3843109a62
23 changed files with 6884 additions and 8333 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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<List<string>> CalculateLunarEclipse(DateTime d, double latRad, double longRad)
{
return Calculate(d, latRad, longRad);
}
public static List<LunarEclipseDetails> CalculateLunarEclipse(DateTime d, double latRad, double longRad, double[] events)
{
List<List<string>> evs = Calculate(d, latRad, longRad, events);
List<LunarEclipseDetails> deetsList = new List<LunarEclipseDetails>();
foreach (List<string> ls in evs)
{
LunarEclipseDetails deets = new LunarEclipseDetails(ls);
deetsList.Add(deets);
}
return deetsList;
}
public static List<List<string>> CalculateLunarEclipse(DateTime d, Coordinate coord)
{
return Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians());
}
// CALCULATE!
private static List<List<string>> 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<List<string>> events = new List<List<string>>();
double[] el;
if (ev == null)
{
el = Eclipse.LunarData.LunarDateData(d);//Get 100 year solar data;
}
else
{
el = ev;
}
events = new List<List<string>>();
ReadData(latRad, longRad, obsvconst);
for (int i = 0; i < el.Length; i += 22)
{
if (el[5 + i] <= obsvconst[5])
{
List<string> values = new List<string>();
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<List<String>> CalculateLunarEclipse(DateTime d, Double latRad, Double longRad) => Calculate(d, latRad, longRad);
public static List<LunarEclipseDetails> CalculateLunarEclipse(DateTime d, Double latRad, Double longRad, Double[] events) {
List<List<String>> evs = Calculate(d, latRad, longRad, events);
List<LunarEclipseDetails> deetsList = new List<LunarEclipseDetails>();
foreach (List<String> ls in evs) {
LunarEclipseDetails deets = new LunarEclipseDetails(ls);
deetsList.Add(deets);
}
return deetsList;
}
public static List<List<String>> CalculateLunarEclipse(DateTime d, Coordinate coord) => Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians());
// CALCULATE!
private static List<List<String>> 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<List<String>> events = new List<List<String>>();
ReadData(latRad, longRad, obsvconst);
for (Int32 i = 0; i < el.Length; i += 22) {
if (el[5 + i] <= obsvconst[5]) {
List<String> values = new List<String>();
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;
}
}
}
}

View File

@ -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]);
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
/// <summary>
/// Gets time of event based on specified degree below horizon
/// </summary>
/// <param name="lw">Observer Longitude in radians</param>
/// <param name="phi">Observer Latitude in radians</param>
/// <param name="h">Angle in Degrees</param>
/// <param name="date">Date of Event</param>
/// <returns>DateTime?[]{rise, set}</returns>
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<List<string>> 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<string> 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
}
/// <summary>
/// Gets time of event based on specified degree below horizon
/// </summary>
/// <param name="lw">Observer Longitude in radians</param>
/// <param name="phi">Observer Latitude in radians</param>
/// <param name="h">Angle in Degrees</param>
/// <param name="date">Date of Event</param>
/// <returns>DateTime?[]{rise, set}</returns>
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<List<String>> 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<String> 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
}
}

File diff suppressed because it is too large Load Diff

View File

@ -2,268 +2,233 @@
using System.Collections.Generic;
using System.Linq;
namespace CoordinateSharp
{
namespace CoordinateSharp {
/// <summary>
/// Used for UTM/MGRS Conversions
/// </summary>
[Serializable]
internal class LatZones
{
public static List<string> longZongLetters = new List<string>(new string[]{"C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
/// <summary>
/// Used for UTM/MGRS Conversions
/// </summary>
[Serializable]
internal class LatZones {
public static List<String> longZongLetters = new List<String>(new String[]{"C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
"U", "V", "W", "X"});
}
/// <summary>
/// Used for handling diagraph determination
/// </summary>
[Serializable]
internal class Digraphs {
private readonly List<Digraph> digraph1;
private readonly List<Digraph> 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<Digraph>();
this.digraph2 = new List<Digraph>();
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;
}
}
/// <summary>
/// Diagraph model
/// </summary>
[Serializable]
internal class Digraph {
public Int32 Zone { get; set; }
public String Letter { get; set; }
}
/// <summary>
/// Used for setting whether a coordinate part is latitudinal or longitudinal.
/// </summary>
[Serializable]
public enum CoordinateType {
/// <summary>
/// Used for handling diagraph determination
/// Latitude
/// </summary>
[Serializable]
internal class Digraphs
{
private List<Digraph> digraph1;
private List<Digraph> 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<Digraph>();
digraph2 = new List<Digraph>();
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,
/// <summary>
/// Diagraph model
/// Longitude
/// </summary>
[Serializable]
internal class Digraph
{
public int Zone { get; set; }
public string Letter { get; set; }
}
Long
}
/// <summary>
/// Used to set a coordinate part position.
/// </summary>
[Serializable]
public enum CoordinatesPosition : Int32 {
/// <summary>
/// Used for setting whether a coordinate part is latitudinal or longitudinal.
/// North
/// </summary>
[Serializable]
public enum CoordinateType
{
/// <summary>
/// Latitude
/// </summary>
Lat,
/// <summary>
/// Longitude
/// </summary>
Long
}
N,
/// <summary>
/// Used to set a coordinate part position.
/// East
/// </summary>
[Serializable]
public enum CoordinatesPosition :int
{
/// <summary>
/// North
/// </summary>
N,
/// <summary>
/// East
/// </summary>
E,
/// <summary>
/// South
/// </summary>
S,
/// <summary>
/// West
/// </summary>
W
}
E,
/// <summary>
/// Coordinate type datum specification
/// South
/// </summary>
[Serializable]
[Flags]
public enum Coordinate_Datum
{
/// <summary>
/// Lat Long GeoDetic
/// </summary>
LAT_LONG = 1,
/// <summary>
/// UTM and MGRS
/// </summary>
UTM_MGRS = 2,
/// <summary>
/// ECEF
/// </summary>
ECEF = 4,
}
S,
/// <summary>
/// Cartesian Coordinate Type
/// West
/// </summary>
public enum CartesianType
{
/// <summary>
/// Spherical Cartesian
/// </summary>
Cartesian,
/// <summary>
/// Earth Centered Earth Fixed
/// </summary>
ECEF,
}
/// <summary>
/// Used for easy read math functions
/// </summary>
[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;
}
}
/// <summary>
/// Coordinate type datum specification
/// </summary>
[Serializable]
[Flags]
public enum Coordinate_Datum {
/// <summary>
/// Earth Shape for Calculations.
/// Lat Long GeoDetic
/// </summary>
LAT_LONG = 1,
/// <summary>
/// UTM and MGRS
/// </summary>
UTM_MGRS = 2,
/// <summary>
/// ECEF
/// </summary>
ECEF = 4,
}
/// <summary>
/// Cartesian Coordinate Type
/// </summary>
public enum CartesianType {
/// <summary>
/// Spherical Cartesian
/// </summary>
Cartesian,
/// <summary>
/// Earth Centered Earth Fixed
/// </summary>
ECEF,
}
/// <summary>
/// Used for easy read math functions
/// </summary>
[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;
}
/// <summary>
/// Earth Shape for Calculations.
/// </summary>
[Serializable]
public enum Shape {
/// <summary>
/// Calculate as sphere (less accurate, more efficient).
/// </summary>
Sphere,
/// <summary>
/// Calculate as ellipsoid (more accurate, less efficient).
/// </summary>
Ellipsoid
}
[Serializable]
public enum Shape
{
/// <summary>
/// Calculate as sphere (less accurate, more efficient).
/// </summary>
Sphere,
/// <summary>
/// Calculate as ellipsoid (more accurate, less efficient).
/// </summary>
Ellipsoid
}
}

View File

@ -1,155 +1,135 @@
using System;
using System.ComponentModel;
namespace CoordinateSharp
{
namespace CoordinateSharp {
/// <summary>
/// Cartesian (X, Y, Z) Coordinate
/// </summary>
[Serializable]
public class Cartesian : INotifyPropertyChanged {
/// <summary>
/// Cartesian (X, Y, Z) Coordinate
/// Create a Cartesian Object
/// </summary>
[Serializable]
public class Cartesian : INotifyPropertyChanged
{
/// <summary>
/// Create a Cartesian Object
/// </summary>
/// <param name="c"></param>
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());
}
/// <summary>
/// Create a Cartesian Object
/// </summary>
/// <param name="xc">X</param>
/// <param name="yc">Y</param>
/// <param name="zc">Z</param>
public Cartesian(double xc, double yc, double zc)
{
//formulas:
x = xc;
y = yc;
z = zc;
}
/// <summary>
/// Updates Cartesian Values
/// </summary>
/// <param name="c"></param>
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;
/// <summary>
/// X Coordinate
/// </summary>
public double X
{
get { return x; }
set
{
if(x != value)
{
x = value;
NotifyPropertyChanged("X");
}
}
}
/// <summary>
/// y Coordinate
/// </summary>
public double Y
{
get { return y; }
set
{
if (y != value)
{
y = value;
NotifyPropertyChanged("Y");
}
}
}
/// <summary>
/// Z Coordinate
/// </summary>
public double Z
{
get { return z; }
set
{
if (z != value)
{
z = value;
NotifyPropertyChanged("Z");
}
}
}
/// <summary>
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="z">Z</param>
/// <returns></returns>
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);
}
/// <summary>
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
/// </summary>
/// <param name="cart">Cartesian Coordinate</param>
/// <returns></returns>
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);
}
/// <summary>
/// Cartesian Default String Format
/// </summary>
/// <returns>Cartesian Formatted Coordinate String</returns>
/// <returns>Values rounded to the 8th place</returns>
public override string ToString()
{
return Math.Round(x,8).ToString() + " " + Math.Round(y, 8).ToString() + " " + Math.Round(z, 8).ToString();
}
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notify property changed
/// </summary>
/// <param name="propName">Property name</param>
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
/// <param name="c"></param>
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());
}
/// <summary>
/// Create a Cartesian Object
/// </summary>
/// <param name="xc">X</param>
/// <param name="yc">Y</param>
/// <param name="zc">Z</param>
public Cartesian(Double xc, Double yc, Double zc) {
//formulas:
this.x = xc;
this.y = yc;
this.z = zc;
}
/// <summary>
/// Updates Cartesian Values
/// </summary>
/// <param name="c"></param>
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;
/// <summary>
/// X Coordinate
/// </summary>
public Double X {
get => this.x;
set {
if (this.x != value) {
this.x = value;
this.NotifyPropertyChanged("X");
}
}
}
/// <summary>
/// y Coordinate
/// </summary>
public Double Y {
get => this.y;
set {
if (this.y != value) {
this.y = value;
this.NotifyPropertyChanged("Y");
}
}
}
/// <summary>
/// Z Coordinate
/// </summary>
public Double Z {
get => this.z;
set {
if (this.z != value) {
this.z = value;
this.NotifyPropertyChanged("Z");
}
}
}
/// <summary>
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="z">Z</param>
/// <returns></returns>
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);
}
/// <summary>
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
/// </summary>
/// <param name="cart">Cartesian Coordinate</param>
/// <returns></returns>
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);
}
/// <summary>
/// Cartesian Default String Format
/// </summary>
/// <returns>Cartesian Formatted Coordinate String</returns>
/// <returns>Values rounded to the 8th place</returns>
public override String ToString() => Math.Round(this.x, 8).ToString() + " " + Math.Round(this.y, 8).ToString() + " " + Math.Round(this.z, 8).ToString();
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notify property changed
/// </summary>
/// <param name="propName">Property name</param>
public void NotifyPropertyChanged(String propName) {
if (this.PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,119 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CoordinateSharp
{
namespace CoordinateSharp {
/// <summary>
/// Turn on/off eager loading of certain properties.
/// </summary>
[Serializable]
public class EagerLoad {
/// <summary>
/// Turn on/off eager loading of certain properties.
/// Create an EagerLoad object
/// </summary>
[Serializable]
public class EagerLoad
{
/// <summary>
/// Create an EagerLoad object
/// </summary>
public EagerLoad()
{
Celestial = true;
UTM_MGRS = true;
Cartesian = true;
ECEF = true;
}
/// <summary>
/// Create an EagerLoad object with all options on or off
/// </summary>
/// <param name="isOn">Turns EagerLoad on or off</param>
public EagerLoad(bool isOn)
{
Celestial = isOn;
UTM_MGRS = isOn;
Cartesian = isOn;
ECEF = isOn;
}
/// <summary>
/// Create an EagerLoad object with only the specified flag options turned on.
/// </summary>
/// <param name="et">EagerLoadType</param>
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;
}
}
/// <summary>
/// Creates an EagerLoad object. Only the specified flags will be set to EagerLoad.
/// </summary>
/// <param name="et">EagerLoadType</param>
/// <returns>EagerLoad</returns>
public static EagerLoad Create(EagerLoadType et)
{
EagerLoad el = new EagerLoad(et);
return el;
}
/// <summary>
/// Eager load celestial information.
/// </summary>
public bool Celestial { get; set; }
/// <summary>
/// Eager load UTM and MGRS information
/// </summary>
public bool UTM_MGRS { get; set; }
/// <summary>
/// Eager load Cartesian information
/// </summary>
public bool Cartesian { get; set; }
/// <summary>
/// Eager load ECEF information
/// </summary>
public bool ECEF { get; set; }
public EagerLoad() {
this.Celestial = true;
this.UTM_MGRS = true;
this.Cartesian = true;
this.ECEF = true;
}
/// <summary>
/// EagerLoad Enumerator
/// Create an EagerLoad object with all options on or off
/// </summary>
[Serializable]
[Flags]
public enum EagerLoadType
{
/// <summary>
/// UTM and MGRS
/// </summary>
UTM_MGRS = 1,
/// <summary>
/// Celestial
/// </summary>
Celestial = 2,
/// <summary>
/// Cartesian
/// </summary>
Cartesian = 4,
/// <summary>
/// ECEF
/// </summary>
ECEF = 8
/// <param name="isOn">Turns EagerLoad on or off</param>
public EagerLoad(Boolean isOn) {
this.Celestial = isOn;
this.UTM_MGRS = isOn;
this.Cartesian = isOn;
this.ECEF = isOn;
}
/// <summary>
/// Create an EagerLoad object with only the specified flag options turned on.
/// </summary>
/// <param name="et">EagerLoadType</param>
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;
}
}
/// <summary>
/// Creates an EagerLoad object. Only the specified flags will be set to EagerLoad.
/// </summary>
/// <param name="et">EagerLoadType</param>
/// <returns>EagerLoad</returns>
public static EagerLoad Create(EagerLoadType et) {
EagerLoad el = new EagerLoad(et);
return el;
}
/// <summary>
/// Eager load celestial information.
/// </summary>
public Boolean Celestial { get; set; }
/// <summary>
/// Eager load UTM and MGRS information
/// </summary>
public Boolean UTM_MGRS { get; set; }
/// <summary>
/// Eager load Cartesian information
/// </summary>
public Boolean Cartesian { get; set; }
/// <summary>
/// Eager load ECEF information
/// </summary>
public Boolean ECEF { get; set; }
}
/// <summary>
/// EagerLoad Enumerator
/// </summary>
[Serializable]
[Flags]
public enum EagerLoadType {
/// <summary>
/// UTM and MGRS
/// </summary>
UTM_MGRS = 1,
/// <summary>
/// Celestial
/// </summary>
Celestial = 2,
/// <summary>
/// Cartesian
/// </summary>
Cartesian = 4,
/// <summary>
/// ECEF
/// </summary>
ECEF = 8
}
}

View File

@ -1,107 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CoordinateSharp
{
namespace CoordinateSharp {
/// <summary>
/// Coordinate formatting options for a Coordinate object.
/// </summary>
[Serializable]
public class CoordinateFormatOptions {
/// <summary>
/// Coordinate formatting options for a Coordinate object.
/// Set default values with the constructor.
/// </summary>
[Serializable]
public class CoordinateFormatOptions
{
/// <summary>
/// Set default values with the constructor.
/// </summary>
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;
}
/// <summary>
/// Coordinate format type.
/// </summary>
public CoordinateFormatType Format { get; set; }
/// <summary>
/// Rounds Coordinates to the set value.
/// </summary>
public int Round { get; set; }
/// <summary>
/// Displays leading zeros.
/// </summary>
public bool Display_Leading_Zeros { get; set; }
/// <summary>
/// Display trailing zeros.
/// </summary>
public bool Display_Trailing_Zeros { get; set; }
/// <summary>
/// Allow symbols to display.
/// </summary>
public bool Display_Symbols { get; set; }
/// <summary>
/// Display degree symbols.
/// </summary>
public bool Display_Degree_Symbol { get; set; }
/// <summary>
/// Display minute symbols.
/// </summary>
public bool Display_Minute_Symbol { get; set; }
/// <summary>
/// Display secons symbol.
/// </summary>
public bool Display_Seconds_Symbol { get; set; }
/// <summary>
/// Display hyphens between values.
/// </summary>
public bool Display_Hyphens { get; set; }
/// <summary>
/// Show coordinate position first.
/// Will show last if set 'false'.
/// </summary>
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;
}
/// <summary>
/// Coordinate Format Types.
/// Coordinate format type.
/// </summary>
[Serializable]
public enum CoordinateFormatType
{
/// <summary>
/// Decimal Degree Format
/// </summary>
/// <remarks>
/// Example: N 40.456 W 75.456
/// </remarks>
Decimal_Degree,
/// <summary>
/// Decimal Degree Minutes Format
/// </summary>
/// <remarks>
/// Example: N 40º 34.552' W 70º 45.408'
/// </remarks>
Degree_Decimal_Minutes,
/// <summary>
/// Decimal Degree Minutes Format
/// </summary>
/// <remarks>
/// Example: N 40º 34" 36.552' W 70º 45" 24.408'
/// </remarks>
Degree_Minutes_Seconds,
/// <summary>
/// Decimal Format
/// </summary>
/// <remarks>
/// Example: 40.57674 -70.46574
/// </remarks>
Decimal
}
public CoordinateFormatType Format { get; set; }
/// <summary>
/// Rounds Coordinates to the set value.
/// </summary>
public Int32 Round { get; set; }
/// <summary>
/// Displays leading zeros.
/// </summary>
public Boolean Display_Leading_Zeros { get; set; }
/// <summary>
/// Display trailing zeros.
/// </summary>
public Boolean Display_Trailing_Zeros { get; set; }
/// <summary>
/// Allow symbols to display.
/// </summary>
public Boolean Display_Symbols { get; set; }
/// <summary>
/// Display degree symbols.
/// </summary>
public Boolean Display_Degree_Symbol { get; set; }
/// <summary>
/// Display minute symbols.
/// </summary>
public Boolean Display_Minute_Symbol { get; set; }
/// <summary>
/// Display secons symbol.
/// </summary>
public Boolean Display_Seconds_Symbol { get; set; }
/// <summary>
/// Display hyphens between values.
/// </summary>
public Boolean Display_Hyphens { get; set; }
/// <summary>
/// Show coordinate position first.
/// Will show last if set 'false'.
/// </summary>
public Boolean Position_First { get; set; }
}
/// <summary>
/// Coordinate Format Types.
/// </summary>
[Serializable]
public enum CoordinateFormatType {
/// <summary>
/// Decimal Degree Format
/// </summary>
/// <remarks>
/// Example: N 40.456 W 75.456
/// </remarks>
Decimal_Degree,
/// <summary>
/// Decimal Degree Minutes Format
/// </summary>
/// <remarks>
/// Example: N 40º 34.552' W 70º 45.408'
/// </remarks>
Degree_Decimal_Minutes,
/// <summary>
/// Decimal Degree Minutes Format
/// </summary>
/// <remarks>
/// Example: N 40º 34" 36.552' W 70º 45" 24.408'
/// </remarks>
Degree_Minutes_Seconds,
/// <summary>
/// Decimal Format
/// </summary>
/// <remarks>
/// Example: 40.57674 -70.46574
/// </remarks>
Decimal
}
}

View File

@ -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 {
/// <summary>
/// Military Grid Reference System (MGRS). Uses the WGS 84 Datum.
/// Relies upon values from the UniversalTransverseMercator class
/// </summary>
[Serializable]
public class MilitaryGridReferenceSystem : INotifyPropertyChanged {
/// <summary>
/// Military Grid Reference System (MGRS). Uses the WGS 84 Datum.
/// Relies upon values from the UniversalTransverseMercator class
/// Create an MGRS object with WGS84 datum
/// </summary>
[Serializable]
public class MilitaryGridReferenceSystem : INotifyPropertyChanged
{
/// <summary>
/// Create an MGRS object with WGS84 datum
/// </summary>
/// <param name="latz">Lat Zone</param>
/// <param name="longz">Long Zone</param>
/// <param name="d">Digraph</param>
/// <param name="e">Easting</param>
/// <param name="n">Northing</param>
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;
}
/// <summary>
/// Create an MGRS object with custom datum
/// </summary>
/// <param name="latz">Lat Zone</param>
/// <param name="longz">Long Zone</param>
/// <param name="d">Digraph</param>
/// <param name="e">Easting</param>
/// <param name="n">Northing</param>
/// <param name="rad">Equatorial Radius</param>
/// <param name="flt">Inverse Flattening</param>
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;
}
/// <param name="latz">Lat Zone</param>
/// <param name="longz">Long Zone</param>
/// <param name="d">Digraph</param>
/// <param name="e">Easting</param>
/// <param name="n">Northing</param>
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;
}
/// <summary>
/// MGRS Zone Letter
/// </summary>
public string LatZone
{
get { return latZone; }
}
/// <summary>
/// MGRS Zone Number
/// </summary>
public int LongZone
{
get { return longZone; }
}
/// <summary>
/// MGRS Easting
/// </summary>
public double Easting
{
get { return easting; }
}
/// <summary>
/// MGRS Northing
/// </summary>
public double Northing
{
get { return northing; }
}
/// <summary>
/// MGRS Digraph
/// </summary>
public string Digraph
{
get { return digraph; }
}
/// <summary>
/// Is MGRS conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
/// </summary>
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;
}
/// <summary>
/// Creates a Coordinate object from an MGRS/NATO UTM Coordinate
/// </summary>
/// <param name="mgrs">MilitaryGridReferenceSystem</param>
/// <returns>Coordinate object</returns>
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;
}
/// <summary>
/// MGRS Default String Format
/// </summary>
/// <returns>MGRS Formatted Coordinate String</returns>
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");
}
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notify property changed
/// </summary>
/// <param name="propName">Property name</param>
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
/// <summary>
/// Create an MGRS object with custom datum
/// </summary>
/// <param name="latz">Lat Zone</param>
/// <param name="longz">Long Zone</param>
/// <param name="d">Digraph</param>
/// <param name="e">Easting</param>
/// <param name="n">Northing</param>
/// <param name="rad">Equatorial Radius</param>
/// <param name="flt">Inverse Flattening</param>
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;
/// <summary>
/// MGRS Zone Letter
/// </summary>
public String LatZone { get; private set; }
/// <summary>
/// MGRS Zone Number
/// </summary>
public Int32 LongZone { get; private set; }
/// <summary>
/// MGRS Easting
/// </summary>
public Double Easting { get; private set; }
/// <summary>
/// MGRS Northing
/// </summary>
public Double Northing { get; private set; }
/// <summary>
/// MGRS Digraph
/// </summary>
public String Digraph { get; private set; }
/// <summary>
/// Is MGRS conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
/// </summary>
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;
}
/// <summary>
/// Creates a Coordinate object from an MGRS/NATO UTM Coordinate
/// </summary>
/// <param name="mgrs">MilitaryGridReferenceSystem</param>
/// <returns>Coordinate object</returns>
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;
}
/// <summary>
/// MGRS Default String Format
/// </summary>
/// <returns>MGRS Formatted Coordinate String</returns>
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.
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notify property changed
/// </summary>
/// <param name="propName">Property name</param>
public void NotifyPropertyChanged(String propName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -34,8 +34,7 @@ SOFTWARE.
using System;
using System.ComponentModel;
namespace CoordinateSharp
{
namespace CoordinateSharp {
/// <summary>
/// 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
/// </remarks>
[Serializable]
public class Coordinate : INotifyPropertyChanged
{
public class Coordinate : INotifyPropertyChanged {
/// <summary>
/// Creates an empty Coordinate.
/// </summary>
/// <remarks>
/// Values will need to be provided to latitude/longitude CoordinateParts manually
/// </remarks>
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
/// <remarks>
/// Values will need to be provided to latitude/longitude CoordinateParts manually
/// </remarks>
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
/// <remarks>
/// Geodate will default to 1/1/1900 GMT until provided
/// </remarks>
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
/// <param name="lat">latitude</param>
/// <param name="longi">longitude</param>
/// <param name="date">DateTime (UTC)</param>
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
/// </remarks>
/// <param name="eagerLoad">Eager loading options</param>
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
/// <param name="lat">latitude</param>
/// <param name="longi">longitude</param>
/// <param name="eagerLoad">Eager loading options</param>
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
/// <param name="longi">Decimal format longitude</param>
/// <param name="date">DateTime you wish to use for celestial calculation</param>
/// <param name="eagerLoad">Eager loading options</param>
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
/// <summary>
/// Latitudinal Coordinate Part
/// </summary>
public CoordinatePart Latitude
{
public CoordinatePart Latitude {
get => this.latitude;
set {
if (this.latitude != value) {
@ -292,8 +282,7 @@ namespace CoordinateSharp
/// <summary>
/// Longitudinal Coordinate Part
/// </summary>
public CoordinatePart Longitude
{
public CoordinatePart Longitude {
get => this.longitude;
set {
if (this.longitude != value) {
@ -325,8 +314,7 @@ namespace CoordinateSharp
/// <remarks>
/// Assumes all times are in UTC
/// </remarks>
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.
/// </summary>
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.
/// </summary>
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
/// <summary>
/// Initialize UTM and MGRS information (required if eager loading is turned off).
/// </summary>
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.
/// </summary>
/// <returns>string (formatted).</returns>
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
/// </summary>
/// <param name="options">CoordinateFormatOptions</param>
/// <returns>Custom formatted coordinate</returns>
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
/// </summary>
/// <param name="radius">Equatorial Radius</param>
/// <param name="flat">Inverse Flattening</param>
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
/// <param name="radius">Equatorial Radius</param>
/// <param name="flat">Inverse Flattening</param>
/// <param name="cd">Coordinate_Datum</param>
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"
/// </code>
/// </example>
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"
/// </code>
/// </example>
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"
/// </code>
/// </example>
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"
/// </code>
/// </example>
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
/// }
/// </code>
/// </example>
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
/// }
/// </code>
/// </example>
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
/// }
/// </code>
/// </example>
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
/// }
/// </code>
/// </example>
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
/// </summary>
/// <param name="propName">Property name</param>
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.
/// </remarks>
[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
/// <summary>
/// Observable decimal format coordinate.
/// </summary>
public Double DecimalDegree
{
public Double DecimalDegree {
get => this.decimalDegree;
set {
//If changing, notify the needed property changes
@ -1018,8 +984,7 @@ namespace CoordinateSharp
/// <summary>
/// Observable decimal format minute.
/// </summary>
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
/// <summary>
/// Observable coordinate degree.
/// </summary>
public Int32 Degrees
{
public Int32 Degrees {
get => this.degrees;
set {
//Validate Value
@ -1105,8 +1069,7 @@ namespace CoordinateSharp
/// <summary>
/// Observable coordinate minute.
/// </summary>
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
/// <summary>
/// Observable coordinate second.
/// </summary>
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
/// <summary>
/// Observable coordinate position.
/// </summary>
public CoordinatesPosition Position
{
public CoordinatesPosition Position {
get => this.position;
set {
if (this.position != value) {
@ -1231,8 +1192,7 @@ namespace CoordinateSharp
/// <param name="t">CoordinateType</param>
/// <param name="c">Parent Coordinate object</param>
[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
/// <param name="t">Coordinate type</param>
/// <param name="c">Parent Coordinate object</param>
[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
/// <param name="pos">Coordinate Part Position</param>
/// <param name="c">Parent Coordinate</param>
[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
/// <param name="pos">Coordinate Part Position</param>
/// <param name="c">Parent Coordinate object</param>
[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.
/// </summary>
/// <param name="t">CoordinateType</param>
public CoordinatePart(CoordinateType t)
{
public CoordinatePart(CoordinateType t) {
this.type = t;
this.decimalDegree = 0;
this.degrees = 0;
@ -1382,8 +1338,7 @@ namespace CoordinateSharp
/// </summary>
/// <param name="value">Coordinate decimal value</param>
/// <param name="t">Coordinate type</param>
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
/// <param name="min">Minutes</param>
/// <param name="sec">Seconds</param>
/// <param name="pos">Coordinate Part Position</param>
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
/// <param name="deg">Degrees</param>
/// <param name="minSec">Decimal Minutes</param>
/// <param name="pos">Coordinate Part Position</param>
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
/// </summary>
/// <param name="options">CoordinateFormatOptions</param>
/// <returns>Formatted coordinate part string</returns>
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
}
/// <summary>
/// Notify the correct properties and parent properties.
/// </summary>
/// <param name="p">Property Type</param>
private void NotifyProperties(PropertyTypes p)
{
private void NotifyProperties(PropertyTypes p) {
switch (p) {
case PropertyTypes.DecimalDegree:
this.NotifyPropertyChanged("DecimalDegree");
@ -1786,8 +1712,7 @@ namespace CoordinateSharp
/// <summary>
/// Used for notifying the correct properties.
/// </summary>
private enum PropertyTypes
{
private enum PropertyTypes {
DecimalDegree, DecimalMinute, Position, Degree, Minute, Second, FormatChange
}
@ -1811,12 +1736,7 @@ namespace CoordinateSharp
/// }
/// </code>
/// </example>
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;
/// <summary>
/// Attempts to parse a string into a CoordinatePart.
/// </summary>
@ -1833,9 +1753,7 @@ namespace CoordinateSharp
/// }
/// </code>
/// </example>
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;

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<AssemblyName>CoordinateSharp</AssemblyName>
<RootNamespace>CoordinateSharp</RootNamespace>
<Description>A simple .NET standard library that is designed to assist with geographic coordinate conversions, formatting and location based celestial calculations.</Description>
<Copyright>Copyright 2019</Copyright>
<Version>1.1.5.2</Version>
</PropertyGroup>
</Project>

View File

@ -1,442 +1,382 @@
using System;
using System.Diagnostics;
namespace CoordinateSharp
{
namespace CoordinateSharp {
/// <summary>
/// Contains distance values between two coordinates.
/// </summary>
[Serializable]
public class Distance {
/// <summary>
/// Contains distance values between two coordinates.
/// Initializes a distance object using Haversine (Spherical Earth).
/// </summary>
[Serializable]
public class Distance
{
private double kilometers;
private double miles;
private double feet;
private double meters;
private double bearing;
private double nauticalMiles;
/// <summary>
/// Initializes a distance object using Haversine (Spherical Earth).
/// </summary>
/// <param name="c1">Coordinate 1</param>
/// <param name="c2">Coordinate 2</param>
public Distance(Coordinate c1, Coordinate c2)
{
Haversine(c1, c2);
}
/// <summary>
/// Initializes a distance object using Haversine (Spherical Earth) or Vincenty (Elliptical Earth).
/// </summary>
/// <param name="c1">Coordinate 1</param>
/// <param name="c2">Coordinate 2</param>
/// <param name="shape">Shape of earth</param>
public Distance(Coordinate c1, Coordinate c2, Shape shape)
{
if (shape == Shape.Sphere)
{
Haversine(c1, c2);
}
else
{
Vincenty(c1, c2);
}
}
/// <summary>
/// Initializes distance object based on distance in KM
/// </summary>
/// <param name="km">Kilometers</param>
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
}
/// <summary>
/// Initializaes distance object based on specified distance and measurement type
/// </summary>
/// <param name="distance">Distance</param>
/// <param name="type">Measurement type</param>
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;
}
/// <summary>
/// Distance in Kilometers
/// </summary>
public double Kilometers
{
get { return kilometers; }
}
/// <summary>
/// Distance in Statute Miles
/// </summary>
public double Miles
{
get { return miles; }
}
/// <summary>
/// Distance in Nautical Miles
/// </summary>
public double NauticalMiles
{
get { return nauticalMiles; }
}
/// <summary>
/// Distance in Meters
/// </summary>
public double Meters
{
get { return meters; }
}
/// <summary>
/// Distance in Feet
/// </summary>
public double Feet
{
get { return feet; }
}
/// <summary>
/// Initial Bearing from Coordinate 1 to Coordinate 2
/// </summary>
public double Bearing
{
get { return bearing; }
}
/// <param name="c1">Coordinate 1</param>
/// <param name="c2">Coordinate 2</param>
public Distance(Coordinate c1, Coordinate c2) => this.Haversine(c1, c2);
/// <summary>
/// Initializes a distance object using Haversine (Spherical Earth) or Vincenty (Elliptical Earth).
/// </summary>
/// <param name="c1">Coordinate 1</param>
/// <param name="c2">Coordinate 2</param>
/// <param name="shape">Shape of earth</param>
public Distance(Coordinate c1, Coordinate c2, Shape shape) {
if (shape == Shape.Sphere) {
this.Haversine(c1, c2);
} else {
this.Vincenty(c1, c2);
}
}
/// <summary>
/// Distance measurement type
/// Initializes distance object based on distance in KM
/// </summary>
public enum DistanceType
{
/// <summary>
/// Distance in Meters
/// </summary>
Meters,
/// <summary>
/// Distance in Kilometers
/// </summary>
Kilometers,
/// <summary>
/// Distance in Feet
/// </summary>
Feet,
/// <summary>
/// Distance in Statute Miles
/// </summary>
Miles,
/// <summary>
/// Distance in Nautical Miles
/// </summary>
NauticalMiles
/// <param name="km">Kilometers</param>
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
}
/// <summary>
/// Initializaes distance object based on specified distance and measurement type
/// </summary>
/// <param name="distance">Distance</param>
/// <param name="type">Measurement type</param>
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
{
/// <summary>
/// Returns new geodetic coordinate in radians
/// </summary>
/// <param name="glat1">Latitude in Radians</param>
/// <param name="glon1">Longitude in Radians</param>
/// <param name="faz">Bearing</param>
/// <param name="s">Distance</param>
/// <param name="ellipse">Earth Ellipse Values</param>
/// <returns>double[]</returns>
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 };
}
/// <summary>
/// Returns new geodetic coordinate in radians
/// </summary>
/// <param name="lat1">Latitude in radians</param>
/// <param name="lon1">Longitude in radians</param>
/// <param name="crs12">Bearing</param>
/// <param name="d12">Distance</param>
/// <returns>double[]</returns>
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;
}
/// <summary>
/// Distance in Kilometers
/// </summary>
public Double Kilometers { get; private set; }
/// <summary>
/// Distance in Statute Miles
/// </summary>
public Double Miles { get; private set; }
/// <summary>
/// Distance in Nautical Miles
/// </summary>
public Double NauticalMiles { get; private set; }
/// <summary>
/// Distance in Meters
/// </summary>
public Double Meters { get; private set; }
/// <summary>
/// Distance in Feet
/// </summary>
public Double Feet { get; private set; }
/// <summary>
/// Initial Bearing from Coordinate 1 to Coordinate 2
/// </summary>
public Double Bearing { get; private set; }
}
/// <summary>
/// Distance measurement type
/// </summary>
public enum DistanceType {
/// <summary>
/// Distance in Meters
/// </summary>
Meters,
/// <summary>
/// Distance in Kilometers
/// </summary>
Kilometers,
/// <summary>
/// Distance in Feet
/// </summary>
Feet,
/// <summary>
/// Distance in Statute Miles
/// </summary>
Miles,
/// <summary>
/// Distance in Nautical Miles
/// </summary>
NauticalMiles
}
[Serializable]
internal class Distance_Assistant {
/// <summary>
/// Returns new geodetic coordinate in radians
/// </summary>
/// <param name="glat1">Latitude in Radians</param>
/// <param name="glon1">Longitude in Radians</param>
/// <param name="faz">Bearing</param>
/// <param name="s">Distance</param>
/// <param name="ellipse">Earth Ellipse Values</param>
/// <returns>double[]</returns>
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 };
}
/// <summary>
/// Returns new geodetic coordinate in radians
/// </summary>
/// <param name="lat1">Latitude in radians</param>
/// <param name="lon1">Longitude in radians</param>
/// <param name="crs12">Bearing</param>
/// <param name="d12">Distance</param>
/// <returns>double[]</returns>
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 };
}
}
}

View File

@ -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<double[]> data = new List<double[]>()
{
public static Double[] LunarDateData(DateTime d) {
//Return combined 100 year arrays so in order to grab Last and Next exlipLE.
List<Double[]> data = new List<Double[]>()
{
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<double[]> data = new List<double[]>()
{
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<Double[]> data = new List<Double[]>()
{
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;
}
}
}

View File

@ -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<double[]> data = new List<double[]>()
{
public static Double[] SolarDateData(DateTime d) {
//Return combined 100 year arrays so in order to grab Last and Next exlipse.
List<Double[]> data = new List<Double[]>()
{
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<double[]> data = new List<double[]>()
{
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<Double[]> data = new List<Double[]>()
{
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;
}
}
}

View File

@ -1,161 +1,138 @@
using System.Collections.Generic;
using System.Linq;
using System;
using System.Collections.Generic;
namespace CoordinateSharp {
/// <summary>
/// Geo Fence class. It helps to check if points/coordinates are inside a polygon,
/// Next to a polyline, and counting...
/// </summary>
public class GeoFence {
#region Fields
private readonly List<Point> _points = new List<Point>();
#endregion
namespace CoordinateSharp
{
/// <summary>
/// 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
/// </summary>
public class GeoFence
{
#region Fields
private List<Point> _points = new List<Point>();
#endregion
/// <param name="points">List of points</param>
public GeoFence(List<Point> points) => this._points = points;
/// <summary>
/// Prepare GeoFence with a list of points
/// </summary>
/// <param name="points">List of points</param>
public GeoFence(List<Point> points)
{
_points = points;
}
/// <summary>
/// Prepare Geofence with a list of coordinates
/// </summary>
/// <param name="coordinates">List of coordinates</param>
public GeoFence(List<Coordinate> 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
/// <summary>
/// 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.
/// </summary>
/// <param name="point">The point to test</param>
/// <returns>bool</returns>
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;
}
/// <summary>
/// The function will return true if the point x,y is next the given range of
/// the polyline, or false if it is not.
/// </summary>
/// <param name="point">The point to test</param>
/// <param name="range">The range in meters</param>
/// <returns>bool</returns>
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;
}
/// <summary>
/// The function will return true if the point x,y is next the given range of
/// the polyline, or false if it is not.
/// </summary>
/// <param name="point">The point to test</param>
/// <param name="range">The range is a distance object</param>
/// <returns>bool</returns>
public bool IsPointInRangeOfLine(Coordinate point, Distance range)
{
if (point == null || range == null)
return false;
return IsPointInRangeOfLine(point, range.Meters);
}
/// <summary>
/// This class is a help class to simplify GeoFence calculus
/// </summary>
public class Point
{
/// <summary>
/// Initialize empty point
/// </summary>
public Point()
{
}
/// <summary>
/// Initialize point with defined Latitude and Longitude
/// </summary>
/// <param name="lat">Latitude (signed)</param>
/// <param name="lng">Longitude (signed)</param>
public Point(double lat, double lng)
{
Latitude = lat;
Longitude = lng;
}
/// <summary>
/// The longitude in degrees
/// </summary>
public double Longitude;
/// <summary>
/// The latitude in degrees
/// </summary>
public double Latitude;
}
/// <summary>
/// Prepare Geofence with a list of coordinates
/// </summary>
/// <param name="coordinates">List of coordinates</param>
public GeoFence(List<Coordinate> 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
/// <summary>
/// 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.
/// </summary>
/// <param name="point">The point to test</param>
/// <returns>bool</returns>
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;
}
/// <summary>
/// The function will return true if the point x,y is next the given range of
/// the polyline, or false if it is not.
/// </summary>
/// <param name="point">The point to test</param>
/// <param name="range">The range in meters</param>
/// <returns>bool</returns>
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;
}
/// <summary>
/// The function will return true if the point x,y is next the given range of
/// the polyline, or false if it is not.
/// </summary>
/// <param name="point">The point to test</param>
/// <param name="range">The range is a distance object</param>
/// <returns>bool</returns>
public Boolean IsPointInRangeOfLine(Coordinate point, Distance range) => point == null || range == null ? false : this.IsPointInRangeOfLine(point, range.Meters);
/// <summary>
/// This class is a help class to simplify GeoFence calculus
/// </summary>
public class Point {
/// <summary>
/// Initialize empty point
/// </summary>
public Point() {
}
/// <summary>
/// Initialize point with defined Latitude and Longitude
/// </summary>
/// <param name="lat">Latitude (signed)</param>
/// <param name="lng">Longitude (signed)</param>
public Point(Double lat, Double lng) {
this.Latitude = lat;
this.Longitude = lng;
}
/// <summary>
/// The longitude in degrees
/// </summary>
public Double Longitude;
/// <summary>
/// The latitude in degrees
/// </summary>
public Double Latitude;
}
}
}

View File

@ -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

25
CoordinateSharp_Core.sln Normal file
View File

@ -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