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;
using System.Collections.Generic; using System.Collections.Generic;
namespace CoordinateSharp namespace CoordinateSharp {
{ //CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
//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
//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
//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 //ELLIPSOID ADJUSTMENT
//6378140.0 Ellipsoid is used in the NASA Calculator //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. //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. //This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
//CURRENT RANGE 1601-2600. //CURRENT RANGE 1601-2600.
internal class LunarEclipseCalc internal class LunarEclipseCalc {
{ public static List<List<String>> CalculateLunarEclipse(DateTime d, Double latRad, Double longRad) => Calculate(d, latRad, longRad);
public static List<List<string>> CalculateLunarEclipse(DateTime d, double latRad, double longRad) public static List<LunarEclipseDetails> CalculateLunarEclipse(DateTime d, Double latRad, Double longRad, Double[] events) {
{ List<List<String>> evs = Calculate(d, latRad, longRad, events);
return Calculate(d, latRad, longRad); List<LunarEclipseDetails> deetsList = new List<LunarEclipseDetails>();
} foreach (List<String> ls in evs) {
public static List<LunarEclipseDetails> CalculateLunarEclipse(DateTime d, double latRad, double longRad, double[] events) LunarEclipseDetails deets = new LunarEclipseDetails(ls);
{ deetsList.Add(deets);
List<List<string>> evs = Calculate(d, latRad, longRad, events); }
List<LunarEclipseDetails> deetsList = new List<LunarEclipseDetails>(); return deetsList;
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;
}
}
} }
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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CoordinateSharp namespace CoordinateSharp {
{ internal partial class MeeusTables {
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, 0,0,1,0,
2,0,-1,0, 2,0,-1,0,
2,0,0,0, 2,0,0,0,
@ -71,9 +66,9 @@ namespace CoordinateSharp
1,1,-1,0, 1,1,-1,0,
2,0,3,0, 2,0,3,0,
2,0,-1,-2 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,0,1,
0,0,1,1, 0,0,1,1,
0,0,1,-1, 0,0,1,-1,
@ -135,9 +130,9 @@ namespace CoordinateSharp
1,0,-1,-1, 1,0,-1,-1,
4,-1,0,-1, 4,-1,0,-1,
2,-2,0,1, 2,-2,0,1,
}; };
private static double[] Table47A_El_Er = new double[] private static readonly Double[] Table47A_El_Er = new Double[]
{ {
//El //El
6288774, 1274027,658314,213618,-185116,-114332,58793,57066,53322,45758, 6288774, 1274027,658314,213618,-185116,-114332,58793,57066,53322,45758,
-40923,-34720,-30383,15327,-12528,10980,10675,10034,8548,-7888,-6766,-5163, -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, -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 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, 5128122,280602,277693,173237,55413,46271,32573,17198,9266,8822,
8216,4324,4200,-3359,2463,2211,2065,-1870,1828,-1794,-1749,-1565,-1491, 8216,4324,4200,-3359,2463,2211,2065,-1870,1828,-1794,-1749,-1565,-1491,
-1475,-1410,-1344,-1335,1107,1021,833, -1475,-1410,-1344,-1335,1107,1021,833,
777,671,607,596,491,-451,439,422,421,-366,-351,331,315,302,-283,-229, 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 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) private static Double Get_Table47A_Values(Double[] values, Int32 l, Double t, Boolean sine) {
{ //sine true returns El
//sine true returns El //sine false return Er
//sine false return Er //Er values start at 60 in the Table47A_El_Er array.
//Er values start at 60 in the Table47A_El_Er array.
int nl = l * 4; Int32 nl = l * 4;
if (sine) if (sine) {
{ Double e = 1;
double e = 1;
if (Table47A_Arguments[nl + 1] != 0) if (Table47A_Arguments[nl + 1] != 0) {
{ e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
if (Math.Abs(Table47A_Arguments[nl + 1]) == 2) if (Math.Abs(Table47A_Arguments[nl + 1]) == 2) {
{ e *= e;
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]);
}
} }
private static double Get_Table47B_Values(double[] values, int l, double t) 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 {
int nl = l * 4; Double e = 1;
double e = 1; if (Table47A_Arguments[nl + 1] != 0) {
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
if (Table47B_Arguments[nl + 1] != 0) if (Math.Abs(Table47A_Arguments[nl + 1]) == 2) {
{ e *= e;
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]);
} }
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;
using System.Collections.Generic; 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 namespace CoordinateSharp {
internal class SunCalc {
//Get Julian public static void CalculateSunTime(Double lat, Double longi, DateTime date, Celestial c, Double _ = 0) {
double lw = rad * -longi; if (date.Year == 0001) { return; } //Return if date vaue hasn't been established.
double phi = rad * lat; DateTime actualDate = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc);
//Rise Set ////Sun Time Calculations
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;
} //Get Julian
else if (!c.SunSet.HasValue) Double lw = rad * -longi;
{ Double phi = rad * lat;
// 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];
//Rise Set
DateTime?[] evDate = Get_Event_Time(lw, phi, -.8333, actualDate);
c.sunRise = evDate[0];
c.sunSet = evDate[1];
//Nautical c.sunCondition = CelestialStatus.RiseAndSet;
evDate = Get_Event_Time(lw, phi, -12, actualDate); //Azimuth and Altitude
c.AdditionalSolarTimes.NauticalDawn = evDate[0]; CalculateSunAngle(date, longi, lat, c);
c.AdditionalSolarTimes.NauticalDusk = evDate[1]; // 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 } else if (!c.SunSet.HasValue) {
evDate = Get_Event_Time(lw, phi, -18, actualDate); // No sunset this date
c.sunCondition = CelestialStatus.NoSet;
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 };
} }
}
//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 //Nautical
private static readonly double dayMS = 1000 * 60 * 60 * 24, j1970 = 2440588, j2000 = 2451545; evDate = Get_Event_Time(lw, phi, -12, actualDate);
private static readonly double rad = Math.PI / 180; c.AdditionalSolarTimes.NauticalDawn = evDate[0];
c.AdditionalSolarTimes.NauticalDusk = evDate[1];
private static double LocalSiderealTimeForTimeZone(double lon, double jd, double z) //Astronomical
{ evDate = Get_Event_Time(lw, phi, -18, actualDate);
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)); }
//Returns Time of specified event based on suns angle c.AdditionalSolarTimes.AstronomicalDawn = evDate[0];
private static double GetTime(double h, double lw, double phi, double dec, double n,double M, double L) c.AdditionalSolarTimes.AstronomicalDusk = evDate[1];
{
double approxTime = hourAngle(h, phi, dec); //Ch15 Formula 15.1
double a = approxTransit(approxTime, lw, n); //BottomDisc
double st = solarTransitJ(a, M, L); evDate = Get_Event_Time(lw, phi, -.2998, actualDate);
c.AdditionalSolarTimes.SunriseBottomDisc = evDate[0];
return st; c.AdditionalSolarTimes.SunsetBottomDisc = evDate[1];
}
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; CalculateSolarEclipse(date, lat, longi, c);
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)
{
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.Collections.Generic;
using System.Linq; using System.Linq;
namespace CoordinateSharp namespace CoordinateSharp {
{
/// <summary>
/// Used for UTM/MGRS Conversions /// <summary>
/// </summary> /// Used for UTM/MGRS Conversions
[Serializable] /// </summary>
internal class LatZones [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", 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"}); "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> /// <summary>
/// Used for handling diagraph determination /// Latitude
/// </summary> /// </summary>
[Serializable] Lat,
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;
}
}
/// <summary> /// <summary>
/// Diagraph model /// Longitude
/// </summary> /// </summary>
[Serializable] Long
internal class Digraph }
{ /// <summary>
public int Zone { get; set; } /// Used to set a coordinate part position.
public string Letter { get; set; } /// </summary>
} [Serializable]
public enum CoordinatesPosition : Int32 {
/// <summary> /// <summary>
/// Used for setting whether a coordinate part is latitudinal or longitudinal. /// North
/// </summary> /// </summary>
[Serializable] N,
public enum CoordinateType
{
/// <summary>
/// Latitude
/// </summary>
Lat,
/// <summary>
/// Longitude
/// </summary>
Long
}
/// <summary> /// <summary>
/// Used to set a coordinate part position. /// East
/// </summary> /// </summary>
[Serializable] E,
public enum CoordinatesPosition :int
{
/// <summary>
/// North
/// </summary>
N,
/// <summary>
/// East
/// </summary>
E,
/// <summary>
/// South
/// </summary>
S,
/// <summary>
/// West
/// </summary>
W
}
/// <summary> /// <summary>
/// Coordinate type datum specification /// South
/// </summary> /// </summary>
[Serializable] S,
[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,
}
/// <summary> /// <summary>
/// Cartesian Coordinate Type /// West
/// </summary> /// </summary>
public enum CartesianType W
{ }
/// <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);
}
public static double ModLon(double x)
{
return Mod(x + Math.PI, 2 * Math.PI) - Math.PI;
}
public static double ModCrs(double x) /// <summary>
{ /// Coordinate type datum specification
return Mod(x, 2 * Math.PI); /// </summary>
} [Serializable]
[Flags]
public static double ModLat(double x) public enum Coordinate_Datum {
{
return Mod(x + Math.PI / 2, 2 * Math.PI) - Math.PI / 2;
}
}
/// <summary> /// <summary>
/// Earth Shape for Calculations. /// Lat Long GeoDetic
/// </summary> /// </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;
using System.ComponentModel; using System.ComponentModel;
namespace CoordinateSharp
{ namespace CoordinateSharp {
/// <summary>
/// Cartesian (X, Y, Z) Coordinate
/// </summary>
[Serializable]
public class Cartesian : INotifyPropertyChanged {
/// <summary> /// <summary>
/// Cartesian (X, Y, Z) Coordinate /// Create a Cartesian Object
/// </summary> /// </summary>
[Serializable] /// <param name="c"></param>
public class Cartesian : INotifyPropertyChanged public Cartesian(Coordinate c) {
{ //formulas:
/// <summary> this.x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
/// Create a Cartesian Object this.y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
/// </summary> this.z = Math.Sin(c.Latitude.ToRadians());
/// <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));
}
}
} }
/// <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;
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> /// <summary>
/// Turn on/off eager loading of certain properties. /// Create an EagerLoad object
/// </summary> /// </summary>
[Serializable] public EagerLoad() {
public class EagerLoad this.Celestial = true;
{ this.UTM_MGRS = true;
/// <summary> this.Cartesian = true;
/// Create an EagerLoad object this.ECEF = true;
/// </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; }
} }
/// <summary> /// <summary>
/// EagerLoad Enumerator /// Create an EagerLoad object with all options on or off
/// </summary> /// </summary>
[Serializable] /// <param name="isOn">Turns EagerLoad on or off</param>
[Flags] public EagerLoad(Boolean isOn) {
public enum EagerLoadType this.Celestial = isOn;
{ this.UTM_MGRS = isOn;
/// <summary> this.Cartesian = isOn;
/// UTM and MGRS this.ECEF = isOn;
/// </summary>
UTM_MGRS = 1,
/// <summary>
/// Celestial
/// </summary>
Celestial = 2,
/// <summary>
/// Cartesian
/// </summary>
Cartesian = 4,
/// <summary>
/// ECEF
/// </summary>
ECEF = 8
} }
/// <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;
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> /// <summary>
/// Coordinate formatting options for a Coordinate object. /// Set default values with the constructor.
/// </summary> /// </summary>
[Serializable] public CoordinateFormatOptions() {
public class CoordinateFormatOptions this.Format = CoordinateFormatType.Degree_Minutes_Seconds;
{ this.Round = 3;
/// <summary> this.Display_Leading_Zeros = false;
/// Set default values with the constructor. this.Display_Trailing_Zeros = false;
/// </summary> this.Display_Symbols = true;
public CoordinateFormatOptions() this.Display_Degree_Symbol = true;
{ this.Display_Minute_Symbol = true;
Format = CoordinateFormatType.Degree_Minutes_Seconds; this.Display_Seconds_Symbol = true;
Round = 3; this.Display_Hyphens = false;
Display_Leading_Zeros = false; this.Position_First = true;
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; }
} }
/// <summary> /// <summary>
/// Coordinate Format Types. /// Coordinate format type.
/// </summary> /// </summary>
[Serializable] public CoordinateFormatType Format { get; set; }
public enum CoordinateFormatType /// <summary>
{ /// Rounds Coordinates to the set value.
/// <summary> /// </summary>
/// Decimal Degree Format public Int32 Round { get; set; }
/// </summary> /// <summary>
/// <remarks> /// Displays leading zeros.
/// Example: N 40.456 W 75.456 /// </summary>
/// </remarks> public Boolean Display_Leading_Zeros { get; set; }
Decimal_Degree, /// <summary>
/// <summary> /// Display trailing zeros.
/// Decimal Degree Minutes Format /// </summary>
/// </summary> public Boolean Display_Trailing_Zeros { get; set; }
/// <remarks> /// <summary>
/// Example: N 40º 34.552' W 70º 45.408' /// Allow symbols to display.
/// </remarks> /// </summary>
Degree_Decimal_Minutes, public Boolean Display_Symbols { get; set; }
/// <summary> /// <summary>
/// Decimal Degree Minutes Format /// Display degree symbols.
/// </summary> /// </summary>
/// <remarks> public Boolean Display_Degree_Symbol { get; set; }
/// Example: N 40º 34" 36.552' W 70º 45" 24.408' /// <summary>
/// </remarks> /// Display minute symbols.
Degree_Minutes_Seconds, /// </summary>
/// <summary> public Boolean Display_Minute_Symbol { get; set; }
/// Decimal Format /// <summary>
/// </summary> /// Display secons symbol.
/// <remarks> /// </summary>
/// Example: 40.57674 -70.46574 public Boolean Display_Seconds_Symbol { get; set; }
/// </remarks> /// <summary>
Decimal /// 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;
using System.Linq;
using System.Diagnostics;
using System.ComponentModel; 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> /// <summary>
/// Military Grid Reference System (MGRS). Uses the WGS 84 Datum. /// Create an MGRS object with WGS84 datum
/// Relies upon values from the UniversalTransverseMercator class
/// </summary> /// </summary>
[Serializable] /// <param name="latz">Lat Zone</param>
public class MilitaryGridReferenceSystem : INotifyPropertyChanged /// <param name="longz">Long Zone</param>
{ /// <param name="d">Digraph</param>
/// <summary> /// <param name="e">Easting</param>
/// Create an MGRS object with WGS84 datum /// <param name="n">Northing</param>
/// </summary> public MilitaryGridReferenceSystem(String latz, Int32 longz, String d, Double e, Double n) {
/// <param name="latz">Lat Zone</param> String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
/// <param name="longz">Long Zone</param> String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
/// <param name="d">Digraph</param> if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
/// <param name="e">Easting</param> if (!this.Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
/// <param name="n">Northing</param> if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
public MilitaryGridReferenceSystem(string latz, int longz, string d, double e, double n) 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."); }
string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ"; if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV"; this.LatZone = latz;
if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); } this.LongZone = longz;
if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); } this.Digraph = d;
if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); } this.Easting = e;
if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } this.Northing = n;
if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } //WGS84
if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } this.equatorialRadius = 6378137.0;
latZone = latz; this.inverseFlattening = 298.257223563;
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;
}
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;
using System.ComponentModel; using System.ComponentModel;
namespace CoordinateSharp namespace CoordinateSharp {
{
/// <summary> /// <summary>
/// Observable class for handling all location based information. /// Observable class for handling all location based information.
/// This is the main class for CoordinateSharp. /// 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 /// All information should be pulled from this class to include celestial information
/// </remarks> /// </remarks>
[Serializable] [Serializable]
public class Coordinate : INotifyPropertyChanged public class Coordinate : INotifyPropertyChanged {
{
/// <summary> /// <summary>
/// Creates an empty Coordinate. /// Creates an empty Coordinate.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Values will need to be provided to latitude/longitude CoordinateParts manually /// Values will need to be provided to latitude/longitude CoordinateParts manually
/// </remarks> /// </remarks>
public Coordinate() public Coordinate() {
{
this.FormatOptions = new CoordinateFormatOptions(); this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc); this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(CoordinateType.Lat); this.latitude = new CoordinatePart(CoordinateType.Lat);
@ -77,8 +74,7 @@ namespace CoordinateSharp
/// <remarks> /// <remarks>
/// Values will need to be provided to latitude/longitude CoordinateParts manually /// Values will need to be provided to latitude/longitude CoordinateParts manually
/// </remarks> /// </remarks>
internal Coordinate(Double equatorialRadius, Double inverseFlattening, Boolean t) internal Coordinate(Double equatorialRadius, Double inverseFlattening, Boolean _) {
{
this.FormatOptions = new CoordinateFormatOptions(); this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc); this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(CoordinateType.Lat); this.latitude = new CoordinatePart(CoordinateType.Lat);
@ -102,8 +98,7 @@ namespace CoordinateSharp
/// <remarks> /// <remarks>
/// Geodate will default to 1/1/1900 GMT until provided /// Geodate will default to 1/1/1900 GMT until provided
/// </remarks> /// </remarks>
public Coordinate(Double lat, Double longi) public Coordinate(Double lat, Double longi) {
{
this.FormatOptions = new CoordinateFormatOptions(); this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc); this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(lat, CoordinateType.Lat); this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
@ -126,8 +121,7 @@ namespace CoordinateSharp
/// <param name="lat">latitude</param> /// <param name="lat">latitude</param>
/// <param name="longi">longitude</param> /// <param name="longi">longitude</param>
/// <param name="date">DateTime (UTC)</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.FormatOptions = new CoordinateFormatOptions();
this.latitude = new CoordinatePart(lat, CoordinateType.Lat); this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
this.longitude = new CoordinatePart(longi, CoordinateType.Long); this.longitude = new CoordinatePart(longi, CoordinateType.Long);
@ -152,8 +146,7 @@ namespace CoordinateSharp
/// Values will need to be provided to latitude/longitude manually /// Values will need to be provided to latitude/longitude manually
/// </remarks> /// </remarks>
/// <param name="eagerLoad">Eager loading options</param> /// <param name="eagerLoad">Eager loading options</param>
public Coordinate(EagerLoad eagerLoad) public Coordinate(EagerLoad eagerLoad) {
{
this.FormatOptions = new CoordinateFormatOptions(); this.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc); this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(CoordinateType.Lat); this.latitude = new CoordinatePart(CoordinateType.Lat);
@ -188,8 +181,7 @@ namespace CoordinateSharp
/// <param name="lat">latitude</param> /// <param name="lat">latitude</param>
/// <param name="longi">longitude</param> /// <param name="longi">longitude</param>
/// <param name="eagerLoad">Eager loading options</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.FormatOptions = new CoordinateFormatOptions();
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc); this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
this.latitude = new CoordinatePart(lat, CoordinateType.Lat); this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
@ -223,8 +215,7 @@ namespace CoordinateSharp
/// <param name="longi">Decimal format longitude</param> /// <param name="longi">Decimal format longitude</param>
/// <param name="date">DateTime you wish to use for celestial calculation</param> /// <param name="date">DateTime you wish to use for celestial calculation</param>
/// <param name="eagerLoad">Eager loading options</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.FormatOptions = new CoordinateFormatOptions();
this.latitude = new CoordinatePart(lat, CoordinateType.Lat); this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
this.longitude = new CoordinatePart(longi, CoordinateType.Long); this.longitude = new CoordinatePart(longi, CoordinateType.Long);
@ -261,8 +252,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Latitudinal Coordinate Part /// Latitudinal Coordinate Part
/// </summary> /// </summary>
public CoordinatePart Latitude public CoordinatePart Latitude {
{
get => this.latitude; get => this.latitude;
set { set {
if (this.latitude != value) { if (this.latitude != value) {
@ -292,8 +282,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Longitudinal Coordinate Part /// Longitudinal Coordinate Part
/// </summary> /// </summary>
public CoordinatePart Longitude public CoordinatePart Longitude {
{
get => this.longitude; get => this.longitude;
set { set {
if (this.longitude != value) { if (this.longitude != value) {
@ -325,8 +314,7 @@ namespace CoordinateSharp
/// <remarks> /// <remarks>
/// Assumes all times are in UTC /// Assumes all times are in UTC
/// </remarks> /// </remarks>
public DateTime GeoDate public DateTime GeoDate {
{
get => this.geoDate; get => this.geoDate;
set { set {
if (this.geoDate != value) { if (this.geoDate != value) {
@ -357,8 +345,7 @@ namespace CoordinateSharp
/// Uses Ellipsoidal height with no geoid model included. /// Uses Ellipsoidal height with no geoid model included.
/// 0 = Mean Sea Level based on the provided Datum. /// 0 = Mean Sea Level based on the provided Datum.
/// </summary> /// </summary>
public ECEF ECEF public ECEF ECEF {
{
get => this.ecef; get => this.ecef;
//Required due to GeoDetic Height //Required due to GeoDetic Height
@ -376,8 +363,7 @@ namespace CoordinateSharp
/// Used to determine what format the coordinate was parsed from. /// Used to determine what format the coordinate was parsed from.
/// Will equal "None" if Coordinate was not initialzed via a TryParse() method. /// Will equal "None" if Coordinate was not initialzed via a TryParse() method.
/// </summary> /// </summary>
public Parse_Format_Type Parse_Format public Parse_Format_Type Parse_Format {
{
get => this.parse_Format; get => this.parse_Format;
internal set { internal set {
if (this.parse_Format != value) { if (this.parse_Format != value) {
@ -399,8 +385,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Initialize UTM and MGRS information (required if eager loading is turned off). /// Initialize UTM and MGRS information (required if eager loading is turned off).
/// </summary> /// </summary>
public void LoadUTM_MGRS_Info() public void LoadUTM_MGRS_Info() {
{
this.UTM = new UniversalTransverseMercator(this.latitude.ToDouble(), this.longitude.ToDouble(), this); this.UTM = new UniversalTransverseMercator(this.latitude.ToDouble(), this.longitude.ToDouble(), this);
this.MGRS = new MilitaryGridReferenceSystem(this.UTM); this.MGRS = new MilitaryGridReferenceSystem(this.UTM);
} }
@ -431,8 +416,7 @@ namespace CoordinateSharp
/// Overridden Coordinate ToString() method. /// Overridden Coordinate ToString() method.
/// </summary> /// </summary>
/// <returns>string (formatted).</returns> /// <returns>string (formatted).</returns>
public override String ToString() public override String ToString() {
{
String latString = this.latitude.ToString(); String latString = this.latitude.ToString();
String longSting = this.longitude.ToString(); String longSting = this.longitude.ToString();
return latString + " " + longSting; return latString + " " + longSting;
@ -444,8 +428,7 @@ namespace CoordinateSharp
/// </summary> /// </summary>
/// <param name="options">CoordinateFormatOptions</param> /// <param name="options">CoordinateFormatOptions</param>
/// <returns>Custom formatted coordinate</returns> /// <returns>Custom formatted coordinate</returns>
public String ToString(CoordinateFormatOptions options) public String ToString(CoordinateFormatOptions options) {
{
String latString = this.latitude.ToString(options); String latString = this.latitude.ToString(options);
String longSting = this.longitude.ToString(options); String longSting = this.longitude.ToString(options);
return latString + " " + longSting; return latString + " " + longSting;
@ -458,8 +441,7 @@ namespace CoordinateSharp
/// </summary> /// </summary>
/// <param name="radius">Equatorial Radius</param> /// <param name="radius">Equatorial Radius</param>
/// <param name="flat">Inverse Flattening</param> /// <param name="flat">Inverse Flattening</param>
public void Set_Datum(Double radius, Double flat) public void Set_Datum(Double radius, Double flat) {
{
//WGS84 //WGS84
//RADIUS 6378137.0; //RADIUS 6378137.0;
//FLATTENING 298.257223563; //FLATTENING 298.257223563;
@ -487,8 +469,7 @@ namespace CoordinateSharp
/// <param name="radius">Equatorial Radius</param> /// <param name="radius">Equatorial Radius</param>
/// <param name="flat">Inverse Flattening</param> /// <param name="flat">Inverse Flattening</param>
/// <param name="cd">Coordinate_Datum</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 //WGS84
//RADIUS 6378137.0; //RADIUS 6378137.0;
//FLATTENING 298.257223563; //FLATTENING 298.257223563;
@ -554,8 +535,7 @@ namespace CoordinateSharp
/// //New Coordinate - N 25º 4' 54.517" E 24º 57' 29.189" /// //New Coordinate - N 25º 4' 54.517" E 24º 57' 29.189"
/// </code> /// </code>
/// </example> /// </example>
public void Move(Double distance, Double bearing, Shape shape) public void Move(Double distance, Double bearing, Shape shape) {
{
//Convert to Radians for formula //Convert to Radians for formula
Double lat1 = this.latitude.ToRadians(); Double lat1 = this.latitude.ToRadians();
Double lon1 = this.longitude.ToRadians(); Double lon1 = this.longitude.ToRadians();
@ -605,8 +585,7 @@ namespace CoordinateSharp
/// //New Coordinate - N 24º 56' 21.526" E 25º 4' 23.944" /// //New Coordinate - N 24º 56' 21.526" E 25º 4' 23.944"
/// </code> /// </code>
/// </example> /// </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); Distance d = new Distance(this, target, shape);
//Convert to Radians for formula //Convert to Radians for formula
Double lat1 = this.latitude.ToRadians(); Double lat1 = this.latitude.ToRadians();
@ -656,8 +635,7 @@ namespace CoordinateSharp
/// //New Coordinate - N 25º 4' 54.517" E 24º 57' 29.189" /// //New Coordinate - N 25º 4' 54.517" E 24º 57' 29.189"
/// </code> /// </code>
/// </example> /// </example>
public void Move(Distance distance, Double bearing, Shape shape) public void Move(Distance distance, Double bearing, Shape shape) {
{
//Convert to Radians for formula //Convert to Radians for formula
Double lat1 = this.latitude.ToRadians(); Double lat1 = this.latitude.ToRadians();
Double lon1 = this.longitude.ToRadians(); Double lon1 = this.longitude.ToRadians();
@ -708,8 +686,7 @@ namespace CoordinateSharp
/// //New Coordinate - N 24º 56' 21.526" E 25º 4' 23.944" /// //New Coordinate - N 24º 56' 21.526" E 25º 4' 23.944"
/// </code> /// </code>
/// </example> /// </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); Distance d = new Distance(this, target, shape);
//Convert to Radians for formula //Convert to Radians for formula
Double lat1 = this.latitude.ToRadians(); Double lat1 = this.latitude.ToRadians();
@ -752,9 +729,7 @@ namespace CoordinateSharp
/// } /// }
/// </code> /// </code>
/// </example> /// </example>
public static Boolean TryParse(String s, out Coordinate c) public static Boolean TryParse(String s, out Coordinate c) {
{
c = null;
if (FormatFinder.TryParse(s, CartesianType.Cartesian, out c)) { if (FormatFinder.TryParse(s, CartesianType.Cartesian, out c)) {
Parse_Format_Type pft = c.Parse_Format; Parse_Format_Type pft = c.Parse_Format;
c = new Coordinate(c.Latitude.ToDouble(), c.Longitude.ToDouble()) { c = new Coordinate(c.Latitude.ToDouble(), c.Longitude.ToDouble()) {
@ -781,9 +756,7 @@ namespace CoordinateSharp
/// } /// }
/// </code> /// </code>
/// </example> /// </example>
public static Boolean TryParse(String s, DateTime geoDate, out Coordinate c) public static Boolean TryParse(String s, DateTime geoDate, out Coordinate c) {
{
c = null;
if (FormatFinder.TryParse(s, CartesianType.Cartesian, out c)) { if (FormatFinder.TryParse(s, CartesianType.Cartesian, out c)) {
Parse_Format_Type pft = c.Parse_Format; Parse_Format_Type pft = c.Parse_Format;
c = new Coordinate(c.Latitude.ToDouble(), c.Longitude.ToDouble(), geoDate) { c = new Coordinate(c.Latitude.ToDouble(), c.Longitude.ToDouble(), geoDate) {
@ -810,9 +783,7 @@ namespace CoordinateSharp
/// } /// }
/// </code> /// </code>
/// </example> /// </example>
public static Boolean TryParse(String s, CartesianType ct, out Coordinate c) public static Boolean TryParse(String s, CartesianType ct, out Coordinate c) {
{
c = null;
if (FormatFinder.TryParse(s, ct, out c)) { if (FormatFinder.TryParse(s, ct, out c)) {
Parse_Format_Type pft = c.Parse_Format; Parse_Format_Type pft = c.Parse_Format;
if (ct == CartesianType.ECEF) { if (ct == CartesianType.ECEF) {
@ -845,9 +816,7 @@ namespace CoordinateSharp
/// } /// }
/// </code> /// </code>
/// </example> /// </example>
public static Boolean TryParse(String s, DateTime geoDate, CartesianType ct, out Coordinate c) public static Boolean TryParse(String s, DateTime geoDate, CartesianType ct, out Coordinate c) {
{
c = null;
if (FormatFinder.TryParse(s, ct, out c)) { if (FormatFinder.TryParse(s, ct, out c)) {
Parse_Format_Type pft = c.Parse_Format; Parse_Format_Type pft = c.Parse_Format;
if (ct == CartesianType.ECEF) { if (ct == CartesianType.ECEF) {
@ -872,8 +841,7 @@ namespace CoordinateSharp
/// Notify property changed /// Notify property changed
/// </summary> /// </summary>
/// <param name="propName">Property name</param> /// <param name="propName">Property name</param>
public void NotifyPropertyChanged(String propName) public void NotifyPropertyChanged(String propName) {
{
switch (propName) { switch (propName) {
case "CelestialInfo": case "CelestialInfo":
if (!this.EagerLoadSettings.Celestial || this.CelestialInfo == null) { return; } //Prevent Null Exceptions and calls while eagerloading is off 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. /// Objects can be passed to Coordinate object Latitude and Longitude properties.
/// </remarks> /// </remarks>
[Serializable] [Serializable]
public class CoordinatePart : INotifyPropertyChanged public class CoordinatePart : INotifyPropertyChanged {
{
//Defaults: //Defaults:
//Format: Degrees Minutes Seconds //Format: Degrees Minutes Seconds
//Rounding: Dependent upon selected format //Rounding: Dependent upon selected format
@ -941,8 +908,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Observable decimal format coordinate. /// Observable decimal format coordinate.
/// </summary> /// </summary>
public Double DecimalDegree public Double DecimalDegree {
{
get => this.decimalDegree; get => this.decimalDegree;
set { set {
//If changing, notify the needed property changes //If changing, notify the needed property changes
@ -1018,8 +984,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Observable decimal format minute. /// Observable decimal format minute.
/// </summary> /// </summary>
public Double DecimalMinute public Double DecimalMinute {
{
get => this.decimalMinute; get => this.decimalMinute;
set { set {
if (this.decimalMinute != value) { if (this.decimalMinute != value) {
@ -1048,7 +1013,7 @@ namespace CoordinateSharp
Decimal newDM = decValue / 60; //divide decimalMinute by 60 to get storage value 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; 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 this.decimalDegree = Convert.ToDouble(newDD); //Convert back to double for storage
@ -1064,8 +1029,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Observable coordinate degree. /// Observable coordinate degree.
/// </summary> /// </summary>
public Int32 Degrees public Int32 Degrees {
{
get => this.degrees; get => this.degrees;
set { set {
//Validate Value //Validate Value
@ -1105,8 +1069,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Observable coordinate minute. /// Observable coordinate minute.
/// </summary> /// </summary>
public Int32 Minutes public Int32 Minutes {
{
get => this.minutes; get => this.minutes;
set { set {
if (this.minutes != value) { if (this.minutes != value) {
@ -1114,9 +1077,9 @@ namespace CoordinateSharp
//Validate the minutes //Validate the minutes
Decimal vMin = Convert.ToDecimal(value); Decimal vMin = Convert.ToDecimal(value);
if (this.type == CoordinateType.Lat) { 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 { } 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) { if (value >= 60) {
throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60"); throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60");
@ -1154,8 +1117,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Observable coordinate second. /// Observable coordinate second.
/// </summary> /// </summary>
public Double Seconds public Double Seconds {
{
get => this.seconds; get => this.seconds;
set { set {
if (value < 0) { value *= -1; }//Adjust accidental negative input if (value < 0) { value *= -1; }//Adjust accidental negative input
@ -1182,9 +1144,9 @@ namespace CoordinateSharp
this.seconds = value; this.seconds = value;
Double degABS = Math.Abs(this.decimalDegree); //Make decimalDegree positive //Double degABS = Math.Abs(this.decimalDegree); //Make decimalDegree positive
Double degFloor = Math.Truncate(degABS); //Truncate the number left of the decimal //Double degFloor = Math.Truncate(degABS); //Truncate the number left of the decimal
Decimal f = Convert.ToDecimal(degFloor); //Convert to decimal to keep precision //Decimal f = Convert.ToDecimal(degFloor); //Convert to decimal to keep precision
Decimal secs = Convert.ToDecimal(this.seconds); //Convert seconds to decimal for calculations Decimal secs = Convert.ToDecimal(this.seconds); //Convert seconds to decimal for calculations
secs /= 60; //Convert to storage format secs /= 60; //Convert to storage format
@ -1207,8 +1169,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Observable coordinate position. /// Observable coordinate position.
/// </summary> /// </summary>
public CoordinatesPosition Position public CoordinatesPosition Position {
{
get => this.position; get => this.position;
set { set {
if (this.position != value) { if (this.position != value) {
@ -1231,8 +1192,7 @@ namespace CoordinateSharp
/// <param name="t">CoordinateType</param> /// <param name="t">CoordinateType</param>
/// <param name="c">Parent Coordinate object</param> /// <param name="c">Parent Coordinate object</param>
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")] [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.parent = c;
this.type = t; this.type = t;
this.decimalDegree = 0; this.decimalDegree = 0;
@ -1248,8 +1208,7 @@ namespace CoordinateSharp
/// <param name="t">Coordinate type</param> /// <param name="t">Coordinate type</param>
/// <param name="c">Parent Coordinate object</param> /// <param name="c">Parent Coordinate object</param>
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")] [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.parent = c;
this.type = t; this.type = t;
@ -1287,8 +1246,7 @@ namespace CoordinateSharp
/// <param name="pos">Coordinate Part Position</param> /// <param name="pos">Coordinate Part Position</param>
/// <param name="c">Parent Coordinate</param> /// <param name="c">Parent Coordinate</param>
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")] [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.parent = c;
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long; this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
@ -1308,12 +1266,12 @@ namespace CoordinateSharp
minD += secD; //Decimal Minutes minD += secD; //Decimal Minutes
if (this.type == CoordinateType.Long) { 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 { } 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); 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) { if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
@ -1329,8 +1287,7 @@ namespace CoordinateSharp
/// <param name="pos">Coordinate Part Position</param> /// <param name="pos">Coordinate Part Position</param>
/// <param name="c">Parent Coordinate object</param> /// <param name="c">Parent Coordinate object</param>
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")] [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.parent = c;
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long; 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 (minSec >= 60) { throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60."); }
if (this.type == CoordinateType.Lat) { 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 { } 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.degrees = deg;
this.decimalMinute = minSec; this.decimalMinute = minSec;
@ -1356,7 +1313,7 @@ namespace CoordinateSharp
sec *= 60; sec *= 60;
Decimal secD = Convert.ToDecimal(sec); Decimal secD = Convert.ToDecimal(sec);
this.seconds = Convert.ToDouble(secD); this.seconds = Convert.ToDouble(secD);
Decimal dd = deg + (minD / 60); Decimal dd = deg + minD / 60;
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) { if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
dd *= -1; dd *= -1;
@ -1368,8 +1325,7 @@ namespace CoordinateSharp
/// Creates an empty CoordinatePart. /// Creates an empty CoordinatePart.
/// </summary> /// </summary>
/// <param name="t">CoordinateType</param> /// <param name="t">CoordinateType</param>
public CoordinatePart(CoordinateType t) public CoordinatePart(CoordinateType t) {
{
this.type = t; this.type = t;
this.decimalDegree = 0; this.decimalDegree = 0;
this.degrees = 0; this.degrees = 0;
@ -1382,8 +1338,7 @@ namespace CoordinateSharp
/// </summary> /// </summary>
/// <param name="value">Coordinate decimal value</param> /// <param name="value">Coordinate decimal value</param>
/// <param name="t">Coordinate type</param> /// <param name="t">Coordinate type</param>
public CoordinatePart(Double value, CoordinateType t) public CoordinatePart(Double value, CoordinateType t) {
{
this.type = t; this.type = t;
if (this.type == CoordinateType.Long) { if (this.type == CoordinateType.Long) {
@ -1418,8 +1373,7 @@ namespace CoordinateSharp
/// <param name="min">Minutes</param> /// <param name="min">Minutes</param>
/// <param name="sec">Seconds</param> /// <param name="sec">Seconds</param>
/// <param name="pos">Coordinate Part Position</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; 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."); } 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 minD += secD; //Decimal Minutes
if (this.type == CoordinateType.Long) { 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 { } 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); 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) { if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
@ -1457,8 +1411,7 @@ namespace CoordinateSharp
/// <param name="deg">Degrees</param> /// <param name="deg">Degrees</param>
/// <param name="minSec">Decimal Minutes</param> /// <param name="minSec">Decimal Minutes</param>
/// <param name="pos">Coordinate Part Position</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; 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."); } 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 (minSec >= 60) { throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60."); }
if (this.type == CoordinateType.Lat) { 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 { } 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.degrees = deg;
this.decimalMinute = minSec; this.decimalMinute = minSec;
@ -1482,7 +1435,7 @@ namespace CoordinateSharp
sec *= 60; sec *= 60;
Decimal secD = Convert.ToDecimal(sec); Decimal secD = Convert.ToDecimal(sec);
this.seconds = Convert.ToDouble(secD); this.seconds = Convert.ToDouble(secD);
Decimal dd = deg + (minD / 60); Decimal dd = deg + minD / 60;
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) { if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
dd *= -1; dd *= -1;
@ -1513,46 +1466,25 @@ namespace CoordinateSharp
/// </summary> /// </summary>
/// <param name="options">CoordinateFormatOptions</param> /// <param name="options">CoordinateFormatOptions</param>
/// <returns>Formatted coordinate part string</returns> /// <returns>Formatted coordinate part string</returns>
private String FormatString(CoordinateFormatOptions options) 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;
#region Assign Formatting Rules #region Assign Formatting Rules
switch (options.Format) { ToStringType type = options.Format switch
case CoordinateFormatType.Degree_Minutes_Seconds: {
type = ToStringType.Degree_Minute_Second; CoordinateFormatType.Degree_Minutes_Seconds => ToStringType.Degree_Minute_Second,
break; CoordinateFormatType.Degree_Decimal_Minutes => ToStringType.Degree_Decimal_Minute,
case CoordinateFormatType.Degree_Decimal_Minutes: CoordinateFormatType.Decimal_Degree => ToStringType.Decimal_Degree,
type = ToStringType.Degree_Decimal_Minute; CoordinateFormatType.Decimal => ToStringType.Decimal,
break; _ => ToStringType.Degree_Minute_Second,
case CoordinateFormatType.Decimal_Degree: };
type = ToStringType.Decimal_Degree; Int32? rounding = options.Round;
break; Boolean lead = options.Display_Leading_Zeros;
case CoordinateFormatType.Decimal: Boolean trail = options.Display_Trailing_Zeros;
type = ToStringType.Decimal; Boolean symbols = options.Display_Symbols;
break; Boolean degreeSymbol = options.Display_Degree_Symbol;
default: Boolean minuteSymbol = options.Display_Minute_Symbol;
type = ToStringType.Degree_Minute_Second; Boolean secondsSymbol = options.Display_Seconds_Symbol;
break; Boolean hyphen = options.Display_Hyphens;
} Boolean positionFirst = options.Position_First;
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;
#endregion #endregion
switch (type) { switch (type) {
@ -1576,8 +1508,7 @@ namespace CoordinateSharp
return String.Empty; return String.Empty;
} }
//DMS Coordinate Format //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 leadString = this.Leading_Trailing_Format(lead, false, rounding, this.Position);
String d = String.Format(leadString, this.Degrees); // Degree String 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(); : d + ds + hs + minute + ms + hs + second + ss + hs + this.Position.ToString();
} }
//DDM Coordinate Format //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"; String leadString = "{0:0";
if (lead) { if (lead) {
if (this.Position == CoordinatesPosition.E || this.Position == CoordinatesPosition.W) { if (this.Position == CoordinatesPosition.E || this.Position == CoordinatesPosition.W) {
@ -1646,8 +1576,7 @@ namespace CoordinateSharp
} }
////DD Coordinate Format ////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 degreeS = "";
String hyph = " "; String hyph = " ";
if (degreeSymbol) { degreeS = "º"; } if (degreeSymbol) { degreeS = "º"; }
@ -1672,15 +1601,14 @@ namespace CoordinateSharp
} }
leadTrail += "}"; 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); result = Math.Round(result, rounding);
String d = String.Format(leadTrail, Math.Abs(result)); String d = String.Format(leadTrail, Math.Abs(result));
return positionFirst ? this.Position.ToString() + hyph + d + degreeS : d + degreeS + hyph + this.Position.ToString(); 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"; String leadString = "{0:0";
if (isLead) { if (isLead) {
if (p != null) { 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 Decimal_Degree, Degree_Decimal_Minute, Degree_Minute_Second, Decimal
} }
/// <summary> /// <summary>
/// Notify the correct properties and parent properties. /// Notify the correct properties and parent properties.
/// </summary> /// </summary>
/// <param name="p">Property Type</param> /// <param name="p">Property Type</param>
private void NotifyProperties(PropertyTypes p) private void NotifyProperties(PropertyTypes p) {
{
switch (p) { switch (p) {
case PropertyTypes.DecimalDegree: case PropertyTypes.DecimalDegree:
this.NotifyPropertyChanged("DecimalDegree"); this.NotifyPropertyChanged("DecimalDegree");
@ -1786,8 +1712,7 @@ namespace CoordinateSharp
/// <summary> /// <summary>
/// Used for notifying the correct properties. /// Used for notifying the correct properties.
/// </summary> /// </summary>
private enum PropertyTypes private enum PropertyTypes {
{
DecimalDegree, DecimalMinute, Position, Degree, Minute, Second, FormatChange DecimalDegree, DecimalMinute, Position, Degree, Minute, Second, FormatChange
} }
@ -1811,12 +1736,7 @@ namespace CoordinateSharp
/// } /// }
/// </code> /// </code>
/// </example> /// </example>
public static Boolean TryParse(String s, out CoordinatePart cp) public static Boolean TryParse(String s, out CoordinatePart cp) => FormatFinder_CoordPart.TryParse(s, out cp) ? true : false;
{
cp = null;
return FormatFinder_CoordPart.TryParse(s, out cp) ? true : false;
}
/// <summary> /// <summary>
/// Attempts to parse a string into a CoordinatePart. /// Attempts to parse a string into a CoordinatePart.
/// </summary> /// </summary>
@ -1833,9 +1753,7 @@ namespace CoordinateSharp
/// } /// }
/// </code> /// </code>
/// </example> /// </example>
public static Boolean TryParse(String s, CoordinateType t, out CoordinatePart cp) public static Boolean TryParse(String s, CoordinateType t, out CoordinatePart cp) {
{
cp = null;
//Comma at beginning parses to long //Comma at beginning parses to long
//Asterik forces lat //Asterik forces lat
s = t == CoordinateType.Long ? "," + s : "*" + s; 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;
using System.Diagnostics; using System.Diagnostics;
namespace CoordinateSharp
{ namespace CoordinateSharp {
/// <summary>
/// Contains distance values between two coordinates.
/// </summary>
[Serializable]
public class Distance {
/// <summary> /// <summary>
/// Contains distance values between two coordinates. /// Initializes a distance object using Haversine (Spherical Earth).
/// </summary> /// </summary>
[Serializable] /// <param name="c1">Coordinate 1</param>
public class Distance /// <param name="c2">Coordinate 2</param>
{ public Distance(Coordinate c1, Coordinate c2) => this.Haversine(c1, c2);
private double kilometers; /// <summary>
private double miles; /// Initializes a distance object using Haversine (Spherical Earth) or Vincenty (Elliptical Earth).
private double feet; /// </summary>
private double meters; /// <param name="c1">Coordinate 1</param>
private double bearing; /// <param name="c2">Coordinate 2</param>
private double nauticalMiles; /// <param name="shape">Shape of earth</param>
public Distance(Coordinate c1, Coordinate c2, Shape shape) {
/// <summary> if (shape == Shape.Sphere) {
/// Initializes a distance object using Haversine (Spherical Earth). this.Haversine(c1, c2);
/// </summary> } else {
/// <param name="c1">Coordinate 1</param> this.Vincenty(c1, c2);
/// <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; }
}
} }
/// <summary> /// <summary>
/// Distance measurement type /// Initializes distance object based on distance in KM
/// </summary> /// </summary>
public enum DistanceType /// <param name="km">Kilometers</param>
{ public Distance(Double km) {
/// <summary> this.Kilometers = km;
/// Distance in Meters this.Meters = km * 1000;
/// </summary> this.Feet = this.Meters * 3.28084;
Meters, this.Miles = this.Meters * 0.000621371;
/// <summary> this.NauticalMiles = this.Meters * 0.0005399565;
/// Distance in Kilometers this.Bearing = 0;//None specified
/// </summary> }
Kilometers, /// <summary>
/// <summary> /// Initializaes distance object based on specified distance and measurement type
/// Distance in Feet /// </summary>
/// </summary> /// <param name="distance">Distance</param>
Feet, /// <param name="type">Measurement type</param>
/// <summary>
/// Distance in Statute Miles public Distance(Double distance, DistanceType type) {
/// </summary> this.Bearing = 0;
Miles, switch (type) {
/// <summary> case DistanceType.Feet:
/// Distance in Nautical Miles this.Feet = distance;
/// </summary> this.Meters = this.Feet * 0.3048;
NauticalMiles 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] private void Haversine(Coordinate coord1, Coordinate coord2) {
internal class Distance_Assistant ////RADIANS
{ Double lat1 = coord1.Latitude.ToRadians();
/// <summary> Double long1 = coord1.Longitude.ToRadians();
/// Returns new geodetic coordinate in radians Double lat2 = coord2.Latitude.ToRadians();
/// </summary> Double long2 = coord2.Longitude.ToRadians();
/// <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 //Distance Calcs
if ((Math.Abs(Math.Cos(glat1)) < EPS) && !(Math.Abs(Math.Sin(faz)) < EPS)) Double R = 6371000; //6378137.0;//6371e3; //meters
{ Double latRad = coord2.Latitude.ToRadians() - coord1.Latitude.ToRadians();
Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location."); 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 //Get bearing
f = 1 / ellipse[1];//Flattening Double dLong = long2 - long1;
r = 1 - f; Double y = Math.Sin(dLong) * Math.Cos(lat2);
tu = r * Math.Tan(glat1); Double x = Math.Cos(lat1) * Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(dLong);
sf = Math.Sin(faz); Double brng = Math.Atan2(y, x) * (180 / Math.PI); //Convert bearing back to degrees.
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;
}
b = cu * cy * cf - su * sy; //if (brng < 0) { brng -= 180; brng = Math.Abs(brng); }
c = r * Math.Sqrt(sa * sa + b * b); brng = (brng + 360) % 360; //v2.1.1.1 NORMALIZE HEADING
d = su * cy + cu * sy * cf;
glat2 = ModM.ModLat(Math.Atan2(d, c)); this.Kilometers = dist / 1000;
c = cu * cy - su * sy * cf; this.Meters = dist;
x = Math.Atan2(sy * sf, c); this.Feet = dist * 3.28084;
c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0; this.Miles = dist * 0.000621371;
d = ((e * cy * c + cz) * sy * c + y) * sa; this.NauticalMiles = dist * 0.0005399565;
glon2 = ModM.ModLon(glon1 + x - (1.0 - c) * d * f); //Adjust for IDL this.Bearing = brng;
//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 };
}
} }
/// <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.Collections.Generic;
using System.Linq; using System.Linq;
namespace CoordinateSharp.Eclipse namespace CoordinateSharp.Eclipse {
{ internal class LunarData {
internal class LunarData static readonly Double[] LE1601 = new Double[] {
{
static double[] LE1601 = new double[] {
// 1601 1 18 // 1601 1 18
2305831.105839, 15.0, 117.3, 0.033, -0.978, 3, 2305831.105839, 15.0, 117.3, 0.033, -0.978, 3,
-1.13536, 0.98335, 0.26794, -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, -3.09161, -1.92390, -0.82385, 0.02344, 0.87082, 1.97089, 3.13800,
337.8589683, 0.48164, -1.510e-04, 337.8589683, 0.48164, -1.510e-04,
-9.4195702, 0.13945, 3.390e-04 }; -9.4195702, 0.13945, 3.390e-04 };
static double[] LE1701 = new double[] static readonly Double[] LE1701 = new Double[]
{ {
// 1701 2 22 // 1701 2 22
2342390.479120, 23.0, 8.2, 1.428, 0.463, 2, 2342390.479120, 23.0, 8.2, 1.428, 0.463, 2,
-14.82816, 1.02374, 0.27894, -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, -2.69377, -1.12653, 0.00000, -0.22214, 0.00000, 0.67926, 2.24840,
9.1688605, 0.46956, -7.000e-05, 9.1688605, 0.46956, -7.000e-05,
3.0790301, 0.25315, -2.000e-04 3.0790301, 0.25315, -2.000e-04
}; };
static double[] LE1801 = new double[] static readonly Double[] LE1801 = new Double[]
{ {
// 1801 3 30 // 1801 3 30
2378949.725057, 5.0, 13.0, 2.857, 1.840, 1, 2378949.725057, 5.0, 13.0, 2.857, 1.840, 1,
-6.52639, 0.96247, 0.26225, -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, -1.50705, 0.00000, 0.00000, 0.44149, 0.00000, 0.00000, 2.38825,
72.2570493, 0.64062, -1.660e-04, 72.2570493, 0.64062, -1.660e-04,
21.3680795, 0.01873, -1.222e-03 21.3680795, 0.01873, -1.222e-03
}; };
static double[] LE1901 = new double[] static readonly Double[] LE1901 = new Double[]
{ {
// 1901 5 3 // 1901 5 3
2415508.271269, 19.0, -0.9, 1.043, -0.033, 3, 2415508.271269, 19.0, -0.9, 1.043, -0.033, 3,
-14.26838, 0.90110, 0.24553, -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, -3.17609, -2.02249, -0.94259, -0.05589, 0.83086, 1.91081, 3.06398,
296.2552752, 0.52835, -1.150e-04, 296.2552752, 0.52835, -1.150e-04,
-21.2212594, 0.04170, 8.250e-04 -21.2212594, 0.04170, 8.250e-04
}; };
static double[] LE2001 = new double[] static readonly Double[] LE2001 = new Double[]
{ {
// 2001 1 9 // 2001 1 9
2451919.348374, 20.0, 64.1, 2.162, 1.189, 1, 2451919.348374, 20.0, 64.1, 2.162, 1.189, 1,
3.29475, 1.02253, 0.27861, 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, -2.37000, 0.00000, 0.00000, -0.25042, 0.00000, 0.00000, 1.86680,
329.8184696, 0.49978, -6.760e-04, 329.8184696, 0.49978, -6.760e-04,
-13.3626205, 0.22960, 3.990e-04 -13.3626205, 0.22960, 3.990e-04
}; };
static double[] LE2101 = new double[] static readonly Double[] LE2101 = new Double[]
{ {
// 2101 2 14 // 2101 2 14
2488478.618055, 3.0, 205.1, 2.218, 1.183, 1, 2488478.618055, 3.0, 205.1, 2.218, 1.183, 1,
12.59941, 0.95660, 0.26065, 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, -2.67458, -1.48697, 0.00000, -0.25460, 0.00000, 0.97583, 2.16508,
28.0294400, 0.59158, 9.000e-05, 28.0294400, 0.59158, 9.000e-05,
10.7019400, 0.15900, -6.160e-04 10.7019400, 0.15900, -6.160e-04
}; };
static double[] LE2201 = new double[] static readonly Double[] LE2201 = new Double[]
{ {
// 2201 3 20 // 2201 3 20
2525037.204912, 17.0, 444.3, 0.532, -0.560, 3, 2525037.204912, 17.0, 444.3, 0.532, -0.560, 3,
4.85759, 0.90005, 0.24524, 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, -2.66449, -1.75055, -0.80821, 0.00923, 0.82677, 1.76918, 2.68236,
63.0500500, 0.65278, 8.590e-04, 63.0500500, 0.65278, 8.590e-04,
21.0508309, 0.17085, -1.218e-03 21.0508309, 0.17085, -1.218e-03
}; };
static double[] LE2301 = new double[] static readonly Double[] LE2301 = new Double[]
{ {
// 2301 5 23 // 2301 5 23
2561625.186996, 16.0, 720.0, 1.809, 0.754, 2, 2561625.186996, 16.0, 720.0, 1.809, 0.754, 2,
8.04603, 0.91666, 0.24977, 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, -2.07354, -0.65576, 0.00000, 0.44265, 0.00000, 1.54366, 2.95874,
101.2753539, 0.59275, -1.730e-04, 101.2753539, 0.59275, -1.730e-04,
23.7726800, -0.09243, -1.170e-03 23.7726800, -0.09243, -1.170e-03
}; };
static double[] LE2401 = new double[] { static readonly Double[] LE2401 = new Double[] {
// 2401 6 26 // 2401 6 26
2598183.958214, 11.0, 1059.4, 2.107, 1.139, 1, 2598183.958214, 11.0, 1059.4, 2.107, 1.139, 1,
5.31800, 0.99489, 0.27108, 5.31800, 0.99489, 0.27108,
@ -13176,7 +13174,7 @@ namespace CoordinateSharp.Eclipse
348.3334732, 0.58130, -3.870e-04, 348.3334732, 0.58130, -3.870e-04,
-5.5431301, 0.18349, 2.190e-04 -5.5431301, 0.18349, 2.190e-04
}; };
static double[] LE2501 = new double[] { static readonly Double[] LE2501 = new Double[] {
// 2501 3 6 // 2501 3 6
2634595.801080, 7.0, 1461.0, 0.491, -0.599, 3, 2634595.801080, 7.0, 1461.0, 0.491, -0.599, 3,
17.93340, 0.90700, 0.24714, 17.93340, 0.90700, 0.24714,
@ -14541,70 +14539,49 @@ namespace CoordinateSharp.Eclipse
8.0835801, 0.28700, -3.300e-04 8.0835801, 0.28700, -3.300e-04
}; };
public static double[] LunarDateData(DateTime d) public static Double[] LunarDateData(DateTime d) {
{ //Return combined 100 year arrays so in order to grab Last and Next exlipLE.
//Return combined 100 year arrays so in order to grab Last and Next exlipLE. List<Double[]> data = new List<Double[]>()
List<double[]> data = new List<double[]>() {
{
LE1601, LE1701,LE1801, LE1901, LE2001, LE1601, LE1701,LE1801, LE1901, LE2001,
LE2101,LE2201, LE2301, LE2401, LE2501 LE2101,LE2201, LE2301, LE2401, LE2501
}; };
double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year. Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
int index = GetIndex(cent); //Gets index for calling data list. 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 //Determine data to LEnd if year is near beginning or end of databaLE
int halfCent = d.Year - (int)cent; Int32 halfCent = d.Year - (Int32)cent;
if (index == 0 || index == data.Count - 1) 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();
{
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[] 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.Collections.Generic;
using System.Linq; using System.Linq;
namespace CoordinateSharp.Eclipse namespace CoordinateSharp.Eclipse {
{ internal class SolarData {
internal class SolarData //ECLIPSE DATA FROM 1701-2400
{ static readonly Double[] SE1601 = new Double[]
//ECLIPSE DATA FROM 1701-2400 {
static double[] SE1601 = new double[]
{
// 1601 1 4 // 1601 1 4
2305817.017109, 12.0, -4.0, 4.0, 117.4, 117.4, 2305817.017109, 12.0, -4.0, 4.0, 117.4, 117.4,
-0.2585420, 0.5087563, -7.100e-06, -6.160e-06, -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.5346340, 0.0000437, -1.270e-05,
-0.0114460, 0.0000434, -1.270e-05, -0.0114460, 0.0000434, -1.270e-05,
0.0046524, 0.0046293 0.0046524, 0.0046293
}; };
static double[] SE1701 = new double[] static readonly Double[] SE1701 = new Double[]
{ {
// 1701 2 7 // 1701 2 7
2342375.461729, 23.0, -4.0, 4.0, 8.2, 8.2, 2342375.461729, 23.0, -4.0, 4.0, 8.2, 8.2,
-0.1836620, 0.4942406, -1.910e-05, -5.580e-06, -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.0039760, -0.0000963, -1.230e-05,
0.0046973, 0.0046739 0.0046973, 0.0046739
}; };
static double[] SE1801 = new double[] static readonly Double[] SE1801 = new Double[]
{ {
// 1801 3 14 // 1801 3 14
2378934.156652, 16.0, -4.0, 4.0, 13.0, 13.0, 2378934.156652, 16.0, -4.0, 4.0, 13.0, 13.0,
0.8100150, 0.4830337, -6.270e-05, -6.820e-06, 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.5676560, -0.0000826, -1.030e-05,
0.0214110, -0.0000822, -1.030e-05, 0.0214110, -0.0000822, -1.030e-05,
0.0047365, 0.0047129}; 0.0047365, 0.0047129};
static double[] SE1901 = new double[] static readonly Double[] SE1901 = new Double[]
{ {
// 1901 5 18 // 1901 5 18
2415522.731807, 6.0, -4.0, 4.0, -0.9, -0.9, 2415522.731807, 6.0, -4.0, 4.0, -0.9, -0.9,
0.3000790, 0.5746928, -4.400e-06, -9.600e-06, 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.5730920, 0.0000514, -1.000e-05,
0.0268200, 0.0000511, -1.000e-05, 0.0268200, 0.0000511, -1.000e-05,
0.0047553, 0.0047316 0.0047553, 0.0047316
}; };
static double[] SE2001 = new double[] static readonly Double[] SE2001 = new Double[]
{ {
// 2001 6 21 // 2001 6 21
2452082.003314, 12.0, -4.0, 4.0, 64.2, 64.2, 2452082.003314, 12.0, -4.0, 4.0, 64.2, 64.2,
0.0103400, 0.5653861, 2.920e-05, -8.860e-06, 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.5398730, -0.0001031, -1.210e-05,
-0.0062330, -0.0001026, -1.200e-05, -0.0062330, -0.0001026, -1.200e-05,
0.0046346, 0.0046116 0.0046346, 0.0046116
}; };
static double[] SE2101 = new double[] static readonly Double[] SE2101 = new Double[]
{ {
// 2101 2 28 // 2101 2 28
2488492.594741, 2.0, -4.0, 4.0, 205.2, 205.2, 2488492.594741, 2.0, -4.0, 4.0, 205.2, 205.2,
-0.5934920, 0.4746287, -1.290e-05, -6.230e-06, -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.5652510, -0.0000740, -1.020e-05,
0.0190180, -0.0000736, -1.010e-05, 0.0190180, -0.0000736, -1.010e-05,
0.0046769, 0.0046536 0.0046769, 0.0046536
}; };
static double[] SE2201 = new double[] static readonly Double[] SE2201 = new Double[]
{ {
// 2201 4 4 // 2201 4 4
2525051.763849, 6.0, -4.0, 4.0, 444.4, 444.4, 2525051.763849, 6.0, -4.0, 4.0, 444.4, 444.4,
-0.1405310, 0.5551418, 1.180e-05, -9.340e-06, -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.5747280, 0.0000236, -9.900e-06,
0.0284480, 0.0000235, -9.800e-06, 0.0284480, 0.0000235, -9.800e-06,
0.0047462, 0.0047226 0.0047462, 0.0047226
}; };
static double[] SE2301 = new double[] static readonly Double[] SE2301 = new Double[]
{ {
// 2301 5 9 // 2301 5 9
2561611.084014, 14.0, -4.0, 4.0, 719.9, 719.9, 2561611.084014, 14.0, -4.0, 4.0, 719.9, 719.9,
0.2556460, 0.5255338, 4.360e-05, -8.080e-06, 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.5389710, -0.0001064, -1.190e-05,
-0.0071310, -0.0001059, -1.190e-05, -0.0071310, -0.0001059, -1.190e-05,
0.0046006, 0.0045776 0.0046006, 0.0045776
}; };
static double[] SE2401 = new double[] { static readonly Double[] SE2401 = new Double[] {
// 2401 1 14 // 2401 1 14
2598021.427310, 22.0, -4.0, 4.0, 1057.8, 1057.8, 2598021.427310, 22.0, -4.0, 4.0, 1057.8, 1057.8,
-0.2870830, 0.5189539, -4.590e-05, -7.000e-06, -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.0163870, -0.0000706, -1.000e-05,
0.0046201, 0.0045971 0.0046201, 0.0045971
}; };
static double[] SE2501 = new double[] { static readonly Double[] SE2501 = new Double[] {
// 2501 2 19 // 2501 2 19
2634580.691215, 5.0, -4.0, 4.0, 1460.8, 1460.8, 2634580.691215, 5.0, -4.0, 4.0, 1460.8, 1460.8,
0.1813720, 0.5619451, -3.330e-05, -9.490e-06, 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.0248230, 0.0000365, -9.800e-06,
0.0046944, 0.0046710 }; 0.0046944, 0.0046710 };
public static double[] SolarDateData(DateTime d) public static Double[] SolarDateData(DateTime d) {
{ //Return combined 100 year arrays so in order to grab Last and Next exlipse.
//Return combined 100 year arrays so in order to grab Last and Next exlipse. List<Double[]> data = new List<Double[]>()
List<double[]> data = new List<double[]>() {
{
SE1601, SE1701, SE1801, SE1901, SE2001, SE1601, SE1701, SE1801, SE1901, SE2001,
SE2101, SE2201, SE2301, SE2401, SE2501 SE2101, SE2201, SE2301, SE2401, SE2501
}; };
double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year. Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
int index = GetIndex(cent); //Gets index for calling data list. 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 //Determine data to send if year is near beginning or end of database
int halfCent = d.Year - (int)cent; Int32 halfCent = d.Year - (Int32)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.
if (index == -1) { return new double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE 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();
//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 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;
using System.Linq; 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> /// <summary>
/// Geo Fence class. It helps to check if points/coordinates are inside a polygon, /// Prepare GeoFence with a list of points
/// Next to a polyline, and counting...
/// </summary> /// </summary>
public class GeoFence /// <param name="points">List of points</param>
{ public GeoFence(List<Point> points) => this._points = points;
#region Fields
private List<Point> _points = new List<Point>();
#endregion
/// <summary> /// <summary>
/// Prepare GeoFence with a list of points /// Prepare Geofence with a list of coordinates
/// </summary> /// </summary>
/// <param name="points">List of points</param> /// <param name="coordinates">List of coordinates</param>
public GeoFence(List<Point> points) public GeoFence(List<Coordinate> coordinates) {
{ foreach (Coordinate c in coordinates) {
_points = points; this._points.Add(new Point { Latitude = c.Latitude.ToDouble(), Longitude = c.Longitude.ToDouble() });
} }
/// <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;
}
} }
#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.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -34,3 +35,4 @@ using System.Runtime.InteropServices;
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.5.2")] [assembly: AssemblyVersion("1.1.5.2")]
[assembly: AssemblyFileVersion("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