Add netcore
This commit is contained in:
parent
2b0fbff159
commit
3843109a62
File diff suppressed because it is too large
Load Diff
@ -1,412 +1,321 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
//CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
|
||||
//Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used
|
||||
//to signify eclipses that had already started during rise and set times on the NASA calculator
|
||||
namespace CoordinateSharp {
|
||||
//CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
|
||||
//Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used
|
||||
//to signify eclipses that had already started during rise and set times on the NASA calculator
|
||||
|
||||
//SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC".
|
||||
//SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC".
|
||||
|
||||
//ELLIPSOID ADJUSTMENT
|
||||
//6378140.0 Ellipsoid is used in the NASA Calculator
|
||||
//WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions.
|
||||
//This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
|
||||
//ELLIPSOID ADJUSTMENT
|
||||
//6378140.0 Ellipsoid is used in the NASA Calculator
|
||||
//WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions.
|
||||
//This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
|
||||
|
||||
//CURRENT RANGE 1601-2600.
|
||||
internal class LunarEclipseCalc
|
||||
{
|
||||
public static List<List<string>> CalculateLunarEclipse(DateTime d, double latRad, double longRad)
|
||||
{
|
||||
return Calculate(d, latRad, longRad);
|
||||
}
|
||||
public static List<LunarEclipseDetails> CalculateLunarEclipse(DateTime d, double latRad, double longRad, double[] events)
|
||||
{
|
||||
List<List<string>> evs = Calculate(d, latRad, longRad, events);
|
||||
List<LunarEclipseDetails> deetsList = new List<LunarEclipseDetails>();
|
||||
foreach (List<string> ls in evs)
|
||||
{
|
||||
LunarEclipseDetails deets = new LunarEclipseDetails(ls);
|
||||
deetsList.Add(deets);
|
||||
}
|
||||
return deetsList;
|
||||
}
|
||||
public static List<List<string>> CalculateLunarEclipse(DateTime d, Coordinate coord)
|
||||
{
|
||||
return Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians());
|
||||
}
|
||||
|
||||
|
||||
// CALCULATE!
|
||||
private static List<List<string>> Calculate(DateTime d, double latRad, double longRad, double[] ev = null)
|
||||
{
|
||||
//DECLARE ARRAYS
|
||||
double[] obsvconst = new double[6];
|
||||
double[] mid = new double[41];
|
||||
double[] p1 = new double[41];
|
||||
double[] u1 = new double[41];
|
||||
double[] u2 = new double[41];
|
||||
double[] u3 = new double[41];
|
||||
double[] u4 = new double[41];
|
||||
double[] p4 = new double[41];
|
||||
|
||||
List<List<string>> events = new List<List<string>>();
|
||||
|
||||
double[] el;
|
||||
if (ev == null)
|
||||
{
|
||||
el = Eclipse.LunarData.LunarDateData(d);//Get 100 year solar data;
|
||||
}
|
||||
else
|
||||
{
|
||||
el = ev;
|
||||
}
|
||||
|
||||
events = new List<List<string>>();
|
||||
ReadData(latRad, longRad, obsvconst);
|
||||
|
||||
for (int i = 0; i < el.Length; i += 22)
|
||||
{
|
||||
if (el[5 + i] <= obsvconst[5])
|
||||
{
|
||||
List<string> values = new List<string>();
|
||||
obsvconst[4] = i;
|
||||
GetAll(el, obsvconst, mid, p1, u1, u2,u3,u4,p4);
|
||||
// Is there an event...
|
||||
if (mid[5] != 1)
|
||||
{
|
||||
|
||||
values.Add(GetDate(el, p1, obsvconst));
|
||||
|
||||
if (el[5 + i] == 1)
|
||||
{
|
||||
values.Add("T");
|
||||
}
|
||||
else if (el[5 + i] == 2)
|
||||
{
|
||||
values.Add("P");
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add("N");
|
||||
}
|
||||
|
||||
// Pen. Mag
|
||||
values.Add(el[3 + i].ToString());
|
||||
|
||||
// Umbral Mag
|
||||
values.Add(el[4 + i].ToString());
|
||||
|
||||
// P1
|
||||
values.Add(GetTime(el, p1, obsvconst));
|
||||
|
||||
// P1 alt
|
||||
values.Add(GetAlt(p1));
|
||||
|
||||
if (u1[5] == 1)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
// U1
|
||||
values.Add(GetTime(el, u1, obsvconst));
|
||||
|
||||
// U1 alt
|
||||
values.Add(GetAlt(u1));
|
||||
}
|
||||
if (u2[5] == 1)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
// U2
|
||||
values.Add(GetTime(el, u2, obsvconst));
|
||||
|
||||
// U2 alt
|
||||
values.Add(GetAlt(u2));
|
||||
}
|
||||
// mid
|
||||
|
||||
values.Add(GetTime(el, mid, obsvconst));
|
||||
|
||||
// mid alt
|
||||
|
||||
values.Add(GetAlt(mid));
|
||||
|
||||
if (u3[5] == 1)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
// u3
|
||||
values.Add(GetTime(el, u3, obsvconst));
|
||||
|
||||
// u3 alt
|
||||
values.Add(GetAlt(u3));
|
||||
}
|
||||
if (u4[5] == 1)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
// u4
|
||||
values.Add(GetTime(el, u4, obsvconst));
|
||||
|
||||
// u4 alt
|
||||
values.Add(GetAlt(u4));
|
||||
|
||||
}
|
||||
// P4
|
||||
values.Add(GetTime(el, p4, obsvconst));
|
||||
|
||||
// P4 alt
|
||||
values.Add(GetAlt(p4));
|
||||
events.Add(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
// Read the data that's in the form, and populate the obsvconst array
|
||||
private static void ReadData(double latRad, double longRad, double[] obsvconst)
|
||||
{
|
||||
|
||||
// Get the latitude
|
||||
obsvconst[0] = latRad;
|
||||
|
||||
// Get the longitude
|
||||
obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN.
|
||||
|
||||
// Get the altitude
|
||||
obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS.
|
||||
|
||||
// Get the time zone
|
||||
obsvconst[3] = 0; //GMT TIME
|
||||
|
||||
obsvconst[4] = 0; //INDEX
|
||||
|
||||
//SET MAX ECLIPSE TYPE
|
||||
obsvconst[5] = 4;//4 is ALL Eclipses
|
||||
|
||||
}
|
||||
// Populate the p1, u1, u2, mid, u3, u4 and p4 arrays
|
||||
private static void GetAll(double[] elements, double[] obsvconst, double[] mid, double[] p1, double[] u1, double[] u2, double[] u3, double[] u4, double[] p4)
|
||||
{
|
||||
int index = (int)obsvconst[4];
|
||||
p1[1] = elements[index + 9];
|
||||
PopulateCircumstances(elements, p1, obsvconst);
|
||||
mid[1] = elements[index + 12];
|
||||
PopulateCircumstances(elements, mid, obsvconst);
|
||||
p4[1] = elements[index + 15];
|
||||
PopulateCircumstances(elements, p4, obsvconst);
|
||||
if (elements[index + 5] < 3)
|
||||
{
|
||||
u1[1] = elements[index + 10];
|
||||
PopulateCircumstances(elements, u1, obsvconst);
|
||||
u4[1] = elements[index + 14];
|
||||
PopulateCircumstances(elements, u4, obsvconst);
|
||||
if (elements[index + 5] < 2)
|
||||
{
|
||||
u2[1] = elements[index + 11];
|
||||
u3[1] = elements[index + 13];
|
||||
PopulateCircumstances(elements, u2, obsvconst);
|
||||
PopulateCircumstances(elements, u3, obsvconst);
|
||||
}
|
||||
else
|
||||
{
|
||||
u2[5] = 1;
|
||||
u3[5] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u1[5] = 1;
|
||||
u2[5] = 1;
|
||||
u3[5] = 1;
|
||||
u4[5] = 1;
|
||||
}
|
||||
if ((p1[5] != 0) && (u1[5] != 0) && (u2[5] != 0) && (mid[5] != 0) && (u3[5] != 0) && (u4[5] != 0) && (p4[5] != 0))
|
||||
{
|
||||
mid[5] = 1;
|
||||
}
|
||||
}
|
||||
// Populate the circumstances array
|
||||
// entry condition - circumstances[1] must contain the correct value
|
||||
private static void PopulateCircumstances(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
double t, ra, dec, h;
|
||||
|
||||
int index = (int)obsvconst[4];
|
||||
t = circumstances[1];
|
||||
ra = elements[18 + index] * t + elements[17 + index];
|
||||
ra = ra * t + elements[16 + index];
|
||||
dec = elements[21 + index] * t + elements[20 + index];
|
||||
dec = dec * t + elements[19 + index];
|
||||
dec = dec * Math.PI / 180.0;
|
||||
circumstances[3] = dec;
|
||||
h = 15.0 * (elements[6 + index] + (t - elements[2 + index] / 3600.0) * 1.00273791) - ra;
|
||||
h = h * Math.PI / 180.0 - obsvconst[1];
|
||||
circumstances[2] = h;
|
||||
circumstances[4] = Math.Asin(Math.Sin(obsvconst[0]) * Math.Sin(dec) + Math.Cos(obsvconst[0]) * Math.Cos(dec) * Math.Cos(h));
|
||||
circumstances[4] -= Math.Asin(Math.Sin(elements[7 + index] * Math.PI / 180.0) * Math.Cos(circumstances[4]));
|
||||
if (circumstances[4] * 180.0 / Math.PI < elements[8 + index] - 0.5667)
|
||||
{
|
||||
circumstances[5] = 2;
|
||||
}
|
||||
else if (circumstances[4] < 0.0)
|
||||
{
|
||||
circumstances[4] = 0.0;
|
||||
circumstances[5] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
circumstances[5] = 0;
|
||||
}
|
||||
}
|
||||
// Get the date of an event
|
||||
private static string GetDate(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
string[] month = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };//Month string array
|
||||
double t, jd, a, b, c, d, e;
|
||||
string ans = "";
|
||||
int index = (int)obsvconst[4];
|
||||
// Calculate the JD for noon (TDT) the day before the day that contains T0
|
||||
jd = Math.Floor(elements[index] - (elements[1 + index] / 24.0));
|
||||
// Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0).
|
||||
t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
|
||||
|
||||
if (t < 0.0)
|
||||
{
|
||||
jd--;
|
||||
}
|
||||
if (t >= 24.0)
|
||||
{
|
||||
jd++;
|
||||
}
|
||||
if (jd >= 2299160.0)
|
||||
{
|
||||
a = Math.Floor((jd - 1867216.25) / 36524.25);
|
||||
a = jd + 1 + a - Math.Floor(a / 4.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = jd;
|
||||
}
|
||||
b = a + 1525.0;
|
||||
c = Math.Floor((b - 122.1) / 365.25);
|
||||
d = Math.Floor(365.25 * c);
|
||||
e = Math.Floor((b - d) / 30.6001);
|
||||
d = b - d - Math.Floor(30.6001 * e);
|
||||
if (e < 13.5)
|
||||
{
|
||||
e = e - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
e = e - 13;
|
||||
}
|
||||
double year;
|
||||
if (e > 2.5)
|
||||
{
|
||||
ans = c - 4716 + "-";
|
||||
year = c - 4716;
|
||||
}
|
||||
else
|
||||
{
|
||||
ans = c - 4715 + "-";
|
||||
year = c - 4715;
|
||||
}
|
||||
string m = month[(int)e - 1];
|
||||
ans += m+ "-";
|
||||
if (d < 10)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + d;
|
||||
//Leap Year Integrity Check
|
||||
|
||||
if (m == "Feb" && d == 29 && !DateTime.IsLeapYear((int)year))
|
||||
{
|
||||
ans = year.ToString() + "-Mar-01";
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
// Get the time of an event
|
||||
private static string GetTime(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
double t;
|
||||
string ans = "";
|
||||
|
||||
int index = (int)obsvconst[4];
|
||||
t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
|
||||
if (t < 0.0)
|
||||
{
|
||||
t = t + 24.0;
|
||||
}
|
||||
if (t >= 24.0)
|
||||
{
|
||||
t = t - 24.0;
|
||||
}
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + Math.Floor(t) + ":";
|
||||
t = (t * 60.0) - 60.0 * Math.Floor(t);
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + Math.Floor(t);
|
||||
if (circumstances[5] == 2)
|
||||
{
|
||||
return ans; //RETURNED IN ITAL DETERMINE WHY
|
||||
}
|
||||
else
|
||||
{
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
// Get the altitude
|
||||
private static string GetAlt(double[] circumstances)
|
||||
{
|
||||
double t;
|
||||
string ans = "";
|
||||
t = circumstances[4] * 180.0 / Math.PI;
|
||||
t = Math.Floor(t + 0.5);
|
||||
if (t < 0.0)
|
||||
{
|
||||
ans = "-";
|
||||
t = -t;
|
||||
}
|
||||
else
|
||||
{
|
||||
ans = "+";
|
||||
}
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + t;
|
||||
if (circumstances[5] == 2)
|
||||
{
|
||||
return ans; //returned in italics determine why
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
//CURRENT RANGE 1601-2600.
|
||||
internal class LunarEclipseCalc {
|
||||
public static List<List<String>> CalculateLunarEclipse(DateTime d, Double latRad, Double longRad) => Calculate(d, latRad, longRad);
|
||||
public static List<LunarEclipseDetails> CalculateLunarEclipse(DateTime d, Double latRad, Double longRad, Double[] events) {
|
||||
List<List<String>> evs = Calculate(d, latRad, longRad, events);
|
||||
List<LunarEclipseDetails> deetsList = new List<LunarEclipseDetails>();
|
||||
foreach (List<String> ls in evs) {
|
||||
LunarEclipseDetails deets = new LunarEclipseDetails(ls);
|
||||
deetsList.Add(deets);
|
||||
}
|
||||
return deetsList;
|
||||
}
|
||||
public static List<List<String>> CalculateLunarEclipse(DateTime d, Coordinate coord) => Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians());
|
||||
|
||||
|
||||
// CALCULATE!
|
||||
private static List<List<String>> Calculate(DateTime d, Double latRad, Double longRad, Double[] ev = null) {
|
||||
//DECLARE ARRAYS
|
||||
Double[] obsvconst = new Double[6];
|
||||
Double[] mid = new Double[41];
|
||||
Double[] p1 = new Double[41];
|
||||
Double[] u1 = new Double[41];
|
||||
Double[] u2 = new Double[41];
|
||||
Double[] u3 = new Double[41];
|
||||
Double[] u4 = new Double[41];
|
||||
Double[] p4 = new Double[41];
|
||||
|
||||
Double[] el = ev ?? Eclipse.LunarData.LunarDateData(d);
|
||||
List<List<String>> events = new List<List<String>>();
|
||||
ReadData(latRad, longRad, obsvconst);
|
||||
|
||||
for (Int32 i = 0; i < el.Length; i += 22) {
|
||||
if (el[5 + i] <= obsvconst[5]) {
|
||||
List<String> values = new List<String>();
|
||||
obsvconst[4] = i;
|
||||
GetAll(el, obsvconst, mid, p1, u1, u2, u3, u4, p4);
|
||||
// Is there an event...
|
||||
if (mid[5] != 1) {
|
||||
|
||||
values.Add(GetDate(el, p1, obsvconst));
|
||||
|
||||
if (el[5 + i] == 1) {
|
||||
values.Add("T");
|
||||
} else if (el[5 + i] == 2) {
|
||||
values.Add("P");
|
||||
} else {
|
||||
values.Add("N");
|
||||
}
|
||||
|
||||
// Pen. Mag
|
||||
values.Add(el[3 + i].ToString());
|
||||
|
||||
// Umbral Mag
|
||||
values.Add(el[4 + i].ToString());
|
||||
|
||||
// P1
|
||||
values.Add(GetTime(el, p1, obsvconst));
|
||||
|
||||
// P1 alt
|
||||
values.Add(GetAlt(p1));
|
||||
|
||||
if (u1[5] == 1) {
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
} else {
|
||||
// U1
|
||||
values.Add(GetTime(el, u1, obsvconst));
|
||||
|
||||
// U1 alt
|
||||
values.Add(GetAlt(u1));
|
||||
}
|
||||
if (u2[5] == 1) {
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
} else {
|
||||
// U2
|
||||
values.Add(GetTime(el, u2, obsvconst));
|
||||
|
||||
// U2 alt
|
||||
values.Add(GetAlt(u2));
|
||||
}
|
||||
// mid
|
||||
|
||||
values.Add(GetTime(el, mid, obsvconst));
|
||||
|
||||
// mid alt
|
||||
|
||||
values.Add(GetAlt(mid));
|
||||
|
||||
if (u3[5] == 1) {
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
} else {
|
||||
// u3
|
||||
values.Add(GetTime(el, u3, obsvconst));
|
||||
|
||||
// u3 alt
|
||||
values.Add(GetAlt(u3));
|
||||
}
|
||||
if (u4[5] == 1) {
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
} else {
|
||||
// u4
|
||||
values.Add(GetTime(el, u4, obsvconst));
|
||||
|
||||
// u4 alt
|
||||
values.Add(GetAlt(u4));
|
||||
|
||||
}
|
||||
// P4
|
||||
values.Add(GetTime(el, p4, obsvconst));
|
||||
|
||||
// P4 alt
|
||||
values.Add(GetAlt(p4));
|
||||
events.Add(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
// Read the data that's in the form, and populate the obsvconst array
|
||||
private static void ReadData(Double latRad, Double longRad, Double[] obsvconst) {
|
||||
|
||||
// Get the latitude
|
||||
obsvconst[0] = latRad;
|
||||
|
||||
// Get the longitude
|
||||
obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN.
|
||||
|
||||
// Get the altitude
|
||||
obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS.
|
||||
|
||||
// Get the time zone
|
||||
obsvconst[3] = 0; //GMT TIME
|
||||
|
||||
obsvconst[4] = 0; //INDEX
|
||||
|
||||
//SET MAX ECLIPSE TYPE
|
||||
obsvconst[5] = 4;//4 is ALL Eclipses
|
||||
|
||||
}
|
||||
// Populate the p1, u1, u2, mid, u3, u4 and p4 arrays
|
||||
private static void GetAll(Double[] elements, Double[] obsvconst, Double[] mid, Double[] p1, Double[] u1, Double[] u2, Double[] u3, Double[] u4, Double[] p4) {
|
||||
Int32 index = (Int32)obsvconst[4];
|
||||
p1[1] = elements[index + 9];
|
||||
PopulateCircumstances(elements, p1, obsvconst);
|
||||
mid[1] = elements[index + 12];
|
||||
PopulateCircumstances(elements, mid, obsvconst);
|
||||
p4[1] = elements[index + 15];
|
||||
PopulateCircumstances(elements, p4, obsvconst);
|
||||
if (elements[index + 5] < 3) {
|
||||
u1[1] = elements[index + 10];
|
||||
PopulateCircumstances(elements, u1, obsvconst);
|
||||
u4[1] = elements[index + 14];
|
||||
PopulateCircumstances(elements, u4, obsvconst);
|
||||
if (elements[index + 5] < 2) {
|
||||
u2[1] = elements[index + 11];
|
||||
u3[1] = elements[index + 13];
|
||||
PopulateCircumstances(elements, u2, obsvconst);
|
||||
PopulateCircumstances(elements, u3, obsvconst);
|
||||
} else {
|
||||
u2[5] = 1;
|
||||
u3[5] = 1;
|
||||
}
|
||||
} else {
|
||||
u1[5] = 1;
|
||||
u2[5] = 1;
|
||||
u3[5] = 1;
|
||||
u4[5] = 1;
|
||||
}
|
||||
if (p1[5] != 0 && u1[5] != 0 && u2[5] != 0 && mid[5] != 0 && u3[5] != 0 && u4[5] != 0 && p4[5] != 0) {
|
||||
mid[5] = 1;
|
||||
}
|
||||
}
|
||||
// Populate the circumstances array
|
||||
// entry condition - circumstances[1] must contain the correct value
|
||||
private static void PopulateCircumstances(Double[] elements, Double[] circumstances, Double[] obsvconst) {
|
||||
Double t, ra, dec, h;
|
||||
|
||||
Int32 index = (Int32)obsvconst[4];
|
||||
t = circumstances[1];
|
||||
ra = elements[18 + index] * t + elements[17 + index];
|
||||
ra = ra * t + elements[16 + index];
|
||||
dec = elements[21 + index] * t + elements[20 + index];
|
||||
dec = dec * t + elements[19 + index];
|
||||
dec = dec * Math.PI / 180.0;
|
||||
circumstances[3] = dec;
|
||||
h = 15.0 * (elements[6 + index] + (t - elements[2 + index] / 3600.0) * 1.00273791) - ra;
|
||||
h = h * Math.PI / 180.0 - obsvconst[1];
|
||||
circumstances[2] = h;
|
||||
circumstances[4] = Math.Asin(Math.Sin(obsvconst[0]) * Math.Sin(dec) + Math.Cos(obsvconst[0]) * Math.Cos(dec) * Math.Cos(h));
|
||||
circumstances[4] -= Math.Asin(Math.Sin(elements[7 + index] * Math.PI / 180.0) * Math.Cos(circumstances[4]));
|
||||
if (circumstances[4] * 180.0 / Math.PI < elements[8 + index] - 0.5667) {
|
||||
circumstances[5] = 2;
|
||||
} else if (circumstances[4] < 0.0) {
|
||||
circumstances[4] = 0.0;
|
||||
circumstances[5] = 0;
|
||||
} else {
|
||||
circumstances[5] = 0;
|
||||
}
|
||||
}
|
||||
// Get the date of an event
|
||||
private static String GetDate(Double[] elements, Double[] circumstances, Double[] obsvconst) {
|
||||
String[] month = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };//Month string array
|
||||
Double t, jd, a, b, c, d, e;
|
||||
Int32 index = (Int32)obsvconst[4];
|
||||
// Calculate the JD for noon (TDT) the day before the day that contains T0
|
||||
jd = Math.Floor(elements[index] - elements[1 + index] / 24.0);
|
||||
// Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0).
|
||||
t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
|
||||
|
||||
if (t < 0.0) {
|
||||
jd--;
|
||||
}
|
||||
if (t >= 24.0) {
|
||||
jd++;
|
||||
}
|
||||
if (jd >= 2299160.0) {
|
||||
a = Math.Floor((jd - 1867216.25) / 36524.25);
|
||||
a = jd + 1 + a - Math.Floor(a / 4.0);
|
||||
} else {
|
||||
a = jd;
|
||||
}
|
||||
b = a + 1525.0;
|
||||
c = Math.Floor((b - 122.1) / 365.25);
|
||||
d = Math.Floor(365.25 * c);
|
||||
e = Math.Floor((b - d) / 30.6001);
|
||||
d = b - d - Math.Floor(30.6001 * e);
|
||||
e = e < 13.5 ? e - 1 : e - 13;
|
||||
Double year;
|
||||
String ans;
|
||||
if (e > 2.5) {
|
||||
ans = c - 4716 + "-";
|
||||
year = c - 4716;
|
||||
} else {
|
||||
ans = c - 4715 + "-";
|
||||
year = c - 4715;
|
||||
}
|
||||
String m = month[(Int32)e - 1];
|
||||
ans += m + "-";
|
||||
if (d < 10) {
|
||||
ans += "0";
|
||||
}
|
||||
ans += d;
|
||||
//Leap Year Integrity Check
|
||||
|
||||
if (m == "Feb" && d == 29 && !DateTime.IsLeapYear((Int32)year)) {
|
||||
ans = year.ToString() + "-Mar-01";
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
// Get the time of an event
|
||||
private static String GetTime(Double[] elements, Double[] circumstances, Double[] obsvconst) {
|
||||
Double t;
|
||||
String ans = "";
|
||||
|
||||
Int32 index = (Int32)obsvconst[4];
|
||||
t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
|
||||
if (t < 0.0) {
|
||||
t += 24.0;
|
||||
}
|
||||
if (t >= 24.0) {
|
||||
t -= 24.0;
|
||||
}
|
||||
if (t < 10.0) {
|
||||
ans += "0";
|
||||
}
|
||||
ans = ans + Math.Floor(t) + ":";
|
||||
t = t * 60.0 - 60.0 * Math.Floor(t);
|
||||
if (t < 10.0) {
|
||||
ans += "0";
|
||||
}
|
||||
ans += Math.Floor(t);
|
||||
if (circumstances[5] == 2) {
|
||||
return ans; //RETURNED IN ITAL DETERMINE WHY
|
||||
} else {
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
// Get the altitude
|
||||
private static String GetAlt(Double[] circumstances) {
|
||||
Double t;
|
||||
t = circumstances[4] * 180.0 / Math.PI;
|
||||
t = Math.Floor(t + 0.5);
|
||||
String ans;
|
||||
if (t < 0.0) {
|
||||
ans = "-";
|
||||
t = -t;
|
||||
} else {
|
||||
ans = "+";
|
||||
}
|
||||
if (t < 10.0) {
|
||||
ans += "0";
|
||||
}
|
||||
ans += t;
|
||||
if (circumstances[5] == 2) {
|
||||
return ans; //returned in italics determine why
|
||||
|
||||
} else {
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
internal partial class MeeusTables
|
||||
namespace CoordinateSharp {
|
||||
internal partial class MeeusTables {
|
||||
//Ch 47
|
||||
private static readonly Double[] Table47A_Arguments = new Double[]
|
||||
{
|
||||
//Ch 47
|
||||
private static double[] Table47A_Arguments = new double[]
|
||||
{
|
||||
0,0,1,0,
|
||||
2,0,-1,0,
|
||||
2,0,0,0,
|
||||
@ -71,9 +66,9 @@ namespace CoordinateSharp
|
||||
1,1,-1,0,
|
||||
2,0,3,0,
|
||||
2,0,-1,-2
|
||||
};
|
||||
private static double[] Table47B_Arguments = new double[]
|
||||
{
|
||||
};
|
||||
private static readonly Double[] Table47B_Arguments = new Double[]
|
||||
{
|
||||
0,0,0,1,
|
||||
0,0,1,1,
|
||||
0,0,1,-1,
|
||||
@ -135,9 +130,9 @@ namespace CoordinateSharp
|
||||
1,0,-1,-1,
|
||||
4,-1,0,-1,
|
||||
2,-2,0,1,
|
||||
};
|
||||
private static double[] Table47A_El_Er = new double[]
|
||||
{
|
||||
};
|
||||
private static readonly Double[] Table47A_El_Er = new Double[]
|
||||
{
|
||||
//El
|
||||
6288774, 1274027,658314,213618,-185116,-114332,58793,57066,53322,45758,
|
||||
-40923,-34720,-30383,15327,-12528,10980,10675,10034,8548,-7888,-6766,-5163,
|
||||
@ -150,72 +145,58 @@ namespace CoordinateSharp
|
||||
-12831,-10445,-11650,14403,-7003,0,10056,6322,-9884,5751,0,-4950,4130,0,-3958,0,3258,
|
||||
2616,-1897,-2117,2354,0,0,-1423,-1117,-1571,-1739,0,-4421,0,0,0,0,1165,0,0,8752
|
||||
|
||||
};
|
||||
private static double[] Table47B_Eb = new double[]
|
||||
{
|
||||
};
|
||||
private static readonly Double[] Table47B_Eb = new Double[]
|
||||
{
|
||||
5128122,280602,277693,173237,55413,46271,32573,17198,9266,8822,
|
||||
8216,4324,4200,-3359,2463,2211,2065,-1870,1828,-1794,-1749,-1565,-1491,
|
||||
-1475,-1410,-1344,-1335,1107,1021,833,
|
||||
|
||||
777,671,607,596,491,-451,439,422,421,-366,-351,331,315,302,-283,-229,
|
||||
223,223,-220,-220,-185,181,-177,176,166,-164,132,-119,115,107
|
||||
};
|
||||
private static double Get_Table47A_Values(double[] values, int l, double t, bool sine)
|
||||
{
|
||||
//sine true returns El
|
||||
//sine false return Er
|
||||
//Er values start at 60 in the Table47A_El_Er array.
|
||||
};
|
||||
private static Double Get_Table47A_Values(Double[] values, Int32 l, Double t, Boolean sine) {
|
||||
//sine true returns El
|
||||
//sine false return Er
|
||||
//Er values start at 60 in the Table47A_El_Er array.
|
||||
|
||||
int nl = l * 4;
|
||||
Int32 nl = l * 4;
|
||||
|
||||
if (sine)
|
||||
{
|
||||
double e = 1;
|
||||
if (sine) {
|
||||
Double e = 1;
|
||||
|
||||
if (Table47A_Arguments[nl + 1] != 0)
|
||||
{
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
if (Table47A_Arguments[nl + 1] != 0) {
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
|
||||
if (Math.Abs(Table47A_Arguments[nl + 1]) == 2)
|
||||
{
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
return (Table47A_El_Er[l] * e) * Math.Sin(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] +
|
||||
Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
double e = 1;
|
||||
if (Table47A_Arguments[nl + 1] != 0)
|
||||
{
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
|
||||
if (Math.Abs(Table47A_Arguments[nl + 1]) == 2)
|
||||
{
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
return (Table47A_El_Er[l + 60] * e) * Math.Cos(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] +
|
||||
Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
|
||||
}
|
||||
if (Math.Abs(Table47A_Arguments[nl + 1]) == 2) {
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
private static double Get_Table47B_Values(double[] values, int l, double t)
|
||||
{
|
||||
int nl = l * 4;
|
||||
double e = 1;
|
||||
return Table47A_El_Er[l] * e * Math.Sin(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] + Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
|
||||
} else {
|
||||
Double e = 1;
|
||||
if (Table47A_Arguments[nl + 1] != 0) {
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
|
||||
if (Table47B_Arguments[nl + 1] != 0)
|
||||
{
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
|
||||
if (Math.Abs(Table47B_Arguments[nl + 1]) == 2)
|
||||
{
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
return (Table47B_Eb[l] * e) * Math.Sin(Table47B_Arguments[nl] * values[0] + Table47B_Arguments[nl + 1] * values[1] +
|
||||
Table47B_Arguments[nl + 2] * values[2] + Table47B_Arguments[nl + 3] * values[3]);
|
||||
if (Math.Abs(Table47A_Arguments[nl + 1]) == 2) {
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
return Table47A_El_Er[l + 60] * e * Math.Cos(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] + Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
|
||||
}
|
||||
}
|
||||
private static Double Get_Table47B_Values(Double[] values, Int32 l, Double t) {
|
||||
Int32 nl = l * 4;
|
||||
Double e = 1;
|
||||
|
||||
if (Table47B_Arguments[nl + 1] != 0) {
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
|
||||
if (Math.Abs(Table47B_Arguments[nl + 1]) == 2) {
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
return Table47B_Eb[l] * e * Math.Sin(Table47B_Arguments[nl] * values[0] + Table47B_Arguments[nl + 1] * values[1] + Table47B_Arguments[nl + 2] * values[2] + Table47B_Arguments[nl + 3] * values[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,374 +1,318 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
internal class SunCalc
|
||||
{
|
||||
public static void CalculateSunTime(double lat, double longi, DateTime date, Celestial c,double offset = 0)
|
||||
{
|
||||
if (date.Year == 0001) { return; } //Return if date vaue hasn't been established.
|
||||
DateTime actualDate = new DateTime(date.Year,date.Month,date.Day,0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
////Sun Time Calculations
|
||||
|
||||
//Get Julian
|
||||
double lw = rad * -longi;
|
||||
double phi = rad * lat;
|
||||
namespace CoordinateSharp {
|
||||
internal class SunCalc {
|
||||
public static void CalculateSunTime(Double lat, Double longi, DateTime date, Celestial c, Double _ = 0) {
|
||||
if (date.Year == 0001) { return; } //Return if date vaue hasn't been established.
|
||||
DateTime actualDate = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
//Rise Set
|
||||
DateTime?[] evDate = Get_Event_Time(lw, phi, -.8333, actualDate);
|
||||
c.sunRise = evDate[0];
|
||||
c.sunSet = evDate[1];
|
||||
|
||||
c.sunCondition = CelestialStatus.RiseAndSet;
|
||||
//Azimuth and Altitude
|
||||
CalculateSunAngle(date, longi, lat, c);
|
||||
// neither sunrise nor sunset
|
||||
if ((!c.SunRise.HasValue) && (!c.SunSet.HasValue))
|
||||
{
|
||||
if (c.SunAltitude < 0)
|
||||
{
|
||||
c.sunCondition = CelestialStatus.DownAllDay;
|
||||
}
|
||||
else
|
||||
{
|
||||
c.sunCondition = CelestialStatus.UpAllDay;
|
||||
}
|
||||
}
|
||||
// sunrise or sunset
|
||||
else
|
||||
{
|
||||
if (!c.SunRise.HasValue)
|
||||
{
|
||||
// No sunrise this date
|
||||
c.sunCondition = CelestialStatus.NoRise;
|
||||
////Sun Time Calculations
|
||||
|
||||
}
|
||||
else if (!c.SunSet.HasValue)
|
||||
{
|
||||
// No sunset this date
|
||||
c.sunCondition = CelestialStatus.NoSet;
|
||||
}
|
||||
}
|
||||
//Additional Times
|
||||
c.additionalSolarTimes = new AdditionalSolarTimes();
|
||||
//Dusk and Dawn
|
||||
//Civil
|
||||
evDate = Get_Event_Time(lw, phi, -6, actualDate);
|
||||
c.AdditionalSolarTimes.CivilDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.CivilDusk = evDate[1];
|
||||
//Get Julian
|
||||
Double lw = rad * -longi;
|
||||
Double phi = rad * lat;
|
||||
|
||||
//Rise Set
|
||||
DateTime?[] evDate = Get_Event_Time(lw, phi, -.8333, actualDate);
|
||||
c.sunRise = evDate[0];
|
||||
c.sunSet = evDate[1];
|
||||
|
||||
//Nautical
|
||||
evDate = Get_Event_Time(lw, phi, -12, actualDate);
|
||||
c.AdditionalSolarTimes.NauticalDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.NauticalDusk = evDate[1];
|
||||
c.sunCondition = CelestialStatus.RiseAndSet;
|
||||
//Azimuth and Altitude
|
||||
CalculateSunAngle(date, longi, lat, c);
|
||||
// neither sunrise nor sunset
|
||||
if (!c.SunRise.HasValue && !c.SunSet.HasValue) {
|
||||
c.sunCondition = c.SunAltitude < 0 ? CelestialStatus.DownAllDay : CelestialStatus.UpAllDay;
|
||||
}
|
||||
// sunrise or sunset
|
||||
else {
|
||||
if (!c.SunRise.HasValue) {
|
||||
// No sunrise this date
|
||||
c.sunCondition = CelestialStatus.NoRise;
|
||||
|
||||
//Astronomical
|
||||
evDate = Get_Event_Time(lw, phi, -18, actualDate);
|
||||
|
||||
c.AdditionalSolarTimes.AstronomicalDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.AstronomicalDusk = evDate[1];
|
||||
|
||||
//BottomDisc
|
||||
evDate = Get_Event_Time(lw, phi, -.2998, actualDate);
|
||||
c.AdditionalSolarTimes.SunriseBottomDisc = evDate[0];
|
||||
c.AdditionalSolarTimes.SunsetBottomDisc = evDate[1];
|
||||
|
||||
CalculateSolarEclipse(date, lat, longi, c);
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets time of event based on specified degree below horizon
|
||||
/// </summary>
|
||||
/// <param name="lw">Observer Longitude in radians</param>
|
||||
/// <param name="phi">Observer Latitude in radians</param>
|
||||
/// <param name="h">Angle in Degrees</param>
|
||||
/// <param name="date">Date of Event</param>
|
||||
/// <returns>DateTime?[]{rise, set}</returns>
|
||||
private static DateTime?[] Get_Event_Time(double lw, double phi, double h,DateTime date)
|
||||
{
|
||||
//Create arrays. Index 0 = Day -1, 1 = Day, 2 = Day + 1;
|
||||
//These will be used to find exact day event occurs for comparison
|
||||
DateTime?[] sets = new DateTime?[] { null, null, null, null, null };
|
||||
DateTime?[] rises = new DateTime?[] { null, null, null,null, null };
|
||||
|
||||
//Iterate starting with day -1;
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
double d = JulianConversions.GetJulian(date.AddDays(x-2)) - j2000 + .5; //LESS PRECISE JULIAN NEEDED
|
||||
|
||||
double n = julianCycle(d, lw);
|
||||
double ds = approxTransit(0, lw, n);
|
||||
|
||||
double M = solarMeanAnomaly(ds);
|
||||
double L = eclipticLongitude(M);
|
||||
|
||||
double dec = declination(L, 0);
|
||||
|
||||
double Jnoon = solarTransitJ(ds, M, L);
|
||||
|
||||
double Jset;
|
||||
double Jrise;
|
||||
|
||||
|
||||
DateTime? solarNoon = JulianConversions.GetDate_FromJulian(Jnoon);
|
||||
DateTime? nadir = JulianConversions.GetDate_FromJulian(Jnoon - 0.5);
|
||||
|
||||
//Rise Set
|
||||
Jset = GetTime(h * rad, lw, phi, dec, n, M, L);
|
||||
Jrise = Jnoon - (Jset - Jnoon);
|
||||
|
||||
DateTime? rise = JulianConversions.GetDate_FromJulian(Jrise);
|
||||
DateTime? set = JulianConversions.GetDate_FromJulian(Jset);
|
||||
|
||||
rises[x] = rise;
|
||||
sets[x] = set;
|
||||
}
|
||||
|
||||
//Compare and send
|
||||
DateTime? tRise = null;
|
||||
for(int x=0;x<5;x++)
|
||||
{
|
||||
if(rises[x].HasValue)
|
||||
{
|
||||
if(rises[x].Value.Day == date.Day)
|
||||
{
|
||||
tRise = rises[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
DateTime? tSet = null;
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
if (sets[x].HasValue)
|
||||
{
|
||||
if (sets[x].Value.Day == date.Day)
|
||||
{
|
||||
tSet = sets[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new DateTime?[] { tRise, tSet };
|
||||
} else if (!c.SunSet.HasValue) {
|
||||
// No sunset this date
|
||||
c.sunCondition = CelestialStatus.NoSet;
|
||||
}
|
||||
}
|
||||
//Additional Times
|
||||
c.additionalSolarTimes = new AdditionalSolarTimes();
|
||||
//Dusk and Dawn
|
||||
//Civil
|
||||
evDate = Get_Event_Time(lw, phi, -6, actualDate);
|
||||
c.AdditionalSolarTimes.CivilDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.CivilDusk = evDate[1];
|
||||
|
||||
public static void CalculateZodiacSign(DateTime date, Celestial c)
|
||||
{
|
||||
//Aquarius (January 20 to February 18)
|
||||
//Pisces (February 19 to March 20)
|
||||
//Aries (March 21-April 19)
|
||||
//Taurus (April 20-May 20)
|
||||
//Gemini (May 21-June 20)
|
||||
//Cancer (June 21-July 22)
|
||||
//Leo (July 23-August 22)
|
||||
//Virgo (August 23-September 22)
|
||||
//Libra (September 23-October 22)
|
||||
//Scorpio (October 23-November 21)
|
||||
//Sagittarius (November 22-December 21)
|
||||
//Capricorn (December 22-January 19)
|
||||
if (date >= new DateTime(date.Year, 1, 1) && date <= new DateTime(date.Year, 1, 19, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Capricorn";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 1, 20) && date <= new DateTime(date.Year, 2, 18, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Aquarius";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 2, 19) && date <= new DateTime(date.Year, 3, 20, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Pisces";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 3, 21) && date <= new DateTime(date.Year, 4, 19, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Aries";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 4, 20) && date <= new DateTime(date.Year, 5, 20, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Taurus";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 5, 21) && date <= new DateTime(date.Year, 6, 20,23,59,59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Gemini";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 6, 21) && date <= new DateTime(date.Year, 7, 22, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Cancer";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 7, 23) && date <= new DateTime(date.Year, 8, 22, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Leo";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 8, 23) && date <= new DateTime(date.Year, 9, 22, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Virgo";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 10, 22, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Libra";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 11, 21, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Scorpio";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 11, 21) && date <= new DateTime(date.Year, 12, 21, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Sagittarius";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 12, 22) && date <= new DateTime(date.Year, 12, 31, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Capricorn";
|
||||
return;
|
||||
}
|
||||
}
|
||||
public static void CalculateSolarEclipse(DateTime date, double lat, double longi, Celestial c)
|
||||
{
|
||||
//Convert to Radian
|
||||
double latR = lat * Math.PI / 180;
|
||||
double longR = longi * Math.PI / 180;
|
||||
List<List<string>> se = SolarEclipseCalc.CalculateSolarEclipse(date, latR, longR);
|
||||
//RETURN FIRST AND LAST
|
||||
if (se.Count == 0) { return; }
|
||||
//FIND LAST AND NEXT ECLIPSE
|
||||
int lastE = -1;
|
||||
int nextE = -1;
|
||||
int currentE = 0;
|
||||
DateTime lastDate = new DateTime();
|
||||
DateTime nextDate = new DateTime(3300, 1, 1);
|
||||
//Iterate to get last and next eclipse
|
||||
foreach(List<string> values in se)
|
||||
{
|
||||
DateTime ld = DateTime.ParseExact(values[0], "yyyy-MMM-dd", System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
if (ld < date && ld>lastDate) { lastDate = ld;lastE = currentE; }
|
||||
if(ld>= date && ld < nextDate) { nextDate = ld;nextE = currentE; }
|
||||
currentE++;
|
||||
}
|
||||
//SET ECLIPSE DATA
|
||||
if (lastE >= 0)
|
||||
{
|
||||
c.SolarEclipse.LastEclipse = new SolarEclipseDetails(se[lastE]);
|
||||
}
|
||||
if (nextE >= 0)
|
||||
{
|
||||
c.SolarEclipse.NextEclipse = new SolarEclipseDetails(se[nextE]);
|
||||
}
|
||||
}
|
||||
|
||||
#region Private Suntime Members
|
||||
private static readonly double dayMS = 1000 * 60 * 60 * 24, j1970 = 2440588, j2000 = 2451545;
|
||||
private static readonly double rad = Math.PI / 180;
|
||||
//Nautical
|
||||
evDate = Get_Event_Time(lw, phi, -12, actualDate);
|
||||
c.AdditionalSolarTimes.NauticalDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.NauticalDusk = evDate[1];
|
||||
|
||||
private static double LocalSiderealTimeForTimeZone(double lon, double jd, double z)
|
||||
{
|
||||
double s = 24110.5 + 8640184.812999999 * jd / 36525 + 86636.6 * z + 86400 * lon;
|
||||
s = s / 86400;
|
||||
s = s - Math.Truncate(s);
|
||||
double lst = s * 360 *rad;
|
||||
|
||||
return lst;
|
||||
}
|
||||
private static double SideRealTime(double d, double lw)
|
||||
{
|
||||
double s = rad * (280.16 + 360.9856235 * d) - lw;
|
||||
return s;
|
||||
}
|
||||
private static double solarTransitJ(double ds, double M, double L)
|
||||
{
|
||||
return j2000 + ds + 0.0053 * Math.Sin(M) - 0.0069 * Math.Sin(2 * L);
|
||||
}
|
||||
|
||||
//CH15
|
||||
//Formula 15.1
|
||||
//Returns Approximate Time
|
||||
private static double hourAngle(double h, double phi, double d)
|
||||
{
|
||||
//NUMBER RETURNING > and < 1 NaN;
|
||||
double d1 = Math.Sin(h) - Math.Sin(phi) * Math.Sin(d);
|
||||
double d2 = Math.Cos(phi) * Math.Cos(d);
|
||||
double d3 = (d1 / d2);
|
||||
|
||||
return Math.Acos(d3);
|
||||
}
|
||||
private static double approxTransit(double Ht, double lw, double n)
|
||||
{
|
||||
return 0.0009 + (Ht + lw) / (2 * Math.PI) + n;
|
||||
}
|
||||
|
||||
private static double julianCycle(double d, double lw) { return Math.Round(d - 0.0009 - lw / (2 * Math.PI)); }
|
||||
//Astronomical
|
||||
evDate = Get_Event_Time(lw, phi, -18, actualDate);
|
||||
|
||||
//Returns Time of specified event based on suns angle
|
||||
private static double GetTime(double h, double lw, double phi, double dec, double n,double M, double L)
|
||||
{
|
||||
double approxTime = hourAngle(h, phi, dec); //Ch15 Formula 15.1
|
||||
c.AdditionalSolarTimes.AstronomicalDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.AstronomicalDusk = evDate[1];
|
||||
|
||||
double a = approxTransit(approxTime, lw, n);
|
||||
double st = solarTransitJ(a, M, L);
|
||||
|
||||
return st;
|
||||
}
|
||||
private static double declination(double l, double b)
|
||||
{
|
||||
double e = (Math.PI/180) * 23.4392911; // obliquity of the Earth
|
||||
|
||||
return Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));
|
||||
}
|
||||
|
||||
private static void CalculateSunAngle(DateTime date, double longi, double lat, Celestial c)
|
||||
{
|
||||
TimeSpan ts = date - new DateTime(1970, 1, 1,0,0,0, DateTimeKind.Utc);
|
||||
double dms = (ts.TotalMilliseconds / dayMS -.5 + j1970)-j2000;
|
||||
|
||||
double lw = rad * -longi;
|
||||
double phi = rad * lat;
|
||||
double e = rad * 23.4397;
|
||||
|
||||
double[] sc = sunCoords(dms);
|
||||
|
||||
double H = SideRealTime(dms, lw) - sc[1];
|
||||
//BottomDisc
|
||||
evDate = Get_Event_Time(lw, phi, -.2998, actualDate);
|
||||
c.AdditionalSolarTimes.SunriseBottomDisc = evDate[0];
|
||||
c.AdditionalSolarTimes.SunsetBottomDisc = evDate[1];
|
||||
|
||||
c.sunAzimuth = Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(sc[0]) * Math.Cos(phi)) * 180 / Math.PI + 180;
|
||||
c.sunAltitude = Math.Asin(Math.Sin(phi) * Math.Sin(sc[0]) + Math.Cos(phi) * Math.Cos(sc[0]) * Math.Cos(H)) * 180 / Math.PI;
|
||||
}
|
||||
CalculateSolarEclipse(date, lat, longi, c);
|
||||
|
||||
private static double solarMeanAnomaly(double d)
|
||||
{
|
||||
return rad * (357.5291 + 0.98560028 * d);
|
||||
}
|
||||
|
||||
private static double eclipticLongitude(double m)
|
||||
{
|
||||
double c = rad * (1.9148 * Math.Sin(m) + 0.02 * Math.Sin(2 * m) + 0.0003 * Math.Sin(3 * m)); // equation of center
|
||||
double p = rad * 102.9372; // perihelion of the Earth
|
||||
|
||||
return m + c + p + Math.PI;
|
||||
}
|
||||
private static double[] sunCoords(double d)
|
||||
{
|
||||
|
||||
double m = solarMeanAnomaly(d);
|
||||
double l = eclipticLongitude(m);
|
||||
double[] sc = new double[2];
|
||||
double b = 0;
|
||||
double e = rad * 23.4397; // obliquity of the Earth
|
||||
sc[0] = Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l)); //declination
|
||||
sc[1] = Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l)); //rightAscension
|
||||
return sc;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets time of event based on specified degree below horizon
|
||||
/// </summary>
|
||||
/// <param name="lw">Observer Longitude in radians</param>
|
||||
/// <param name="phi">Observer Latitude in radians</param>
|
||||
/// <param name="h">Angle in Degrees</param>
|
||||
/// <param name="date">Date of Event</param>
|
||||
/// <returns>DateTime?[]{rise, set}</returns>
|
||||
private static DateTime?[] Get_Event_Time(Double lw, Double phi, Double h, DateTime date) {
|
||||
//Create arrays. Index 0 = Day -1, 1 = Day, 2 = Day + 1;
|
||||
//These will be used to find exact day event occurs for comparison
|
||||
DateTime?[] sets = new DateTime?[] { null, null, null, null, null };
|
||||
DateTime?[] rises = new DateTime?[] { null, null, null, null, null };
|
||||
|
||||
//Iterate starting with day -1;
|
||||
for (Int32 x = 0; x < 5; x++) {
|
||||
Double d = JulianConversions.GetJulian(date.AddDays(x - 2)) - j2000 + .5; //LESS PRECISE JULIAN NEEDED
|
||||
|
||||
Double n = JulianCycle(d, lw);
|
||||
Double ds = ApproxTransit(0, lw, n);
|
||||
|
||||
Double M = SolarMeanAnomaly(ds);
|
||||
Double L = EclipticLongitude(M);
|
||||
|
||||
Double dec = Declination(L, 0);
|
||||
|
||||
Double Jnoon = SolarTransitJ(ds, M, L);
|
||||
|
||||
Double Jset;
|
||||
Double Jrise;
|
||||
|
||||
|
||||
//DateTime? solarNoon = JulianConversions.GetDate_FromJulian(Jnoon);
|
||||
//DateTime? nadir = JulianConversions.GetDate_FromJulian(Jnoon - 0.5);
|
||||
|
||||
//Rise Set
|
||||
Jset = GetTime(h * rad, lw, phi, dec, n, M, L);
|
||||
Jrise = Jnoon - (Jset - Jnoon);
|
||||
|
||||
DateTime? rise = JulianConversions.GetDate_FromJulian(Jrise);
|
||||
DateTime? set = JulianConversions.GetDate_FromJulian(Jset);
|
||||
|
||||
rises[x] = rise;
|
||||
sets[x] = set;
|
||||
}
|
||||
|
||||
//Compare and send
|
||||
DateTime? tRise = null;
|
||||
for (Int32 x = 0; x < 5; x++) {
|
||||
if (rises[x].HasValue) {
|
||||
if (rises[x].Value.Day == date.Day) {
|
||||
tRise = rises[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
DateTime? tSet = null;
|
||||
for (Int32 x = 0; x < 5; x++) {
|
||||
if (sets[x].HasValue) {
|
||||
if (sets[x].Value.Day == date.Day) {
|
||||
tSet = sets[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new DateTime?[] { tRise, tSet };
|
||||
}
|
||||
|
||||
public static void CalculateZodiacSign(DateTime date, Celestial c) {
|
||||
//Aquarius (January 20 to February 18)
|
||||
//Pisces (February 19 to March 20)
|
||||
//Aries (March 21-April 19)
|
||||
//Taurus (April 20-May 20)
|
||||
//Gemini (May 21-June 20)
|
||||
//Cancer (June 21-July 22)
|
||||
//Leo (July 23-August 22)
|
||||
//Virgo (August 23-September 22)
|
||||
//Libra (September 23-October 22)
|
||||
//Scorpio (October 23-November 21)
|
||||
//Sagittarius (November 22-December 21)
|
||||
//Capricorn (December 22-January 19)
|
||||
if (date >= new DateTime(date.Year, 1, 1) && date <= new DateTime(date.Year, 1, 19, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Capricorn";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 1, 20) && date <= new DateTime(date.Year, 2, 18, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Aquarius";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 2, 19) && date <= new DateTime(date.Year, 3, 20, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Pisces";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 3, 21) && date <= new DateTime(date.Year, 4, 19, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Aries";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 4, 20) && date <= new DateTime(date.Year, 5, 20, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Taurus";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 5, 21) && date <= new DateTime(date.Year, 6, 20, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Gemini";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 6, 21) && date <= new DateTime(date.Year, 7, 22, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Cancer";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 7, 23) && date <= new DateTime(date.Year, 8, 22, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Leo";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 8, 23) && date <= new DateTime(date.Year, 9, 22, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Virgo";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 10, 22, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Libra";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 11, 21, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Scorpio";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 11, 21) && date <= new DateTime(date.Year, 12, 21, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Sagittarius";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 12, 22) && date <= new DateTime(date.Year, 12, 31, 23, 59, 59)) {
|
||||
c.AstrologicalSigns.ZodiacSign = "Capricorn";
|
||||
return;
|
||||
}
|
||||
}
|
||||
public static void CalculateSolarEclipse(DateTime date, Double lat, Double longi, Celestial c) {
|
||||
//Convert to Radian
|
||||
Double latR = lat * Math.PI / 180;
|
||||
Double longR = longi * Math.PI / 180;
|
||||
List<List<String>> se = SolarEclipseCalc.CalculateSolarEclipse(date, latR, longR);
|
||||
//RETURN FIRST AND LAST
|
||||
if (se.Count == 0) { return; }
|
||||
//FIND LAST AND NEXT ECLIPSE
|
||||
Int32 lastE = -1;
|
||||
Int32 nextE = -1;
|
||||
Int32 currentE = 0;
|
||||
DateTime lastDate = new DateTime();
|
||||
DateTime nextDate = new DateTime(3300, 1, 1);
|
||||
//Iterate to get last and next eclipse
|
||||
foreach (List<String> values in se) {
|
||||
DateTime ld = DateTime.ParseExact(values[0], "yyyy-MMM-dd", System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
if (ld < date && ld > lastDate) { lastDate = ld; lastE = currentE; }
|
||||
if (ld >= date && ld < nextDate) { nextDate = ld; nextE = currentE; }
|
||||
currentE++;
|
||||
}
|
||||
//SET ECLIPSE DATA
|
||||
if (lastE >= 0) {
|
||||
c.SolarEclipse.LastEclipse = new SolarEclipseDetails(se[lastE]);
|
||||
}
|
||||
if (nextE >= 0) {
|
||||
c.SolarEclipse.NextEclipse = new SolarEclipseDetails(se[nextE]);
|
||||
}
|
||||
}
|
||||
|
||||
#region Private Suntime Members
|
||||
private static readonly Double dayMS = 1000 * 60 * 60 * 24, j1970 = 2440588, j2000 = 2451545;
|
||||
private static readonly Double rad = Math.PI / 180;
|
||||
|
||||
/*private static Double LocalSiderealTimeForTimeZone(Double lon, Double jd, Double z)
|
||||
{
|
||||
Double s = 24110.5 + 8640184.812999999 * jd / 36525 + 86636.6 * z + 86400 * lon;
|
||||
s = s / 86400;
|
||||
s = s - Math.Truncate(s);
|
||||
Double lst = s * 360 *rad;
|
||||
|
||||
return lst;
|
||||
}*/
|
||||
private static Double SideRealTime(Double d, Double lw) {
|
||||
Double s = rad * (280.16 + 360.9856235 * d) - lw;
|
||||
return s;
|
||||
}
|
||||
private static Double SolarTransitJ(Double ds, Double M, Double L) => j2000 + ds + 0.0053 * Math.Sin(M) - 0.0069 * Math.Sin(2 * L);
|
||||
|
||||
//CH15
|
||||
//Formula 15.1
|
||||
//Returns Approximate Time
|
||||
private static Double HourAngle(Double h, Double phi, Double d) {
|
||||
//NUMBER RETURNING > and < 1 NaN;
|
||||
Double d1 = Math.Sin(h) - Math.Sin(phi) * Math.Sin(d);
|
||||
Double d2 = Math.Cos(phi) * Math.Cos(d);
|
||||
Double d3 = d1 / d2;
|
||||
|
||||
return Math.Acos(d3);
|
||||
}
|
||||
private static Double ApproxTransit(Double Ht, Double lw, Double n) => 0.0009 + (Ht + lw) / (2 * Math.PI) + n;
|
||||
|
||||
private static Double JulianCycle(Double d, Double lw) => Math.Round(d - 0.0009 - lw / (2 * Math.PI));
|
||||
|
||||
//Returns Time of specified event based on suns angle
|
||||
private static Double GetTime(Double h, Double lw, Double phi, Double dec, Double n, Double M, Double L) {
|
||||
Double approxTime = HourAngle(h, phi, dec); //Ch15 Formula 15.1
|
||||
|
||||
Double a = ApproxTransit(approxTime, lw, n);
|
||||
Double st = SolarTransitJ(a, M, L);
|
||||
|
||||
return st;
|
||||
}
|
||||
private static Double Declination(Double l, Double b) {
|
||||
Double e = Math.PI / 180 * 23.4392911; // obliquity of the Earth
|
||||
|
||||
return Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));
|
||||
}
|
||||
|
||||
private static void CalculateSunAngle(DateTime date, Double longi, Double lat, Celestial c) {
|
||||
TimeSpan ts = date - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
Double dms = ts.TotalMilliseconds / dayMS - .5 + j1970 - j2000;
|
||||
|
||||
Double lw = rad * -longi;
|
||||
Double phi = rad * lat;
|
||||
//Double e = rad * 23.4397;
|
||||
|
||||
Double[] sc = SunCoords(dms);
|
||||
|
||||
Double H = SideRealTime(dms, lw) - sc[1];
|
||||
|
||||
c.sunAzimuth = Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(sc[0]) * Math.Cos(phi)) * 180 / Math.PI + 180;
|
||||
c.sunAltitude = Math.Asin(Math.Sin(phi) * Math.Sin(sc[0]) + Math.Cos(phi) * Math.Cos(sc[0]) * Math.Cos(H)) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
private static Double SolarMeanAnomaly(Double d) => rad * (357.5291 + 0.98560028 * d);
|
||||
|
||||
private static Double EclipticLongitude(Double m) {
|
||||
Double c = rad * (1.9148 * Math.Sin(m) + 0.02 * Math.Sin(2 * m) + 0.0003 * Math.Sin(3 * m)); // equation of center
|
||||
Double p = rad * 102.9372; // perihelion of the Earth
|
||||
|
||||
return m + c + p + Math.PI;
|
||||
}
|
||||
private static Double[] SunCoords(Double d) {
|
||||
|
||||
Double m = SolarMeanAnomaly(d);
|
||||
Double l = EclipticLongitude(m);
|
||||
Double[] sc = new Double[2];
|
||||
Double b = 0;
|
||||
Double e = rad * 23.4397; // obliquity of the Earth
|
||||
sc[0] = Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l)); //declination
|
||||
sc[1] = Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l)); //rightAscension
|
||||
return sc;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,268 +2,233 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
|
||||
namespace CoordinateSharp {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used for UTM/MGRS Conversions
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class LatZones
|
||||
{
|
||||
public static List<string> longZongLetters = new List<string>(new string[]{"C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used for UTM/MGRS Conversions
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class LatZones {
|
||||
public static List<String> longZongLetters = new List<String>(new String[]{"C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
|
||||
"U", "V", "W", "X"});
|
||||
}
|
||||
/// <summary>
|
||||
/// Used for handling diagraph determination
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class Digraphs {
|
||||
private readonly List<Digraph> digraph1;
|
||||
private readonly List<Digraph> digraph2;
|
||||
|
||||
private readonly String[] digraph1Array = { "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
|
||||
|
||||
private readonly String[] digraph2Array = { "V", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V" };
|
||||
|
||||
public Digraphs() {
|
||||
this.digraph1 = new List<Digraph>();
|
||||
this.digraph2 = new List<Digraph>();
|
||||
|
||||
this.digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 2, Letter = "B" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 3, Letter = "C" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 4, Letter = "D" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 5, Letter = "E" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 6, Letter = "F" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 7, Letter = "G" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 8, Letter = "H" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 9, Letter = "J" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 10, Letter = "K" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 11, Letter = "L" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 12, Letter = "M" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 13, Letter = "N" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 14, Letter = "P" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 15, Letter = "Q" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 16, Letter = "R" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 17, Letter = "S" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 18, Letter = "T" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 19, Letter = "U" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 20, Letter = "V" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 21, Letter = "W" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 22, Letter = "X" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 23, Letter = "Y" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 24, Letter = "Z" });
|
||||
this.digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
|
||||
this.digraph2.Add(new Digraph() { Zone = 0, Letter = "V" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 2, Letter = "B" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 3, Letter = "C" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 4, Letter = "D" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 5, Letter = "E" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 6, Letter = "F" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 7, Letter = "G" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 8, Letter = "H" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 9, Letter = "J" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 10, Letter = "K" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 11, Letter = "L" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 12, Letter = "M" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 13, Letter = "N" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 14, Letter = "P" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 15, Letter = "Q" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 16, Letter = "R" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 17, Letter = "S" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 18, Letter = "T" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 19, Letter = "U" });
|
||||
this.digraph2.Add(new Digraph() { Zone = 20, Letter = "V" });
|
||||
}
|
||||
|
||||
internal Int32 GetDigraph1Index(String letter) {
|
||||
for (Int32 i = 0; i < this.digraph1Array.Length; i++) {
|
||||
if (this.digraph1Array[i].Equals(letter)) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal Int32 GetDigraph2Index(String letter) {
|
||||
for (Int32 i = 0; i < this.digraph2Array.Length; i++) {
|
||||
if (this.digraph2Array[i].Equals(letter)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal String GetDigraph1(Int32 longZone, Double easting) {
|
||||
Int32 a1 = longZone;
|
||||
Double a2 = 8 * ((a1 - 1) % 3) + 1;
|
||||
|
||||
Double a3 = easting;
|
||||
Double a4 = a2 + (Int32)(a3 / 100000) - 1;
|
||||
return this.digraph1.Where(x => x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
|
||||
}
|
||||
|
||||
internal String GetDigraph2(Int32 longZone, Double northing) {
|
||||
Int32 a1 = longZone;
|
||||
Double a2 = 1 + 5 * ((a1 - 1) % 2);
|
||||
Double a3 = northing;
|
||||
Double a4 = a2 + (Int32)(a3 / 100000);
|
||||
a4 = (a2 + (Int32)(a3 / 100000.0)) % 20;
|
||||
a4 = Math.Floor(a4);
|
||||
if (a4 < 0) {
|
||||
a4 += 19;
|
||||
}
|
||||
return this.digraph2.Where(x => x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Diagraph model
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class Digraph {
|
||||
public Int32 Zone { get; set; }
|
||||
public String Letter { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Used for setting whether a coordinate part is latitudinal or longitudinal.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinateType {
|
||||
/// <summary>
|
||||
/// Used for handling diagraph determination
|
||||
/// Latitude
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class Digraphs
|
||||
{
|
||||
private List<Digraph> digraph1;
|
||||
private List<Digraph> digraph2;
|
||||
|
||||
private String[] digraph1Array = { "A", "B", "C", "D", "E", "F", "G", "H",
|
||||
"J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
|
||||
"Y", "Z" };
|
||||
|
||||
private String[] digraph2Array = { "V", "A", "B", "C", "D", "E", "F", "G",
|
||||
"H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V" };
|
||||
|
||||
public Digraphs()
|
||||
{
|
||||
digraph1 = new List<Digraph>();
|
||||
digraph2 = new List<Digraph>();
|
||||
|
||||
digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
digraph1.Add(new Digraph() { Zone = 2, Letter = "B" });
|
||||
digraph1.Add(new Digraph() { Zone = 3, Letter = "C" });
|
||||
digraph1.Add(new Digraph() { Zone = 4, Letter = "D" });
|
||||
digraph1.Add(new Digraph() { Zone = 5, Letter = "E" });
|
||||
digraph1.Add(new Digraph() { Zone = 6, Letter = "F" });
|
||||
digraph1.Add(new Digraph() { Zone = 7, Letter = "G" });
|
||||
digraph1.Add(new Digraph() { Zone = 8, Letter = "H" });
|
||||
digraph1.Add(new Digraph() { Zone = 9, Letter = "J" });
|
||||
digraph1.Add(new Digraph() { Zone = 10, Letter = "K" });
|
||||
digraph1.Add(new Digraph() { Zone = 11, Letter = "L" });
|
||||
digraph1.Add(new Digraph() { Zone = 12, Letter = "M" });
|
||||
digraph1.Add(new Digraph() { Zone = 13, Letter = "N" });
|
||||
digraph1.Add(new Digraph() { Zone = 14, Letter = "P" });
|
||||
digraph1.Add(new Digraph() { Zone = 15, Letter = "Q" });
|
||||
digraph1.Add(new Digraph() { Zone = 16, Letter = "R" });
|
||||
digraph1.Add(new Digraph() { Zone = 17, Letter = "S" });
|
||||
digraph1.Add(new Digraph() { Zone = 18, Letter = "T" });
|
||||
digraph1.Add(new Digraph() { Zone = 19, Letter = "U" });
|
||||
digraph1.Add(new Digraph() { Zone = 20, Letter = "V" });
|
||||
digraph1.Add(new Digraph() { Zone = 21, Letter = "W" });
|
||||
digraph1.Add(new Digraph() { Zone = 22, Letter = "X" });
|
||||
digraph1.Add(new Digraph() { Zone = 23, Letter = "Y" });
|
||||
digraph1.Add(new Digraph() { Zone = 24, Letter = "Z" });
|
||||
digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
|
||||
digraph2.Add(new Digraph() { Zone = 0, Letter = "V"});
|
||||
digraph2.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
digraph2.Add(new Digraph() { Zone = 2, Letter = "B" });
|
||||
digraph2.Add(new Digraph() { Zone = 3, Letter = "C" });
|
||||
digraph2.Add(new Digraph() { Zone = 4, Letter = "D" });
|
||||
digraph2.Add(new Digraph() { Zone = 5, Letter = "E" });
|
||||
digraph2.Add(new Digraph() { Zone = 6, Letter = "F" });
|
||||
digraph2.Add(new Digraph() { Zone = 7, Letter = "G" });
|
||||
digraph2.Add(new Digraph() { Zone = 8, Letter = "H" });
|
||||
digraph2.Add(new Digraph() { Zone = 9, Letter = "J" });
|
||||
digraph2.Add(new Digraph() { Zone = 10, Letter = "K" });
|
||||
digraph2.Add(new Digraph() { Zone = 11, Letter = "L" });
|
||||
digraph2.Add(new Digraph() { Zone = 12, Letter = "M" });
|
||||
digraph2.Add(new Digraph() { Zone = 13, Letter = "N" });
|
||||
digraph2.Add(new Digraph() { Zone = 14, Letter = "P" });
|
||||
digraph2.Add(new Digraph() { Zone = 15, Letter = "Q" });
|
||||
digraph2.Add(new Digraph() { Zone = 16, Letter = "R" });
|
||||
digraph2.Add(new Digraph() { Zone = 17, Letter = "S" });
|
||||
digraph2.Add(new Digraph() { Zone = 18, Letter = "T" });
|
||||
digraph2.Add(new Digraph() { Zone = 19, Letter = "U" });
|
||||
digraph2.Add(new Digraph() { Zone = 20, Letter = "V" });
|
||||
}
|
||||
|
||||
internal int getDigraph1Index(String letter)
|
||||
{
|
||||
for (int i = 0; i < digraph1Array.Length; i++)
|
||||
{
|
||||
if (digraph1Array[i].Equals(letter))
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal int getDigraph2Index(String letter)
|
||||
{
|
||||
for (int i = 0; i < digraph2Array.Length; i++)
|
||||
{
|
||||
if (digraph2Array[i].Equals(letter))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal String getDigraph1(int longZone, double easting)
|
||||
{
|
||||
int a1 = longZone;
|
||||
double a2 = 8 * ((a1 - 1) % 3) + 1;
|
||||
|
||||
double a3 = easting;
|
||||
double a4 = a2 + ((int)(a3 / 100000)) - 1;
|
||||
return digraph1.Where(x=>x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
|
||||
}
|
||||
|
||||
internal String getDigraph2(int longZone, double northing)
|
||||
{
|
||||
int a1 = longZone;
|
||||
double a2 = 1 + 5 * ((a1 - 1) % 2);
|
||||
double a3 = northing;
|
||||
double a4 = (a2 + ((int)(a3 / 100000)));
|
||||
a4 = (a2 + ((int)(a3 / 100000.0))) % 20;
|
||||
a4 = Math.Floor(a4);
|
||||
if (a4 < 0)
|
||||
{
|
||||
a4 = a4 + 19;
|
||||
}
|
||||
return digraph2.Where(x => x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
|
||||
}
|
||||
|
||||
}
|
||||
Lat,
|
||||
/// <summary>
|
||||
/// Diagraph model
|
||||
/// Longitude
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class Digraph
|
||||
{
|
||||
public int Zone { get; set; }
|
||||
public string Letter { get; set; }
|
||||
}
|
||||
Long
|
||||
}
|
||||
/// <summary>
|
||||
/// Used to set a coordinate part position.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinatesPosition : Int32 {
|
||||
/// <summary>
|
||||
/// Used for setting whether a coordinate part is latitudinal or longitudinal.
|
||||
/// North
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinateType
|
||||
{
|
||||
/// <summary>
|
||||
/// Latitude
|
||||
/// </summary>
|
||||
Lat,
|
||||
/// <summary>
|
||||
/// Longitude
|
||||
/// </summary>
|
||||
Long
|
||||
}
|
||||
N,
|
||||
/// <summary>
|
||||
/// Used to set a coordinate part position.
|
||||
/// East
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinatesPosition :int
|
||||
{
|
||||
/// <summary>
|
||||
/// North
|
||||
/// </summary>
|
||||
N,
|
||||
/// <summary>
|
||||
/// East
|
||||
/// </summary>
|
||||
E,
|
||||
/// <summary>
|
||||
/// South
|
||||
/// </summary>
|
||||
S,
|
||||
/// <summary>
|
||||
/// West
|
||||
/// </summary>
|
||||
W
|
||||
}
|
||||
|
||||
|
||||
E,
|
||||
/// <summary>
|
||||
/// Coordinate type datum specification
|
||||
/// South
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Flags]
|
||||
public enum Coordinate_Datum
|
||||
{
|
||||
/// <summary>
|
||||
/// Lat Long GeoDetic
|
||||
/// </summary>
|
||||
LAT_LONG = 1,
|
||||
/// <summary>
|
||||
/// UTM and MGRS
|
||||
/// </summary>
|
||||
UTM_MGRS = 2,
|
||||
/// <summary>
|
||||
/// ECEF
|
||||
/// </summary>
|
||||
ECEF = 4,
|
||||
}
|
||||
|
||||
S,
|
||||
/// <summary>
|
||||
/// Cartesian Coordinate Type
|
||||
/// West
|
||||
/// </summary>
|
||||
public enum CartesianType
|
||||
{
|
||||
/// <summary>
|
||||
/// Spherical Cartesian
|
||||
/// </summary>
|
||||
Cartesian,
|
||||
/// <summary>
|
||||
/// Earth Centered Earth Fixed
|
||||
/// </summary>
|
||||
ECEF,
|
||||
}
|
||||
/// <summary>
|
||||
/// Used for easy read math functions
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal static class ModM
|
||||
{
|
||||
public static double Mod(double x, double y)
|
||||
{
|
||||
return x - y * Math.Floor(x / y);
|
||||
}
|
||||
W
|
||||
}
|
||||
|
||||
public static double ModLon(double x)
|
||||
{
|
||||
return Mod(x + Math.PI, 2 * Math.PI) - Math.PI;
|
||||
}
|
||||
|
||||
public static double ModCrs(double x)
|
||||
{
|
||||
return Mod(x, 2 * Math.PI);
|
||||
}
|
||||
|
||||
public static double ModLat(double x)
|
||||
{
|
||||
return Mod(x + Math.PI / 2, 2 * Math.PI) - Math.PI / 2;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Coordinate type datum specification
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Flags]
|
||||
public enum Coordinate_Datum {
|
||||
/// <summary>
|
||||
/// Earth Shape for Calculations.
|
||||
/// Lat Long GeoDetic
|
||||
/// </summary>
|
||||
LAT_LONG = 1,
|
||||
/// <summary>
|
||||
/// UTM and MGRS
|
||||
/// </summary>
|
||||
UTM_MGRS = 2,
|
||||
/// <summary>
|
||||
/// ECEF
|
||||
/// </summary>
|
||||
ECEF = 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cartesian Coordinate Type
|
||||
/// </summary>
|
||||
public enum CartesianType {
|
||||
/// <summary>
|
||||
/// Spherical Cartesian
|
||||
/// </summary>
|
||||
Cartesian,
|
||||
/// <summary>
|
||||
/// Earth Centered Earth Fixed
|
||||
/// </summary>
|
||||
ECEF,
|
||||
}
|
||||
/// <summary>
|
||||
/// Used for easy read math functions
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal static class ModM {
|
||||
public static Double Mod(Double x, Double y) => x - y * Math.Floor(x / y);
|
||||
|
||||
public static Double ModLon(Double x) => Mod(x + Math.PI, 2 * Math.PI) - Math.PI;
|
||||
|
||||
public static Double ModCrs(Double x) => Mod(x, 2 * Math.PI);
|
||||
|
||||
public static Double ModLat(Double x) => Mod(x + Math.PI / 2, 2 * Math.PI) - Math.PI / 2;
|
||||
}
|
||||
/// <summary>
|
||||
/// Earth Shape for Calculations.
|
||||
/// </summary>
|
||||
|
||||
[Serializable]
|
||||
public enum Shape {
|
||||
/// <summary>
|
||||
/// Calculate as sphere (less accurate, more efficient).
|
||||
/// </summary>
|
||||
Sphere,
|
||||
/// <summary>
|
||||
/// Calculate as ellipsoid (more accurate, less efficient).
|
||||
/// </summary>
|
||||
Ellipsoid
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public enum Shape
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculate as sphere (less accurate, more efficient).
|
||||
/// </summary>
|
||||
Sphere,
|
||||
/// <summary>
|
||||
/// Calculate as ellipsoid (more accurate, less efficient).
|
||||
/// </summary>
|
||||
Ellipsoid
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,155 +1,135 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
|
||||
namespace CoordinateSharp {
|
||||
/// <summary>
|
||||
/// Cartesian (X, Y, Z) Coordinate
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Cartesian : INotifyPropertyChanged {
|
||||
/// <summary>
|
||||
/// Cartesian (X, Y, Z) Coordinate
|
||||
/// Create a Cartesian Object
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Cartesian : INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a Cartesian Object
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
public Cartesian(Coordinate c)
|
||||
{
|
||||
//formulas:
|
||||
x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
|
||||
y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
|
||||
z = Math.Sin(c.Latitude.ToRadians());
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a Cartesian Object
|
||||
/// </summary>
|
||||
/// <param name="xc">X</param>
|
||||
/// <param name="yc">Y</param>
|
||||
/// <param name="zc">Z</param>
|
||||
public Cartesian(double xc, double yc, double zc)
|
||||
{
|
||||
//formulas:
|
||||
x = xc;
|
||||
y = yc;
|
||||
z = zc;
|
||||
}
|
||||
/// <summary>
|
||||
/// Updates Cartesian Values
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
public void ToCartesian(Coordinate c)
|
||||
{
|
||||
x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
|
||||
y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
|
||||
z = Math.Sin(c.Latitude.ToRadians());
|
||||
}
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
|
||||
/// <summary>
|
||||
/// X Coordinate
|
||||
/// </summary>
|
||||
public double X
|
||||
{
|
||||
get { return x; }
|
||||
set
|
||||
{
|
||||
if(x != value)
|
||||
{
|
||||
x = value;
|
||||
NotifyPropertyChanged("X");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// y Coordinate
|
||||
/// </summary>
|
||||
public double Y
|
||||
{
|
||||
get { return y; }
|
||||
set
|
||||
{
|
||||
if (y != value)
|
||||
{
|
||||
y = value;
|
||||
NotifyPropertyChanged("Y");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Z Coordinate
|
||||
/// </summary>
|
||||
public double Z
|
||||
{
|
||||
get { return z; }
|
||||
set
|
||||
{
|
||||
if (z != value)
|
||||
{
|
||||
z = value;
|
||||
NotifyPropertyChanged("Z");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
|
||||
/// </summary>
|
||||
/// <param name="x">X</param>
|
||||
/// <param name="y">Y</param>
|
||||
/// <param name="z">Z</param>
|
||||
/// <returns></returns>
|
||||
public static Coordinate CartesianToLatLong(double x, double y, double z)
|
||||
{
|
||||
double lon = Math.Atan2(y, x);
|
||||
double hyp = Math.Sqrt(x * x + y * y);
|
||||
double lat = Math.Atan2(z, hyp);
|
||||
|
||||
double Lat = lat * (180 / Math.PI);
|
||||
double Lon = lon * (180 / Math.PI);
|
||||
return new Coordinate(Lat, Lon);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
|
||||
/// </summary>
|
||||
/// <param name="cart">Cartesian Coordinate</param>
|
||||
/// <returns></returns>
|
||||
public static Coordinate CartesianToLatLong(Cartesian cart)
|
||||
{
|
||||
double x = cart.X;
|
||||
double y = cart.Y;
|
||||
double z = cart.Z;
|
||||
|
||||
double lon = Math.Atan2(y, x);
|
||||
double hyp = Math.Sqrt(x * x + y * y);
|
||||
double lat = Math.Atan2(z, hyp);
|
||||
|
||||
double Lat = lat * (180 / Math.PI);
|
||||
double Lon = lon * (180 / Math.PI);
|
||||
return new Coordinate(Lat, Lon);
|
||||
}
|
||||
/// <summary>
|
||||
/// Cartesian Default String Format
|
||||
/// </summary>
|
||||
/// <returns>Cartesian Formatted Coordinate String</returns>
|
||||
/// <returns>Values rounded to the 8th place</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return Math.Round(x,8).ToString() + " " + Math.Round(y, 8).ToString() + " " + Math.Round(z, 8).ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(string propName)
|
||||
{
|
||||
if (this.PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
||||
/// <param name="c"></param>
|
||||
public Cartesian(Coordinate c) {
|
||||
//formulas:
|
||||
this.x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
|
||||
this.y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
|
||||
this.z = Math.Sin(c.Latitude.ToRadians());
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a Cartesian Object
|
||||
/// </summary>
|
||||
/// <param name="xc">X</param>
|
||||
/// <param name="yc">Y</param>
|
||||
/// <param name="zc">Z</param>
|
||||
public Cartesian(Double xc, Double yc, Double zc) {
|
||||
//formulas:
|
||||
this.x = xc;
|
||||
this.y = yc;
|
||||
this.z = zc;
|
||||
}
|
||||
/// <summary>
|
||||
/// Updates Cartesian Values
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
public void ToCartesian(Coordinate c) {
|
||||
this.x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
|
||||
this.y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
|
||||
this.z = Math.Sin(c.Latitude.ToRadians());
|
||||
}
|
||||
private Double x;
|
||||
private Double y;
|
||||
private Double z;
|
||||
|
||||
/// <summary>
|
||||
/// X Coordinate
|
||||
/// </summary>
|
||||
public Double X {
|
||||
get => this.x;
|
||||
set {
|
||||
if (this.x != value) {
|
||||
this.x = value;
|
||||
this.NotifyPropertyChanged("X");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// y Coordinate
|
||||
/// </summary>
|
||||
public Double Y {
|
||||
get => this.y;
|
||||
set {
|
||||
if (this.y != value) {
|
||||
this.y = value;
|
||||
this.NotifyPropertyChanged("Y");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Z Coordinate
|
||||
/// </summary>
|
||||
public Double Z {
|
||||
get => this.z;
|
||||
set {
|
||||
if (this.z != value) {
|
||||
this.z = value;
|
||||
this.NotifyPropertyChanged("Z");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
|
||||
/// </summary>
|
||||
/// <param name="x">X</param>
|
||||
/// <param name="y">Y</param>
|
||||
/// <param name="z">Z</param>
|
||||
/// <returns></returns>
|
||||
public static Coordinate CartesianToLatLong(Double x, Double y, Double z) {
|
||||
Double lon = Math.Atan2(y, x);
|
||||
Double hyp = Math.Sqrt(x * x + y * y);
|
||||
Double lat = Math.Atan2(z, hyp);
|
||||
|
||||
Double Lat = lat * (180 / Math.PI);
|
||||
Double Lon = lon * (180 / Math.PI);
|
||||
return new Coordinate(Lat, Lon);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
|
||||
/// </summary>
|
||||
/// <param name="cart">Cartesian Coordinate</param>
|
||||
/// <returns></returns>
|
||||
public static Coordinate CartesianToLatLong(Cartesian cart) {
|
||||
Double x = cart.X;
|
||||
Double y = cart.Y;
|
||||
Double z = cart.Z;
|
||||
|
||||
Double lon = Math.Atan2(y, x);
|
||||
Double hyp = Math.Sqrt(x * x + y * y);
|
||||
Double lat = Math.Atan2(z, hyp);
|
||||
|
||||
Double Lat = lat * (180 / Math.PI);
|
||||
Double Lon = lon * (180 / Math.PI);
|
||||
return new Coordinate(Lat, Lon);
|
||||
}
|
||||
/// <summary>
|
||||
/// Cartesian Default String Format
|
||||
/// </summary>
|
||||
/// <returns>Cartesian Formatted Coordinate String</returns>
|
||||
/// <returns>Values rounded to the 8th place</returns>
|
||||
public override String ToString() => Math.Round(this.x, 8).ToString() + " " + Math.Round(this.y, 8).ToString() + " " + Math.Round(this.z, 8).ToString();
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(String propName) {
|
||||
if (this.PropertyChanged != null) {
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,119 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
namespace CoordinateSharp {
|
||||
/// <summary>
|
||||
/// Turn on/off eager loading of certain properties.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class EagerLoad {
|
||||
/// <summary>
|
||||
/// Turn on/off eager loading of certain properties.
|
||||
/// Create an EagerLoad object
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class EagerLoad
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an EagerLoad object
|
||||
/// </summary>
|
||||
public EagerLoad()
|
||||
{
|
||||
Celestial = true;
|
||||
UTM_MGRS = true;
|
||||
Cartesian = true;
|
||||
ECEF = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an EagerLoad object with all options on or off
|
||||
/// </summary>
|
||||
/// <param name="isOn">Turns EagerLoad on or off</param>
|
||||
public EagerLoad(bool isOn)
|
||||
{
|
||||
Celestial = isOn;
|
||||
UTM_MGRS = isOn;
|
||||
Cartesian = isOn;
|
||||
ECEF = isOn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an EagerLoad object with only the specified flag options turned on.
|
||||
/// </summary>
|
||||
/// <param name="et">EagerLoadType</param>
|
||||
public EagerLoad(EagerLoadType et)
|
||||
{
|
||||
Cartesian = false;
|
||||
Celestial = false;
|
||||
UTM_MGRS = false;
|
||||
ECEF = false;
|
||||
|
||||
if (et.HasFlag(EagerLoadType.Cartesian))
|
||||
{
|
||||
Cartesian = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.Celestial))
|
||||
{
|
||||
Celestial = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.UTM_MGRS))
|
||||
{
|
||||
UTM_MGRS = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.ECEF))
|
||||
{
|
||||
ECEF = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an EagerLoad object. Only the specified flags will be set to EagerLoad.
|
||||
/// </summary>
|
||||
/// <param name="et">EagerLoadType</param>
|
||||
/// <returns>EagerLoad</returns>
|
||||
public static EagerLoad Create(EagerLoadType et)
|
||||
{
|
||||
EagerLoad el = new EagerLoad(et);
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eager load celestial information.
|
||||
/// </summary>
|
||||
public bool Celestial { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load UTM and MGRS information
|
||||
/// </summary>
|
||||
public bool UTM_MGRS { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load Cartesian information
|
||||
/// </summary>
|
||||
public bool Cartesian { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load ECEF information
|
||||
/// </summary>
|
||||
public bool ECEF { get; set; }
|
||||
public EagerLoad() {
|
||||
this.Celestial = true;
|
||||
this.UTM_MGRS = true;
|
||||
this.Cartesian = true;
|
||||
this.ECEF = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EagerLoad Enumerator
|
||||
/// Create an EagerLoad object with all options on or off
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Flags]
|
||||
public enum EagerLoadType
|
||||
{
|
||||
/// <summary>
|
||||
/// UTM and MGRS
|
||||
/// </summary>
|
||||
UTM_MGRS = 1,
|
||||
/// <summary>
|
||||
/// Celestial
|
||||
/// </summary>
|
||||
Celestial = 2,
|
||||
/// <summary>
|
||||
/// Cartesian
|
||||
/// </summary>
|
||||
Cartesian = 4,
|
||||
/// <summary>
|
||||
/// ECEF
|
||||
/// </summary>
|
||||
ECEF = 8
|
||||
|
||||
/// <param name="isOn">Turns EagerLoad on or off</param>
|
||||
public EagerLoad(Boolean isOn) {
|
||||
this.Celestial = isOn;
|
||||
this.UTM_MGRS = isOn;
|
||||
this.Cartesian = isOn;
|
||||
this.ECEF = isOn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an EagerLoad object with only the specified flag options turned on.
|
||||
/// </summary>
|
||||
/// <param name="et">EagerLoadType</param>
|
||||
public EagerLoad(EagerLoadType et) {
|
||||
this.Cartesian = false;
|
||||
this.Celestial = false;
|
||||
this.UTM_MGRS = false;
|
||||
this.ECEF = false;
|
||||
|
||||
if (et.HasFlag(EagerLoadType.Cartesian)) {
|
||||
this.Cartesian = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.Celestial)) {
|
||||
this.Celestial = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.UTM_MGRS)) {
|
||||
this.UTM_MGRS = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.ECEF)) {
|
||||
this.ECEF = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an EagerLoad object. Only the specified flags will be set to EagerLoad.
|
||||
/// </summary>
|
||||
/// <param name="et">EagerLoadType</param>
|
||||
/// <returns>EagerLoad</returns>
|
||||
public static EagerLoad Create(EagerLoadType et) {
|
||||
EagerLoad el = new EagerLoad(et);
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eager load celestial information.
|
||||
/// </summary>
|
||||
public Boolean Celestial { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load UTM and MGRS information
|
||||
/// </summary>
|
||||
public Boolean UTM_MGRS { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load Cartesian information
|
||||
/// </summary>
|
||||
public Boolean Cartesian { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load ECEF information
|
||||
/// </summary>
|
||||
public Boolean ECEF { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// EagerLoad Enumerator
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Flags]
|
||||
public enum EagerLoadType {
|
||||
/// <summary>
|
||||
/// UTM and MGRS
|
||||
/// </summary>
|
||||
UTM_MGRS = 1,
|
||||
/// <summary>
|
||||
/// Celestial
|
||||
/// </summary>
|
||||
Celestial = 2,
|
||||
/// <summary>
|
||||
/// Cartesian
|
||||
/// </summary>
|
||||
Cartesian = 4,
|
||||
/// <summary>
|
||||
/// ECEF
|
||||
/// </summary>
|
||||
ECEF = 8
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,107 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
namespace CoordinateSharp {
|
||||
/// <summary>
|
||||
/// Coordinate formatting options for a Coordinate object.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class CoordinateFormatOptions {
|
||||
/// <summary>
|
||||
/// Coordinate formatting options for a Coordinate object.
|
||||
/// Set default values with the constructor.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class CoordinateFormatOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Set default values with the constructor.
|
||||
/// </summary>
|
||||
public CoordinateFormatOptions()
|
||||
{
|
||||
Format = CoordinateFormatType.Degree_Minutes_Seconds;
|
||||
Round = 3;
|
||||
Display_Leading_Zeros = false;
|
||||
Display_Trailing_Zeros = false;
|
||||
Display_Symbols = true;
|
||||
Display_Degree_Symbol = true;
|
||||
Display_Minute_Symbol = true;
|
||||
Display_Seconds_Symbol = true;
|
||||
Display_Hyphens = false;
|
||||
Position_First = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Coordinate format type.
|
||||
/// </summary>
|
||||
public CoordinateFormatType Format { get; set; }
|
||||
/// <summary>
|
||||
/// Rounds Coordinates to the set value.
|
||||
/// </summary>
|
||||
public int Round { get; set; }
|
||||
/// <summary>
|
||||
/// Displays leading zeros.
|
||||
/// </summary>
|
||||
public bool Display_Leading_Zeros { get; set; }
|
||||
/// <summary>
|
||||
/// Display trailing zeros.
|
||||
/// </summary>
|
||||
public bool Display_Trailing_Zeros { get; set; }
|
||||
/// <summary>
|
||||
/// Allow symbols to display.
|
||||
/// </summary>
|
||||
public bool Display_Symbols { get; set; }
|
||||
/// <summary>
|
||||
/// Display degree symbols.
|
||||
/// </summary>
|
||||
public bool Display_Degree_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display minute symbols.
|
||||
/// </summary>
|
||||
public bool Display_Minute_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display secons symbol.
|
||||
/// </summary>
|
||||
public bool Display_Seconds_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display hyphens between values.
|
||||
/// </summary>
|
||||
public bool Display_Hyphens { get; set; }
|
||||
/// <summary>
|
||||
/// Show coordinate position first.
|
||||
/// Will show last if set 'false'.
|
||||
/// </summary>
|
||||
public bool Position_First { get; set; }
|
||||
public CoordinateFormatOptions() {
|
||||
this.Format = CoordinateFormatType.Degree_Minutes_Seconds;
|
||||
this.Round = 3;
|
||||
this.Display_Leading_Zeros = false;
|
||||
this.Display_Trailing_Zeros = false;
|
||||
this.Display_Symbols = true;
|
||||
this.Display_Degree_Symbol = true;
|
||||
this.Display_Minute_Symbol = true;
|
||||
this.Display_Seconds_Symbol = true;
|
||||
this.Display_Hyphens = false;
|
||||
this.Position_First = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Coordinate Format Types.
|
||||
/// Coordinate format type.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinateFormatType
|
||||
{
|
||||
/// <summary>
|
||||
/// Decimal Degree Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40.456 W 75.456
|
||||
/// </remarks>
|
||||
Decimal_Degree,
|
||||
/// <summary>
|
||||
/// Decimal Degree Minutes Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40º 34.552' W 70º 45.408'
|
||||
/// </remarks>
|
||||
Degree_Decimal_Minutes,
|
||||
/// <summary>
|
||||
/// Decimal Degree Minutes Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40º 34" 36.552' W 70º 45" 24.408'
|
||||
/// </remarks>
|
||||
Degree_Minutes_Seconds,
|
||||
/// <summary>
|
||||
/// Decimal Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: 40.57674 -70.46574
|
||||
/// </remarks>
|
||||
Decimal
|
||||
}
|
||||
public CoordinateFormatType Format { get; set; }
|
||||
/// <summary>
|
||||
/// Rounds Coordinates to the set value.
|
||||
/// </summary>
|
||||
public Int32 Round { get; set; }
|
||||
/// <summary>
|
||||
/// Displays leading zeros.
|
||||
/// </summary>
|
||||
public Boolean Display_Leading_Zeros { get; set; }
|
||||
/// <summary>
|
||||
/// Display trailing zeros.
|
||||
/// </summary>
|
||||
public Boolean Display_Trailing_Zeros { get; set; }
|
||||
/// <summary>
|
||||
/// Allow symbols to display.
|
||||
/// </summary>
|
||||
public Boolean Display_Symbols { get; set; }
|
||||
/// <summary>
|
||||
/// Display degree symbols.
|
||||
/// </summary>
|
||||
public Boolean Display_Degree_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display minute symbols.
|
||||
/// </summary>
|
||||
public Boolean Display_Minute_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display secons symbol.
|
||||
/// </summary>
|
||||
public Boolean Display_Seconds_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display hyphens between values.
|
||||
/// </summary>
|
||||
public Boolean Display_Hyphens { get; set; }
|
||||
/// <summary>
|
||||
/// Show coordinate position first.
|
||||
/// Will show last if set 'false'.
|
||||
/// </summary>
|
||||
public Boolean Position_First { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Coordinate Format Types.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinateFormatType {
|
||||
/// <summary>
|
||||
/// Decimal Degree Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40.456 W 75.456
|
||||
/// </remarks>
|
||||
Decimal_Degree,
|
||||
/// <summary>
|
||||
/// Decimal Degree Minutes Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40º 34.552' W 70º 45.408'
|
||||
/// </remarks>
|
||||
Degree_Decimal_Minutes,
|
||||
/// <summary>
|
||||
/// Decimal Degree Minutes Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40º 34" 36.552' W 70º 45" 24.408'
|
||||
/// </remarks>
|
||||
Degree_Minutes_Seconds,
|
||||
/// <summary>
|
||||
/// Decimal Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: 40.57674 -70.46574
|
||||
/// </remarks>
|
||||
Decimal
|
||||
}
|
||||
}
|
||||
|
@ -1,293 +1,221 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
namespace CoordinateSharp {
|
||||
/// <summary>
|
||||
/// Military Grid Reference System (MGRS). Uses the WGS 84 Datum.
|
||||
/// Relies upon values from the UniversalTransverseMercator class
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MilitaryGridReferenceSystem : INotifyPropertyChanged {
|
||||
/// <summary>
|
||||
/// Military Grid Reference System (MGRS). Uses the WGS 84 Datum.
|
||||
/// Relies upon values from the UniversalTransverseMercator class
|
||||
/// Create an MGRS object with WGS84 datum
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MilitaryGridReferenceSystem : INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an MGRS object with WGS84 datum
|
||||
/// </summary>
|
||||
/// <param name="latz">Lat Zone</param>
|
||||
/// <param name="longz">Long Zone</param>
|
||||
/// <param name="d">Digraph</param>
|
||||
/// <param name="e">Easting</param>
|
||||
/// <param name="n">Northing</param>
|
||||
public MilitaryGridReferenceSystem(string latz, int longz, string d, double e, double n)
|
||||
{
|
||||
string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
latZone = latz;
|
||||
longZone = longz;
|
||||
digraph = d;
|
||||
easting = e;
|
||||
northing = n;
|
||||
//WGS84
|
||||
equatorialRadius = 6378137.0;
|
||||
inverseFlattening = 298.257223563;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Create an MGRS object with custom datum
|
||||
/// </summary>
|
||||
/// <param name="latz">Lat Zone</param>
|
||||
/// <param name="longz">Long Zone</param>
|
||||
/// <param name="d">Digraph</param>
|
||||
/// <param name="e">Easting</param>
|
||||
/// <param name="n">Northing</param>
|
||||
/// <param name="rad">Equatorial Radius</param>
|
||||
/// <param name="flt">Inverse Flattening</param>
|
||||
public MilitaryGridReferenceSystem(string latz, int longz, string d, double e, double n,double rad, double flt)
|
||||
{
|
||||
string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
latZone = latz;
|
||||
longZone = longz;
|
||||
digraph = d;
|
||||
easting = e;
|
||||
northing = n;
|
||||
|
||||
equatorialRadius = rad;
|
||||
inverseFlattening = flt;
|
||||
}
|
||||
/// <param name="latz">Lat Zone</param>
|
||||
/// <param name="longz">Long Zone</param>
|
||||
/// <param name="d">Digraph</param>
|
||||
/// <param name="e">Easting</param>
|
||||
/// <param name="n">Northing</param>
|
||||
public MilitaryGridReferenceSystem(String latz, Int32 longz, String d, Double e, Double n) {
|
||||
String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if (!this.Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
this.LatZone = latz;
|
||||
this.LongZone = longz;
|
||||
this.Digraph = d;
|
||||
this.Easting = e;
|
||||
this.Northing = n;
|
||||
//WGS84
|
||||
this.equatorialRadius = 6378137.0;
|
||||
this.inverseFlattening = 298.257223563;
|
||||
|
||||
private double equatorialRadius;
|
||||
private double inverseFlattening;
|
||||
private string latZone;
|
||||
private int longZone;
|
||||
private double easting;
|
||||
private double northing;
|
||||
private string digraph;
|
||||
|
||||
private bool withinCoordinateSystemBounds=true;
|
||||
|
||||
private bool Verify_Lat_Zone(string l)
|
||||
{
|
||||
if (LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Zone Letter
|
||||
/// </summary>
|
||||
public string LatZone
|
||||
{
|
||||
get { return latZone; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// MGRS Zone Number
|
||||
/// </summary>
|
||||
public int LongZone
|
||||
{
|
||||
get { return longZone; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// MGRS Easting
|
||||
/// </summary>
|
||||
public double Easting
|
||||
{
|
||||
get { return easting; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// MGRS Northing
|
||||
/// </summary>
|
||||
public double Northing
|
||||
{
|
||||
get { return northing; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// MGRS Digraph
|
||||
/// </summary>
|
||||
public string Digraph
|
||||
{
|
||||
get { return digraph; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is MGRS conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
|
||||
/// </summary>
|
||||
public bool WithinCoordinateSystemBounds
|
||||
{
|
||||
get { return withinCoordinateSystemBounds; }
|
||||
}
|
||||
|
||||
|
||||
internal MilitaryGridReferenceSystem(UniversalTransverseMercator utm)
|
||||
{
|
||||
ToMGRS(utm);
|
||||
}
|
||||
internal void ToMGRS(UniversalTransverseMercator utm)
|
||||
{
|
||||
Digraphs digraphs = new Digraphs();
|
||||
|
||||
string digraph1 = digraphs.getDigraph1(utm.LongZone, utm.Easting);
|
||||
string digraph2 = digraphs.getDigraph2(utm.LongZone, utm.Northing);
|
||||
|
||||
digraph = digraph1 + digraph2;
|
||||
latZone = utm.LatZone;
|
||||
longZone = utm.LongZone;
|
||||
|
||||
//String easting = String.valueOf((int)_easting);
|
||||
string e = ((int)utm.Easting).ToString();
|
||||
if (e.Length < 5)
|
||||
{
|
||||
e = "00000" + ((int)utm.Easting).ToString();
|
||||
}
|
||||
e = e.Substring(e.Length - 5);
|
||||
|
||||
easting = Convert.ToInt32(e);
|
||||
|
||||
string n = ((int)utm.Northing).ToString();
|
||||
if (n.Length < 5)
|
||||
{
|
||||
n = "0000" + ((int)utm.Northing).ToString();
|
||||
}
|
||||
n = n.Substring(n.Length - 5);
|
||||
|
||||
northing = Convert.ToInt32(n);
|
||||
equatorialRadius = utm.equatorial_radius;
|
||||
inverseFlattening = utm.inverse_flattening;
|
||||
|
||||
withinCoordinateSystemBounds = utm.WithinCoordinateSystemBounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Coordinate object from an MGRS/NATO UTM Coordinate
|
||||
/// </summary>
|
||||
/// <param name="mgrs">MilitaryGridReferenceSystem</param>
|
||||
/// <returns>Coordinate object</returns>
|
||||
public static Coordinate MGRStoLatLong(MilitaryGridReferenceSystem mgrs)
|
||||
{
|
||||
string latz = mgrs.LatZone;
|
||||
string digraph = mgrs.Digraph;
|
||||
|
||||
char eltr = digraph[0];
|
||||
char nltr = digraph[1];
|
||||
|
||||
string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
string digraphLettersAll="";
|
||||
for (int lt = 1; lt < 25; lt++)
|
||||
{
|
||||
digraphLettersAll += "ABCDEFGHJKLMNPQRSTUV";
|
||||
}
|
||||
|
||||
var eidx = digraphLettersE.IndexOf(eltr);
|
||||
var nidx = digraphLettersN.IndexOf(nltr);
|
||||
if (mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0))
|
||||
{
|
||||
nidx -= 5; // correction for even numbered zones
|
||||
}
|
||||
|
||||
var ebase = 100000 * (1 + eidx - 8 * Math.Floor(Convert.ToDouble(eidx) / 8));
|
||||
var latBand = digraphLettersE.IndexOf(latz);
|
||||
var latBandLow = 8 * latBand - 96;
|
||||
var latBandHigh = 8 * latBand - 88;
|
||||
|
||||
if (latBand < 2)
|
||||
{
|
||||
latBandLow = -90;
|
||||
latBandHigh = -80;
|
||||
}
|
||||
else if (latBand == 21)
|
||||
{
|
||||
latBandLow = 72;
|
||||
latBandHigh = 84;
|
||||
}
|
||||
else if (latBand > 21)
|
||||
{
|
||||
latBandLow = 84;
|
||||
latBandHigh = 90;
|
||||
}
|
||||
|
||||
var lowLetter = Math.Floor(100 + 1.11 * latBandLow);
|
||||
var highLetter = Math.Round(100 + 1.11 * latBandHigh);
|
||||
|
||||
string latBandLetters = null;
|
||||
int l = Convert.ToInt32(lowLetter);
|
||||
int h = Convert.ToInt32(highLetter);
|
||||
if (mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0))
|
||||
{
|
||||
latBandLetters = digraphLettersAll.Substring(l + 5, h + 5).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
latBandLetters = digraphLettersAll.Substring(l, h).ToString();
|
||||
}
|
||||
var nbase = 100000 * (lowLetter + latBandLetters.IndexOf(nltr));
|
||||
//latBandLetters.IndexOf(nltr) value causing incorrect Northing below -80
|
||||
var x = ebase + mgrs.Easting;
|
||||
var y = nbase + mgrs.Northing;
|
||||
if (y > 10000000)
|
||||
{
|
||||
y = y - 10000000;
|
||||
}
|
||||
if (nbase >= 10000000)
|
||||
{
|
||||
y = nbase + mgrs.northing - 10000000;
|
||||
}
|
||||
|
||||
var southern = nbase < 10000000;
|
||||
UniversalTransverseMercator utm = new UniversalTransverseMercator(mgrs.LatZone, mgrs.LongZone, x, y);
|
||||
utm.equatorial_radius = mgrs.equatorialRadius;
|
||||
utm.inverse_flattening = mgrs.inverseFlattening;
|
||||
Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
|
||||
|
||||
c.Set_Datum(mgrs.equatorialRadius, mgrs.inverseFlattening);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Default String Format
|
||||
/// </summary>
|
||||
/// <returns>MGRS Formatted Coordinate String</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (!withinCoordinateSystemBounds) { return ""; }//MGRS Coordinate is outside its reliable boundaries. Return empty.
|
||||
return longZone.ToString() + LatZone + " " + digraph + " " + ((int)easting).ToString("00000") + " " + ((int)northing).ToString("00000");
|
||||
}
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(string propName)
|
||||
{
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Create an MGRS object with custom datum
|
||||
/// </summary>
|
||||
/// <param name="latz">Lat Zone</param>
|
||||
/// <param name="longz">Long Zone</param>
|
||||
/// <param name="d">Digraph</param>
|
||||
/// <param name="e">Easting</param>
|
||||
/// <param name="n">Northing</param>
|
||||
/// <param name="rad">Equatorial Radius</param>
|
||||
/// <param name="flt">Inverse Flattening</param>
|
||||
public MilitaryGridReferenceSystem(String latz, Int32 longz, String d, Double e, Double n, Double rad, Double flt) {
|
||||
String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if (!this.Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
this.LatZone = latz;
|
||||
this.LongZone = longz;
|
||||
this.Digraph = d;
|
||||
this.Easting = e;
|
||||
this.Northing = n;
|
||||
|
||||
this.equatorialRadius = rad;
|
||||
this.inverseFlattening = flt;
|
||||
}
|
||||
|
||||
private Double equatorialRadius;
|
||||
private Double inverseFlattening;
|
||||
|
||||
private Boolean Verify_Lat_Zone(String l) => LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() == 1;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Zone Letter
|
||||
/// </summary>
|
||||
public String LatZone { get; private set; }
|
||||
/// <summary>
|
||||
/// MGRS Zone Number
|
||||
/// </summary>
|
||||
public Int32 LongZone { get; private set; }
|
||||
/// <summary>
|
||||
/// MGRS Easting
|
||||
/// </summary>
|
||||
public Double Easting { get; private set; }
|
||||
/// <summary>
|
||||
/// MGRS Northing
|
||||
/// </summary>
|
||||
public Double Northing { get; private set; }
|
||||
/// <summary>
|
||||
/// MGRS Digraph
|
||||
/// </summary>
|
||||
public String Digraph { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is MGRS conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
|
||||
/// </summary>
|
||||
public Boolean WithinCoordinateSystemBounds { get; private set; } = true;
|
||||
|
||||
|
||||
internal MilitaryGridReferenceSystem(UniversalTransverseMercator utm) => this.ToMGRS(utm);
|
||||
internal void ToMGRS(UniversalTransverseMercator utm) {
|
||||
Digraphs digraphs = new Digraphs();
|
||||
|
||||
String digraph1 = digraphs.GetDigraph1(utm.LongZone, utm.Easting);
|
||||
String digraph2 = digraphs.GetDigraph2(utm.LongZone, utm.Northing);
|
||||
|
||||
this.Digraph = digraph1 + digraph2;
|
||||
this.LatZone = utm.LatZone;
|
||||
this.LongZone = utm.LongZone;
|
||||
|
||||
//String easting = String.valueOf((int)_easting);
|
||||
String e = ((Int32)utm.Easting).ToString();
|
||||
if (e.Length < 5) {
|
||||
e = "00000" + ((Int32)utm.Easting).ToString();
|
||||
}
|
||||
e = e.Substring(e.Length - 5);
|
||||
|
||||
this.Easting = Convert.ToInt32(e);
|
||||
|
||||
String n = ((Int32)utm.Northing).ToString();
|
||||
if (n.Length < 5) {
|
||||
n = "0000" + ((Int32)utm.Northing).ToString();
|
||||
}
|
||||
n = n.Substring(n.Length - 5);
|
||||
|
||||
this.Northing = Convert.ToInt32(n);
|
||||
this.equatorialRadius = utm.equatorial_radius;
|
||||
this.inverseFlattening = utm.inverse_flattening;
|
||||
|
||||
this.WithinCoordinateSystemBounds = utm.WithinCoordinateSystemBounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Coordinate object from an MGRS/NATO UTM Coordinate
|
||||
/// </summary>
|
||||
/// <param name="mgrs">MilitaryGridReferenceSystem</param>
|
||||
/// <returns>Coordinate object</returns>
|
||||
public static Coordinate MGRStoLatLong(MilitaryGridReferenceSystem mgrs) {
|
||||
String latz = mgrs.LatZone;
|
||||
String digraph = mgrs.Digraph;
|
||||
|
||||
Char eltr = digraph[0];
|
||||
Char nltr = digraph[1];
|
||||
|
||||
String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
//String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
String digraphLettersAll = "";
|
||||
for (Int32 lt = 1; lt < 25; lt++) {
|
||||
digraphLettersAll += "ABCDEFGHJKLMNPQRSTUV";
|
||||
}
|
||||
|
||||
Int32 eidx = digraphLettersE.IndexOf(eltr);
|
||||
//Int32 nidx = digraphLettersN.IndexOf(nltr);
|
||||
if (mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0)) {
|
||||
//nidx -= 5; // correction for even numbered zones
|
||||
}
|
||||
|
||||
Double ebase = 100000 * (1 + eidx - 8 * Math.Floor(Convert.ToDouble(eidx) / 8));
|
||||
Int32 latBand = digraphLettersE.IndexOf(latz);
|
||||
Int32 latBandLow = 8 * latBand - 96;
|
||||
Int32 latBandHigh = 8 * latBand - 88;
|
||||
|
||||
if (latBand < 2) {
|
||||
latBandLow = -90;
|
||||
latBandHigh = -80;
|
||||
} else if (latBand == 21) {
|
||||
latBandLow = 72;
|
||||
latBandHigh = 84;
|
||||
} else if (latBand > 21) {
|
||||
latBandLow = 84;
|
||||
latBandHigh = 90;
|
||||
}
|
||||
|
||||
Double lowLetter = Math.Floor(100 + 1.11 * latBandLow);
|
||||
Double highLetter = Math.Round(100 + 1.11 * latBandHigh);
|
||||
Int32 l = Convert.ToInt32(lowLetter);
|
||||
Int32 h = Convert.ToInt32(highLetter);
|
||||
|
||||
String latBandLetters = mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0) ? digraphLettersAll.Substring(l + 5, h + 5).ToString() : digraphLettersAll.Substring(l, h).ToString();
|
||||
Double nbase = 100000 * (lowLetter + latBandLetters.IndexOf(nltr));
|
||||
//latBandLetters.IndexOf(nltr) value causing incorrect Northing below -80
|
||||
Double x = ebase + mgrs.Easting;
|
||||
Double y = nbase + mgrs.Northing;
|
||||
if (y > 10000000) {
|
||||
y -= 10000000;
|
||||
}
|
||||
if (nbase >= 10000000) {
|
||||
y = nbase + mgrs.Northing - 10000000;
|
||||
}
|
||||
|
||||
_ = nbase < 10000000;
|
||||
UniversalTransverseMercator utm = new UniversalTransverseMercator(mgrs.LatZone, mgrs.LongZone, x, y) {
|
||||
equatorial_radius = mgrs.equatorialRadius,
|
||||
inverse_flattening = mgrs.inverseFlattening
|
||||
};
|
||||
Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
|
||||
|
||||
c.Set_Datum(mgrs.equatorialRadius, mgrs.inverseFlattening);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Default String Format
|
||||
/// </summary>
|
||||
/// <returns>MGRS Formatted Coordinate String</returns>
|
||||
public override String ToString() => !this.WithinCoordinateSystemBounds ? "" : this.LongZone.ToString() + this.LatZone + " " + this.Digraph + " " + ((Int32)this.Easting).ToString("00000") + " " + ((Int32)this.Northing).ToString("00000");
|
||||
//MGRS Coordinate is outside its reliable boundaries. Return empty.
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(String propName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -34,8 +34,7 @@ SOFTWARE.
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
namespace CoordinateSharp {
|
||||
/// <summary>
|
||||
/// Observable class for handling all location based information.
|
||||
/// This is the main class for CoordinateSharp.
|
||||
@ -44,16 +43,14 @@ namespace CoordinateSharp
|
||||
/// All information should be pulled from this class to include celestial information
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
public class Coordinate : INotifyPropertyChanged
|
||||
{
|
||||
public class Coordinate : INotifyPropertyChanged {
|
||||
/// <summary>
|
||||
/// Creates an empty Coordinate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Values will need to be provided to latitude/longitude CoordinateParts manually
|
||||
/// </remarks>
|
||||
public Coordinate()
|
||||
{
|
||||
public Coordinate() {
|
||||
this.FormatOptions = new CoordinateFormatOptions();
|
||||
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
this.latitude = new CoordinatePart(CoordinateType.Lat);
|
||||
@ -77,8 +74,7 @@ namespace CoordinateSharp
|
||||
/// <remarks>
|
||||
/// Values will need to be provided to latitude/longitude CoordinateParts manually
|
||||
/// </remarks>
|
||||
internal Coordinate(Double equatorialRadius, Double inverseFlattening, Boolean t)
|
||||
{
|
||||
internal Coordinate(Double equatorialRadius, Double inverseFlattening, Boolean _) {
|
||||
this.FormatOptions = new CoordinateFormatOptions();
|
||||
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
this.latitude = new CoordinatePart(CoordinateType.Lat);
|
||||
@ -102,8 +98,7 @@ namespace CoordinateSharp
|
||||
/// <remarks>
|
||||
/// Geodate will default to 1/1/1900 GMT until provided
|
||||
/// </remarks>
|
||||
public Coordinate(Double lat, Double longi)
|
||||
{
|
||||
public Coordinate(Double lat, Double longi) {
|
||||
this.FormatOptions = new CoordinateFormatOptions();
|
||||
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
|
||||
@ -126,8 +121,7 @@ namespace CoordinateSharp
|
||||
/// <param name="lat">latitude</param>
|
||||
/// <param name="longi">longitude</param>
|
||||
/// <param name="date">DateTime (UTC)</param>
|
||||
public Coordinate(Double lat, Double longi, DateTime date)
|
||||
{
|
||||
public Coordinate(Double lat, Double longi, DateTime date) {
|
||||
this.FormatOptions = new CoordinateFormatOptions();
|
||||
this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
|
||||
this.longitude = new CoordinatePart(longi, CoordinateType.Long);
|
||||
@ -152,8 +146,7 @@ namespace CoordinateSharp
|
||||
/// Values will need to be provided to latitude/longitude manually
|
||||
/// </remarks>
|
||||
/// <param name="eagerLoad">Eager loading options</param>
|
||||
public Coordinate(EagerLoad eagerLoad)
|
||||
{
|
||||
public Coordinate(EagerLoad eagerLoad) {
|
||||
this.FormatOptions = new CoordinateFormatOptions();
|
||||
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
this.latitude = new CoordinatePart(CoordinateType.Lat);
|
||||
@ -188,8 +181,7 @@ namespace CoordinateSharp
|
||||
/// <param name="lat">latitude</param>
|
||||
/// <param name="longi">longitude</param>
|
||||
/// <param name="eagerLoad">Eager loading options</param>
|
||||
public Coordinate(Double lat, Double longi, EagerLoad eagerLoad)
|
||||
{
|
||||
public Coordinate(Double lat, Double longi, EagerLoad eagerLoad) {
|
||||
this.FormatOptions = new CoordinateFormatOptions();
|
||||
this.geoDate = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
|
||||
@ -223,8 +215,7 @@ namespace CoordinateSharp
|
||||
/// <param name="longi">Decimal format longitude</param>
|
||||
/// <param name="date">DateTime you wish to use for celestial calculation</param>
|
||||
/// <param name="eagerLoad">Eager loading options</param>
|
||||
public Coordinate(Double lat, Double longi, DateTime date, EagerLoad eagerLoad)
|
||||
{
|
||||
public Coordinate(Double lat, Double longi, DateTime date, EagerLoad eagerLoad) {
|
||||
this.FormatOptions = new CoordinateFormatOptions();
|
||||
this.latitude = new CoordinatePart(lat, CoordinateType.Lat);
|
||||
this.longitude = new CoordinatePart(longi, CoordinateType.Long);
|
||||
@ -261,8 +252,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Latitudinal Coordinate Part
|
||||
/// </summary>
|
||||
public CoordinatePart Latitude
|
||||
{
|
||||
public CoordinatePart Latitude {
|
||||
get => this.latitude;
|
||||
set {
|
||||
if (this.latitude != value) {
|
||||
@ -292,8 +282,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Longitudinal Coordinate Part
|
||||
/// </summary>
|
||||
public CoordinatePart Longitude
|
||||
{
|
||||
public CoordinatePart Longitude {
|
||||
get => this.longitude;
|
||||
set {
|
||||
if (this.longitude != value) {
|
||||
@ -325,8 +314,7 @@ namespace CoordinateSharp
|
||||
/// <remarks>
|
||||
/// Assumes all times are in UTC
|
||||
/// </remarks>
|
||||
public DateTime GeoDate
|
||||
{
|
||||
public DateTime GeoDate {
|
||||
get => this.geoDate;
|
||||
set {
|
||||
if (this.geoDate != value) {
|
||||
@ -357,8 +345,7 @@ namespace CoordinateSharp
|
||||
/// Uses Ellipsoidal height with no geoid model included.
|
||||
/// 0 = Mean Sea Level based on the provided Datum.
|
||||
/// </summary>
|
||||
public ECEF ECEF
|
||||
{
|
||||
public ECEF ECEF {
|
||||
get => this.ecef;
|
||||
|
||||
//Required due to GeoDetic Height
|
||||
@ -376,8 +363,7 @@ namespace CoordinateSharp
|
||||
/// Used to determine what format the coordinate was parsed from.
|
||||
/// Will equal "None" if Coordinate was not initialzed via a TryParse() method.
|
||||
/// </summary>
|
||||
public Parse_Format_Type Parse_Format
|
||||
{
|
||||
public Parse_Format_Type Parse_Format {
|
||||
get => this.parse_Format;
|
||||
internal set {
|
||||
if (this.parse_Format != value) {
|
||||
@ -399,8 +385,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Initialize UTM and MGRS information (required if eager loading is turned off).
|
||||
/// </summary>
|
||||
public void LoadUTM_MGRS_Info()
|
||||
{
|
||||
public void LoadUTM_MGRS_Info() {
|
||||
this.UTM = new UniversalTransverseMercator(this.latitude.ToDouble(), this.longitude.ToDouble(), this);
|
||||
this.MGRS = new MilitaryGridReferenceSystem(this.UTM);
|
||||
}
|
||||
@ -431,8 +416,7 @@ namespace CoordinateSharp
|
||||
/// Overridden Coordinate ToString() method.
|
||||
/// </summary>
|
||||
/// <returns>string (formatted).</returns>
|
||||
public override String ToString()
|
||||
{
|
||||
public override String ToString() {
|
||||
String latString = this.latitude.ToString();
|
||||
String longSting = this.longitude.ToString();
|
||||
return latString + " " + longSting;
|
||||
@ -444,8 +428,7 @@ namespace CoordinateSharp
|
||||
/// </summary>
|
||||
/// <param name="options">CoordinateFormatOptions</param>
|
||||
/// <returns>Custom formatted coordinate</returns>
|
||||
public String ToString(CoordinateFormatOptions options)
|
||||
{
|
||||
public String ToString(CoordinateFormatOptions options) {
|
||||
String latString = this.latitude.ToString(options);
|
||||
String longSting = this.longitude.ToString(options);
|
||||
return latString + " " + longSting;
|
||||
@ -458,8 +441,7 @@ namespace CoordinateSharp
|
||||
/// </summary>
|
||||
/// <param name="radius">Equatorial Radius</param>
|
||||
/// <param name="flat">Inverse Flattening</param>
|
||||
public void Set_Datum(Double radius, Double flat)
|
||||
{
|
||||
public void Set_Datum(Double radius, Double flat) {
|
||||
//WGS84
|
||||
//RADIUS 6378137.0;
|
||||
//FLATTENING 298.257223563;
|
||||
@ -487,8 +469,7 @@ namespace CoordinateSharp
|
||||
/// <param name="radius">Equatorial Radius</param>
|
||||
/// <param name="flat">Inverse Flattening</param>
|
||||
/// <param name="cd">Coordinate_Datum</param>
|
||||
public void Set_Datum(Double radius, Double flat, Coordinate_Datum cd)
|
||||
{
|
||||
public void Set_Datum(Double radius, Double flat, Coordinate_Datum cd) {
|
||||
//WGS84
|
||||
//RADIUS 6378137.0;
|
||||
//FLATTENING 298.257223563;
|
||||
@ -554,8 +535,7 @@ namespace CoordinateSharp
|
||||
/// //New Coordinate - N 25º 4' 54.517" E 24º 57' 29.189"
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void Move(Double distance, Double bearing, Shape shape)
|
||||
{
|
||||
public void Move(Double distance, Double bearing, Shape shape) {
|
||||
//Convert to Radians for formula
|
||||
Double lat1 = this.latitude.ToRadians();
|
||||
Double lon1 = this.longitude.ToRadians();
|
||||
@ -605,8 +585,7 @@ namespace CoordinateSharp
|
||||
/// //New Coordinate - N 24º 56' 21.526" E 25º 4' 23.944"
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void Move(Coordinate target, Double distance, Shape shape)
|
||||
{
|
||||
public void Move(Coordinate target, Double distance, Shape shape) {
|
||||
Distance d = new Distance(this, target, shape);
|
||||
//Convert to Radians for formula
|
||||
Double lat1 = this.latitude.ToRadians();
|
||||
@ -656,8 +635,7 @@ namespace CoordinateSharp
|
||||
/// //New Coordinate - N 25º 4' 54.517" E 24º 57' 29.189"
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void Move(Distance distance, Double bearing, Shape shape)
|
||||
{
|
||||
public void Move(Distance distance, Double bearing, Shape shape) {
|
||||
//Convert to Radians for formula
|
||||
Double lat1 = this.latitude.ToRadians();
|
||||
Double lon1 = this.longitude.ToRadians();
|
||||
@ -708,8 +686,7 @@ namespace CoordinateSharp
|
||||
/// //New Coordinate - N 24º 56' 21.526" E 25º 4' 23.944"
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void Move(Coordinate target, Distance distance, Shape shape)
|
||||
{
|
||||
public void Move(Coordinate target, Distance distance, Shape shape) {
|
||||
Distance d = new Distance(this, target, shape);
|
||||
//Convert to Radians for formula
|
||||
Double lat1 = this.latitude.ToRadians();
|
||||
@ -752,9 +729,7 @@ namespace CoordinateSharp
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static Boolean TryParse(String s, out Coordinate c)
|
||||
{
|
||||
c = null;
|
||||
public static Boolean TryParse(String s, out Coordinate c) {
|
||||
if (FormatFinder.TryParse(s, CartesianType.Cartesian, out c)) {
|
||||
Parse_Format_Type pft = c.Parse_Format;
|
||||
c = new Coordinate(c.Latitude.ToDouble(), c.Longitude.ToDouble()) {
|
||||
@ -781,9 +756,7 @@ namespace CoordinateSharp
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static Boolean TryParse(String s, DateTime geoDate, out Coordinate c)
|
||||
{
|
||||
c = null;
|
||||
public static Boolean TryParse(String s, DateTime geoDate, out Coordinate c) {
|
||||
if (FormatFinder.TryParse(s, CartesianType.Cartesian, out c)) {
|
||||
Parse_Format_Type pft = c.Parse_Format;
|
||||
c = new Coordinate(c.Latitude.ToDouble(), c.Longitude.ToDouble(), geoDate) {
|
||||
@ -810,9 +783,7 @@ namespace CoordinateSharp
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static Boolean TryParse(String s, CartesianType ct, out Coordinate c)
|
||||
{
|
||||
c = null;
|
||||
public static Boolean TryParse(String s, CartesianType ct, out Coordinate c) {
|
||||
if (FormatFinder.TryParse(s, ct, out c)) {
|
||||
Parse_Format_Type pft = c.Parse_Format;
|
||||
if (ct == CartesianType.ECEF) {
|
||||
@ -845,9 +816,7 @@ namespace CoordinateSharp
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static Boolean TryParse(String s, DateTime geoDate, CartesianType ct, out Coordinate c)
|
||||
{
|
||||
c = null;
|
||||
public static Boolean TryParse(String s, DateTime geoDate, CartesianType ct, out Coordinate c) {
|
||||
if (FormatFinder.TryParse(s, ct, out c)) {
|
||||
Parse_Format_Type pft = c.Parse_Format;
|
||||
if (ct == CartesianType.ECEF) {
|
||||
@ -872,8 +841,7 @@ namespace CoordinateSharp
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(String propName)
|
||||
{
|
||||
public void NotifyPropertyChanged(String propName) {
|
||||
switch (propName) {
|
||||
case "CelestialInfo":
|
||||
if (!this.EagerLoadSettings.Celestial || this.CelestialInfo == null) { return; } //Prevent Null Exceptions and calls while eagerloading is off
|
||||
@ -913,8 +881,7 @@ namespace CoordinateSharp
|
||||
/// Objects can be passed to Coordinate object Latitude and Longitude properties.
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
public class CoordinatePart : INotifyPropertyChanged
|
||||
{
|
||||
public class CoordinatePart : INotifyPropertyChanged {
|
||||
//Defaults:
|
||||
//Format: Degrees Minutes Seconds
|
||||
//Rounding: Dependent upon selected format
|
||||
@ -941,8 +908,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Observable decimal format coordinate.
|
||||
/// </summary>
|
||||
public Double DecimalDegree
|
||||
{
|
||||
public Double DecimalDegree {
|
||||
get => this.decimalDegree;
|
||||
set {
|
||||
//If changing, notify the needed property changes
|
||||
@ -1018,8 +984,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Observable decimal format minute.
|
||||
/// </summary>
|
||||
public Double DecimalMinute
|
||||
{
|
||||
public Double DecimalMinute {
|
||||
get => this.decimalMinute;
|
||||
set {
|
||||
if (this.decimalMinute != value) {
|
||||
@ -1048,7 +1013,7 @@ namespace CoordinateSharp
|
||||
|
||||
Decimal newDM = decValue / 60; //divide decimalMinute by 60 to get storage value
|
||||
Decimal newDD = this.degrees + newDM;//Add new decimal value to the floor degree value to get new decimalDegree;
|
||||
if (this.decimalDegree < 0) { newDD = newDD * -1; } //Restore negative if needed
|
||||
if (this.decimalDegree < 0) { newDD *= -1; } //Restore negative if needed
|
||||
|
||||
this.decimalDegree = Convert.ToDouble(newDD); //Convert back to double for storage
|
||||
|
||||
@ -1064,8 +1029,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Observable coordinate degree.
|
||||
/// </summary>
|
||||
public Int32 Degrees
|
||||
{
|
||||
public Int32 Degrees {
|
||||
get => this.degrees;
|
||||
set {
|
||||
//Validate Value
|
||||
@ -1105,8 +1069,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Observable coordinate minute.
|
||||
/// </summary>
|
||||
public Int32 Minutes
|
||||
{
|
||||
public Int32 Minutes {
|
||||
get => this.minutes;
|
||||
set {
|
||||
if (this.minutes != value) {
|
||||
@ -1114,9 +1077,9 @@ namespace CoordinateSharp
|
||||
//Validate the minutes
|
||||
Decimal vMin = Convert.ToDecimal(value);
|
||||
if (this.type == CoordinateType.Lat) {
|
||||
if (this.degrees + (vMin / 60) > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal degrees cannot be greater than 90"); }
|
||||
if (this.degrees + vMin / 60 > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal degrees cannot be greater than 90"); }
|
||||
} else {
|
||||
if (this.degrees + (vMin / 60) > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal degrees cannot be greater than 180"); }
|
||||
if (this.degrees + vMin / 60 > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal degrees cannot be greater than 180"); }
|
||||
}
|
||||
if (value >= 60) {
|
||||
throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60");
|
||||
@ -1154,8 +1117,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Observable coordinate second.
|
||||
/// </summary>
|
||||
public Double Seconds
|
||||
{
|
||||
public Double Seconds {
|
||||
get => this.seconds;
|
||||
set {
|
||||
if (value < 0) { value *= -1; }//Adjust accidental negative input
|
||||
@ -1182,9 +1144,9 @@ namespace CoordinateSharp
|
||||
this.seconds = value;
|
||||
|
||||
|
||||
Double degABS = Math.Abs(this.decimalDegree); //Make decimalDegree positive
|
||||
Double degFloor = Math.Truncate(degABS); //Truncate the number left of the decimal
|
||||
Decimal f = Convert.ToDecimal(degFloor); //Convert to decimal to keep precision
|
||||
//Double degABS = Math.Abs(this.decimalDegree); //Make decimalDegree positive
|
||||
//Double degFloor = Math.Truncate(degABS); //Truncate the number left of the decimal
|
||||
//Decimal f = Convert.ToDecimal(degFloor); //Convert to decimal to keep precision
|
||||
|
||||
Decimal secs = Convert.ToDecimal(this.seconds); //Convert seconds to decimal for calculations
|
||||
secs /= 60; //Convert to storage format
|
||||
@ -1207,8 +1169,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Observable coordinate position.
|
||||
/// </summary>
|
||||
public CoordinatesPosition Position
|
||||
{
|
||||
public CoordinatesPosition Position {
|
||||
get => this.position;
|
||||
set {
|
||||
if (this.position != value) {
|
||||
@ -1231,8 +1192,7 @@ namespace CoordinateSharp
|
||||
/// <param name="t">CoordinateType</param>
|
||||
/// <param name="c">Parent Coordinate object</param>
|
||||
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")]
|
||||
public CoordinatePart(CoordinateType t, Coordinate c)
|
||||
{
|
||||
public CoordinatePart(CoordinateType t, Coordinate c) {
|
||||
this.parent = c;
|
||||
this.type = t;
|
||||
this.decimalDegree = 0;
|
||||
@ -1248,8 +1208,7 @@ namespace CoordinateSharp
|
||||
/// <param name="t">Coordinate type</param>
|
||||
/// <param name="c">Parent Coordinate object</param>
|
||||
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")]
|
||||
public CoordinatePart(Double value, CoordinateType t, Coordinate c)
|
||||
{
|
||||
public CoordinatePart(Double value, CoordinateType t, Coordinate c) {
|
||||
this.parent = c;
|
||||
this.type = t;
|
||||
|
||||
@ -1287,8 +1246,7 @@ namespace CoordinateSharp
|
||||
/// <param name="pos">Coordinate Part Position</param>
|
||||
/// <param name="c">Parent Coordinate</param>
|
||||
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")]
|
||||
public CoordinatePart(Int32 deg, Int32 min, Double sec, CoordinatesPosition pos, Coordinate c)
|
||||
{
|
||||
public CoordinatePart(Int32 deg, Int32 min, Double sec, CoordinatesPosition pos, Coordinate c) {
|
||||
this.parent = c;
|
||||
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
|
||||
|
||||
@ -1308,12 +1266,12 @@ namespace CoordinateSharp
|
||||
minD += secD; //Decimal Minutes
|
||||
|
||||
if (this.type == CoordinateType.Long) {
|
||||
if (deg + (minD / 60) > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal Degrees cannot be greater than 180."); }
|
||||
if (deg + minD / 60 > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal Degrees cannot be greater than 180."); }
|
||||
} else {
|
||||
if (deg + (minD / 60) > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal Degrees cannot be greater than 90."); }
|
||||
if (deg + minD / 60 > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal Degrees cannot be greater than 90."); }
|
||||
}
|
||||
this.decimalMinute = Convert.ToDouble(minD);
|
||||
Decimal dd = Convert.ToDecimal(deg) + (minD / 60);
|
||||
Decimal dd = Convert.ToDecimal(deg) + minD / 60;
|
||||
|
||||
|
||||
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
|
||||
@ -1329,8 +1287,7 @@ namespace CoordinateSharp
|
||||
/// <param name="pos">Coordinate Part Position</param>
|
||||
/// <param name="c">Parent Coordinate object</param>
|
||||
[Obsolete("Method is deprecated. You no longer need to pass a Coordinate object through the constructor.")]
|
||||
public CoordinatePart(Int32 deg, Double minSec, CoordinatesPosition pos, Coordinate c)
|
||||
{
|
||||
public CoordinatePart(Int32 deg, Double minSec, CoordinatesPosition pos, Coordinate c) {
|
||||
this.parent = c;
|
||||
|
||||
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
|
||||
@ -1341,9 +1298,9 @@ namespace CoordinateSharp
|
||||
if (minSec >= 60) { throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60."); }
|
||||
|
||||
if (this.type == CoordinateType.Lat) {
|
||||
if (deg + (minSec / 60) > 90) { throw new ArgumentOutOfRangeException("Degree out of range", "Latitudinal degrees cannot be greater than 90."); }
|
||||
if (deg + minSec / 60 > 90) { throw new ArgumentOutOfRangeException("Degree out of range", "Latitudinal degrees cannot be greater than 90."); }
|
||||
} else {
|
||||
if (deg + (minSec / 60) > 180) { throw new ArgumentOutOfRangeException("Degree out of range", "Longitudinal degrees cannot be greater than 180."); }
|
||||
if (deg + minSec / 60 > 180) { throw new ArgumentOutOfRangeException("Degree out of range", "Longitudinal degrees cannot be greater than 180."); }
|
||||
}
|
||||
this.degrees = deg;
|
||||
this.decimalMinute = minSec;
|
||||
@ -1356,7 +1313,7 @@ namespace CoordinateSharp
|
||||
sec *= 60;
|
||||
Decimal secD = Convert.ToDecimal(sec);
|
||||
this.seconds = Convert.ToDouble(secD);
|
||||
Decimal dd = deg + (minD / 60);
|
||||
Decimal dd = deg + minD / 60;
|
||||
|
||||
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
|
||||
dd *= -1;
|
||||
@ -1368,8 +1325,7 @@ namespace CoordinateSharp
|
||||
/// Creates an empty CoordinatePart.
|
||||
/// </summary>
|
||||
/// <param name="t">CoordinateType</param>
|
||||
public CoordinatePart(CoordinateType t)
|
||||
{
|
||||
public CoordinatePart(CoordinateType t) {
|
||||
this.type = t;
|
||||
this.decimalDegree = 0;
|
||||
this.degrees = 0;
|
||||
@ -1382,8 +1338,7 @@ namespace CoordinateSharp
|
||||
/// </summary>
|
||||
/// <param name="value">Coordinate decimal value</param>
|
||||
/// <param name="t">Coordinate type</param>
|
||||
public CoordinatePart(Double value, CoordinateType t)
|
||||
{
|
||||
public CoordinatePart(Double value, CoordinateType t) {
|
||||
this.type = t;
|
||||
|
||||
if (this.type == CoordinateType.Long) {
|
||||
@ -1418,8 +1373,7 @@ namespace CoordinateSharp
|
||||
/// <param name="min">Minutes</param>
|
||||
/// <param name="sec">Seconds</param>
|
||||
/// <param name="pos">Coordinate Part Position</param>
|
||||
public CoordinatePart(Int32 deg, Int32 min, Double sec, CoordinatesPosition pos)
|
||||
{
|
||||
public CoordinatePart(Int32 deg, Int32 min, Double sec, CoordinatesPosition pos) {
|
||||
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
|
||||
|
||||
if (deg < 0) { throw new ArgumentOutOfRangeException("Degrees out of range", "Degrees cannot be less than 0."); }
|
||||
@ -1438,12 +1392,12 @@ namespace CoordinateSharp
|
||||
minD += secD; //Decimal Minutes
|
||||
|
||||
if (this.type == CoordinateType.Long) {
|
||||
if (deg + (minD / 60) > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal Degrees cannot be greater than 180."); }
|
||||
if (deg + minD / 60 > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal Degrees cannot be greater than 180."); }
|
||||
} else {
|
||||
if (deg + (minD / 60) > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal Degrees cannot be greater than 90."); }
|
||||
if (deg + minD / 60 > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal Degrees cannot be greater than 90."); }
|
||||
}
|
||||
this.decimalMinute = Convert.ToDouble(minD);
|
||||
Decimal dd = Convert.ToDecimal(deg) + (minD / 60);
|
||||
Decimal dd = Convert.ToDecimal(deg) + minD / 60;
|
||||
|
||||
|
||||
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
|
||||
@ -1457,8 +1411,7 @@ namespace CoordinateSharp
|
||||
/// <param name="deg">Degrees</param>
|
||||
/// <param name="minSec">Decimal Minutes</param>
|
||||
/// <param name="pos">Coordinate Part Position</param>
|
||||
public CoordinatePart(Int32 deg, Double minSec, CoordinatesPosition pos)
|
||||
{
|
||||
public CoordinatePart(Int32 deg, Double minSec, CoordinatesPosition pos) {
|
||||
this.type = pos == CoordinatesPosition.N || pos == CoordinatesPosition.S ? CoordinateType.Lat : CoordinateType.Long;
|
||||
|
||||
if (deg < 0) { throw new ArgumentOutOfRangeException("Degree out of range", "Degree cannot be less than 0."); }
|
||||
@ -1467,9 +1420,9 @@ namespace CoordinateSharp
|
||||
if (minSec >= 60) { throw new ArgumentOutOfRangeException("Minutes out of range", "Minutes cannot be greater than or equal to 60."); }
|
||||
|
||||
if (this.type == CoordinateType.Lat) {
|
||||
if (deg + (minSec / 60) > 90) { throw new ArgumentOutOfRangeException("Degree out of range", "Latitudinal degrees cannot be greater than 90."); }
|
||||
if (deg + minSec / 60 > 90) { throw new ArgumentOutOfRangeException("Degree out of range", "Latitudinal degrees cannot be greater than 90."); }
|
||||
} else {
|
||||
if (deg + (minSec / 60) > 180) { throw new ArgumentOutOfRangeException("Degree out of range", "Longitudinal degrees cannot be greater than 180."); }
|
||||
if (deg + minSec / 60 > 180) { throw new ArgumentOutOfRangeException("Degree out of range", "Longitudinal degrees cannot be greater than 180."); }
|
||||
}
|
||||
this.degrees = deg;
|
||||
this.decimalMinute = minSec;
|
||||
@ -1482,7 +1435,7 @@ namespace CoordinateSharp
|
||||
sec *= 60;
|
||||
Decimal secD = Convert.ToDecimal(sec);
|
||||
this.seconds = Convert.ToDouble(secD);
|
||||
Decimal dd = deg + (minD / 60);
|
||||
Decimal dd = deg + minD / 60;
|
||||
|
||||
if (pos == CoordinatesPosition.S || pos == CoordinatesPosition.W) {
|
||||
dd *= -1;
|
||||
@ -1513,46 +1466,25 @@ namespace CoordinateSharp
|
||||
/// </summary>
|
||||
/// <param name="options">CoordinateFormatOptions</param>
|
||||
/// <returns>Formatted coordinate part string</returns>
|
||||
private String FormatString(CoordinateFormatOptions options)
|
||||
{
|
||||
ToStringType type = ToStringType.Degree_Minute_Second;
|
||||
Int32? rounding = null;
|
||||
Boolean lead = false;
|
||||
Boolean trail = false;
|
||||
Boolean hyphen = false;
|
||||
Boolean symbols = true;
|
||||
Boolean degreeSymbol = true;
|
||||
Boolean minuteSymbol = true;
|
||||
Boolean secondsSymbol = true;
|
||||
Boolean positionFirst = true;
|
||||
|
||||
private String FormatString(CoordinateFormatOptions options) {
|
||||
#region Assign Formatting Rules
|
||||
switch (options.Format) {
|
||||
case CoordinateFormatType.Degree_Minutes_Seconds:
|
||||
type = ToStringType.Degree_Minute_Second;
|
||||
break;
|
||||
case CoordinateFormatType.Degree_Decimal_Minutes:
|
||||
type = ToStringType.Degree_Decimal_Minute;
|
||||
break;
|
||||
case CoordinateFormatType.Decimal_Degree:
|
||||
type = ToStringType.Decimal_Degree;
|
||||
break;
|
||||
case CoordinateFormatType.Decimal:
|
||||
type = ToStringType.Decimal;
|
||||
break;
|
||||
default:
|
||||
type = ToStringType.Degree_Minute_Second;
|
||||
break;
|
||||
}
|
||||
rounding = options.Round;
|
||||
lead = options.Display_Leading_Zeros;
|
||||
trail = options.Display_Trailing_Zeros;
|
||||
symbols = options.Display_Symbols;
|
||||
degreeSymbol = options.Display_Degree_Symbol;
|
||||
minuteSymbol = options.Display_Minute_Symbol;
|
||||
secondsSymbol = options.Display_Seconds_Symbol;
|
||||
hyphen = options.Display_Hyphens;
|
||||
positionFirst = options.Position_First;
|
||||
ToStringType type = options.Format switch
|
||||
{
|
||||
CoordinateFormatType.Degree_Minutes_Seconds => ToStringType.Degree_Minute_Second,
|
||||
CoordinateFormatType.Degree_Decimal_Minutes => ToStringType.Degree_Decimal_Minute,
|
||||
CoordinateFormatType.Decimal_Degree => ToStringType.Decimal_Degree,
|
||||
CoordinateFormatType.Decimal => ToStringType.Decimal,
|
||||
_ => ToStringType.Degree_Minute_Second,
|
||||
};
|
||||
Int32? rounding = options.Round;
|
||||
Boolean lead = options.Display_Leading_Zeros;
|
||||
Boolean trail = options.Display_Trailing_Zeros;
|
||||
Boolean symbols = options.Display_Symbols;
|
||||
Boolean degreeSymbol = options.Display_Degree_Symbol;
|
||||
Boolean minuteSymbol = options.Display_Minute_Symbol;
|
||||
Boolean secondsSymbol = options.Display_Seconds_Symbol;
|
||||
Boolean hyphen = options.Display_Hyphens;
|
||||
Boolean positionFirst = options.Position_First;
|
||||
#endregion
|
||||
|
||||
switch (type) {
|
||||
@ -1576,8 +1508,7 @@ namespace CoordinateSharp
|
||||
return String.Empty;
|
||||
}
|
||||
//DMS Coordinate Format
|
||||
private String ToDegreeMinuteSecondString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean minuteSymbol, Boolean secondSymbol, Boolean hyphen, Boolean positionFirst)
|
||||
{
|
||||
private String ToDegreeMinuteSecondString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean minuteSymbol, Boolean secondSymbol, Boolean hyphen, Boolean positionFirst) {
|
||||
|
||||
String leadString = this.Leading_Trailing_Format(lead, false, rounding, this.Position);
|
||||
String d = String.Format(leadString, this.Degrees); // Degree String
|
||||
@ -1602,8 +1533,7 @@ namespace CoordinateSharp
|
||||
: d + ds + hs + minute + ms + hs + second + ss + hs + this.Position.ToString();
|
||||
}
|
||||
//DDM Coordinate Format
|
||||
private String ToDegreeDecimalMinuteString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean minuteSymbol, Boolean hyphen, Boolean positionFirst)
|
||||
{
|
||||
private String ToDegreeDecimalMinuteString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean minuteSymbol, Boolean hyphen, Boolean positionFirst) {
|
||||
String leadString = "{0:0";
|
||||
if (lead) {
|
||||
if (this.Position == CoordinatesPosition.E || this.Position == CoordinatesPosition.W) {
|
||||
@ -1646,8 +1576,7 @@ namespace CoordinateSharp
|
||||
|
||||
}
|
||||
////DD Coordinate Format
|
||||
private String ToDecimalDegreeString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean positionFirst, Boolean hyphen)
|
||||
{
|
||||
private String ToDecimalDegreeString(Int32 rounding, Boolean lead, Boolean trail, Boolean symbols, Boolean degreeSymbol, Boolean positionFirst, Boolean hyphen) {
|
||||
String degreeS = "";
|
||||
String hyph = " ";
|
||||
if (degreeSymbol) { degreeS = "º"; }
|
||||
@ -1672,15 +1601,14 @@ namespace CoordinateSharp
|
||||
}
|
||||
leadTrail += "}";
|
||||
|
||||
Double result = (this.Degrees) + (Convert.ToDouble(this.Minutes)) / 60 + (Convert.ToDouble(this.Seconds)) / 3600;
|
||||
Double result = this.Degrees + Convert.ToDouble(this.Minutes) / 60 + Convert.ToDouble(this.Seconds) / 3600;
|
||||
result = Math.Round(result, rounding);
|
||||
String d = String.Format(leadTrail, Math.Abs(result));
|
||||
return positionFirst ? this.Position.ToString() + hyph + d + degreeS : d + degreeS + hyph + this.Position.ToString();
|
||||
|
||||
}
|
||||
|
||||
private String Leading_Trailing_Format(Boolean isLead, Boolean isTrail, Int32 rounding, CoordinatesPosition? p = null)
|
||||
{
|
||||
private String Leading_Trailing_Format(Boolean isLead, Boolean isTrail, Int32 rounding, CoordinatesPosition? p = null) {
|
||||
String leadString = "{0:0";
|
||||
if (isLead) {
|
||||
if (p != null) {
|
||||
@ -1706,18 +1634,16 @@ namespace CoordinateSharp
|
||||
|
||||
}
|
||||
|
||||
private String FormatError(String argument, String rule) => "'" + argument + "' is not a valid argument for string format rule: " + rule + ".";
|
||||
//private String FormatError(String argument, String rule) => "'" + argument + "' is not a valid argument for string format rule: " + rule + ".";
|
||||
|
||||
private enum ToStringType
|
||||
{
|
||||
private enum ToStringType {
|
||||
Decimal_Degree, Degree_Decimal_Minute, Degree_Minute_Second, Decimal
|
||||
}
|
||||
/// <summary>
|
||||
/// Notify the correct properties and parent properties.
|
||||
/// </summary>
|
||||
/// <param name="p">Property Type</param>
|
||||
private void NotifyProperties(PropertyTypes p)
|
||||
{
|
||||
private void NotifyProperties(PropertyTypes p) {
|
||||
switch (p) {
|
||||
case PropertyTypes.DecimalDegree:
|
||||
this.NotifyPropertyChanged("DecimalDegree");
|
||||
@ -1786,8 +1712,7 @@ namespace CoordinateSharp
|
||||
/// <summary>
|
||||
/// Used for notifying the correct properties.
|
||||
/// </summary>
|
||||
private enum PropertyTypes
|
||||
{
|
||||
private enum PropertyTypes {
|
||||
DecimalDegree, DecimalMinute, Position, Degree, Minute, Second, FormatChange
|
||||
}
|
||||
|
||||
@ -1811,12 +1736,7 @@ namespace CoordinateSharp
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static Boolean TryParse(String s, out CoordinatePart cp)
|
||||
{
|
||||
cp = null;
|
||||
|
||||
return FormatFinder_CoordPart.TryParse(s, out cp) ? true : false;
|
||||
}
|
||||
public static Boolean TryParse(String s, out CoordinatePart cp) => FormatFinder_CoordPart.TryParse(s, out cp) ? true : false;
|
||||
/// <summary>
|
||||
/// Attempts to parse a string into a CoordinatePart.
|
||||
/// </summary>
|
||||
@ -1833,9 +1753,7 @@ namespace CoordinateSharp
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static Boolean TryParse(String s, CoordinateType t, out CoordinatePart cp)
|
||||
{
|
||||
cp = null;
|
||||
public static Boolean TryParse(String s, CoordinateType t, out CoordinatePart cp) {
|
||||
//Comma at beginning parses to long
|
||||
//Asterik forces lat
|
||||
s = t == CoordinateType.Long ? "," + s : "*" + s;
|
||||
|
12
CoordinateSharp/CoordinateSharp_Core.csproj
Normal file
12
CoordinateSharp/CoordinateSharp_Core.csproj
Normal 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>
|
@ -1,442 +1,382 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
|
||||
namespace CoordinateSharp {
|
||||
/// <summary>
|
||||
/// Contains distance values between two coordinates.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Distance {
|
||||
|
||||
/// <summary>
|
||||
/// Contains distance values between two coordinates.
|
||||
/// Initializes a distance object using Haversine (Spherical Earth).
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Distance
|
||||
{
|
||||
private double kilometers;
|
||||
private double miles;
|
||||
private double feet;
|
||||
private double meters;
|
||||
private double bearing;
|
||||
private double nauticalMiles;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a distance object using Haversine (Spherical Earth).
|
||||
/// </summary>
|
||||
/// <param name="c1">Coordinate 1</param>
|
||||
/// <param name="c2">Coordinate 2</param>
|
||||
public Distance(Coordinate c1, Coordinate c2)
|
||||
{
|
||||
Haversine(c1, c2);
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a distance object using Haversine (Spherical Earth) or Vincenty (Elliptical Earth).
|
||||
/// </summary>
|
||||
/// <param name="c1">Coordinate 1</param>
|
||||
/// <param name="c2">Coordinate 2</param>
|
||||
/// <param name="shape">Shape of earth</param>
|
||||
public Distance(Coordinate c1, Coordinate c2, Shape shape)
|
||||
{
|
||||
if (shape == Shape.Sphere)
|
||||
{
|
||||
Haversine(c1, c2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vincenty(c1, c2);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes distance object based on distance in KM
|
||||
/// </summary>
|
||||
/// <param name="km">Kilometers</param>
|
||||
public Distance(double km)
|
||||
{
|
||||
kilometers = km;
|
||||
meters = km * 1000;
|
||||
feet = meters * 3.28084;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
bearing = 0;//None specified
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializaes distance object based on specified distance and measurement type
|
||||
/// </summary>
|
||||
/// <param name="distance">Distance</param>
|
||||
/// <param name="type">Measurement type</param>
|
||||
|
||||
public Distance(double distance, DistanceType type)
|
||||
{
|
||||
bearing = 0;
|
||||
switch (type)
|
||||
{
|
||||
case DistanceType.Feet:
|
||||
feet = distance;
|
||||
meters = feet * 0.3048;
|
||||
kilometers = meters / 1000;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Kilometers:
|
||||
kilometers = distance;
|
||||
meters = kilometers * 1000;
|
||||
feet = meters * 3.28084;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Meters:
|
||||
meters = distance;
|
||||
kilometers = meters / 1000;
|
||||
feet = meters * 3.28084;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Miles:
|
||||
miles = distance;
|
||||
meters = miles * 1609.344;
|
||||
feet = meters * 3.28084;
|
||||
kilometers = meters / 1000;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.NauticalMiles:
|
||||
nauticalMiles = distance;
|
||||
meters = nauticalMiles * 1852.001;
|
||||
feet = meters * 3.28084;
|
||||
kilometers = meters / 1000;
|
||||
miles = meters * 0.000621371;
|
||||
break;
|
||||
default:
|
||||
kilometers = distance;
|
||||
meters = distance * 1000;
|
||||
feet = meters * 3.28084;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void Vincenty(Coordinate coord1, Coordinate coord2)
|
||||
{
|
||||
double lat1, lat2, lon1, lon2;
|
||||
double d, crs12, crs21;
|
||||
|
||||
|
||||
lat1 = coord1.Latitude.ToRadians();
|
||||
lat2 = coord2.Latitude.ToRadians();
|
||||
lon1 = coord1.Longitude.ToRadians() * -1; //REVERSE FOR CALC 2.1.1.1
|
||||
lon2 = coord2.Longitude.ToRadians() * -1; //REVERSE FOR CALC 2.1.1.1
|
||||
|
||||
//Ensure datums match between coords
|
||||
if ((coord1.equatorial_radius != coord2.equatorial_radius) || (coord1.inverse_flattening != coord2.inverse_flattening))
|
||||
{
|
||||
throw new InvalidOperationException("The datum set does not match between Coordinate objects.");
|
||||
}
|
||||
double[] ellipse = new double[] { coord1.equatorial_radius, coord1.inverse_flattening };
|
||||
|
||||
|
||||
// elliptic code
|
||||
double[] cde = Distance_Assistant.Dist_Ell(lat1, -lon1, lat2, -lon2, ellipse); // ellipse uses East negative
|
||||
crs12 = cde[1] * (180 / Math.PI); //Bearing
|
||||
crs21 = cde[2] * (180 / Math.PI); //Reverse Bearing
|
||||
d = cde[0]; //Distance
|
||||
|
||||
bearing = crs12;
|
||||
//reverseBearing = crs21;
|
||||
meters = d;
|
||||
kilometers = d / 1000;
|
||||
feet = d * 3.28084;
|
||||
miles = d * 0.000621371;
|
||||
nauticalMiles = d * 0.0005399565;
|
||||
|
||||
}
|
||||
|
||||
private void Haversine(Coordinate coord1, Coordinate coord2)
|
||||
{
|
||||
////RADIANS
|
||||
double lat1 = coord1.Latitude.ToRadians();
|
||||
double long1 = coord1.Longitude.ToRadians();
|
||||
double lat2 = coord2.Latitude.ToRadians();
|
||||
double long2 = coord2.Longitude.ToRadians();
|
||||
|
||||
//Distance Calcs
|
||||
double R = 6371000; //6378137.0;//6371e3; //meters
|
||||
double latRad = coord2.Latitude.ToRadians() - coord1.Latitude.ToRadians();
|
||||
double longRad = coord2.Longitude.ToRadians() - coord1.Longitude.ToRadians();
|
||||
|
||||
double a = Math.Sin(latRad / 2.0) * Math.Sin(latRad / 2.0) +
|
||||
Math.Cos(lat1) * Math.Cos(lat2) * Math.Sin(longRad / 2.0) * Math.Sin(longRad / 2.0);
|
||||
double cl = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
|
||||
double dist = R * cl;
|
||||
|
||||
//Get bearing
|
||||
double dLong = long2 - long1;
|
||||
double y = Math.Sin(dLong) * Math.Cos(lat2);
|
||||
double x = Math.Cos(lat1) * Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(dLong);
|
||||
double brng = Math.Atan2(y, x) * (180 / Math.PI); //Convert bearing back to degrees.
|
||||
|
||||
//if (brng < 0) { brng -= 180; brng = Math.Abs(brng); }
|
||||
brng = (brng + 360) % 360; //v2.1.1.1 NORMALIZE HEADING
|
||||
|
||||
kilometers = dist / 1000;
|
||||
meters = dist;
|
||||
feet = dist * 3.28084;
|
||||
miles = dist * 0.000621371;
|
||||
nauticalMiles = dist * 0.0005399565;
|
||||
bearing = brng;
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Kilometers
|
||||
/// </summary>
|
||||
public double Kilometers
|
||||
{
|
||||
get { return kilometers; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Statute Miles
|
||||
/// </summary>
|
||||
public double Miles
|
||||
{
|
||||
get { return miles; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Nautical Miles
|
||||
/// </summary>
|
||||
public double NauticalMiles
|
||||
{
|
||||
get { return nauticalMiles; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Meters
|
||||
/// </summary>
|
||||
public double Meters
|
||||
{
|
||||
get { return meters; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Feet
|
||||
/// </summary>
|
||||
public double Feet
|
||||
{
|
||||
get { return feet; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Initial Bearing from Coordinate 1 to Coordinate 2
|
||||
/// </summary>
|
||||
public double Bearing
|
||||
{
|
||||
get { return bearing; }
|
||||
}
|
||||
/// <param name="c1">Coordinate 1</param>
|
||||
/// <param name="c2">Coordinate 2</param>
|
||||
public Distance(Coordinate c1, Coordinate c2) => this.Haversine(c1, c2);
|
||||
/// <summary>
|
||||
/// Initializes a distance object using Haversine (Spherical Earth) or Vincenty (Elliptical Earth).
|
||||
/// </summary>
|
||||
/// <param name="c1">Coordinate 1</param>
|
||||
/// <param name="c2">Coordinate 2</param>
|
||||
/// <param name="shape">Shape of earth</param>
|
||||
public Distance(Coordinate c1, Coordinate c2, Shape shape) {
|
||||
if (shape == Shape.Sphere) {
|
||||
this.Haversine(c1, c2);
|
||||
} else {
|
||||
this.Vincenty(c1, c2);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance measurement type
|
||||
/// Initializes distance object based on distance in KM
|
||||
/// </summary>
|
||||
public enum DistanceType
|
||||
{
|
||||
/// <summary>
|
||||
/// Distance in Meters
|
||||
/// </summary>
|
||||
Meters,
|
||||
/// <summary>
|
||||
/// Distance in Kilometers
|
||||
/// </summary>
|
||||
Kilometers,
|
||||
/// <summary>
|
||||
/// Distance in Feet
|
||||
/// </summary>
|
||||
Feet,
|
||||
/// <summary>
|
||||
/// Distance in Statute Miles
|
||||
/// </summary>
|
||||
Miles,
|
||||
/// <summary>
|
||||
/// Distance in Nautical Miles
|
||||
/// </summary>
|
||||
NauticalMiles
|
||||
/// <param name="km">Kilometers</param>
|
||||
public Distance(Double km) {
|
||||
this.Kilometers = km;
|
||||
this.Meters = km * 1000;
|
||||
this.Feet = this.Meters * 3.28084;
|
||||
this.Miles = this.Meters * 0.000621371;
|
||||
this.NauticalMiles = this.Meters * 0.0005399565;
|
||||
this.Bearing = 0;//None specified
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializaes distance object based on specified distance and measurement type
|
||||
/// </summary>
|
||||
/// <param name="distance">Distance</param>
|
||||
/// <param name="type">Measurement type</param>
|
||||
|
||||
public Distance(Double distance, DistanceType type) {
|
||||
this.Bearing = 0;
|
||||
switch (type) {
|
||||
case DistanceType.Feet:
|
||||
this.Feet = distance;
|
||||
this.Meters = this.Feet * 0.3048;
|
||||
this.Kilometers = this.Meters / 1000;
|
||||
this.Miles = this.Meters * 0.000621371;
|
||||
this.NauticalMiles = this.Meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Kilometers:
|
||||
this.Kilometers = distance;
|
||||
this.Meters = this.Kilometers * 1000;
|
||||
this.Feet = this.Meters * 3.28084;
|
||||
this.Miles = this.Meters * 0.000621371;
|
||||
this.NauticalMiles = this.Meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Meters:
|
||||
this.Meters = distance;
|
||||
this.Kilometers = this.Meters / 1000;
|
||||
this.Feet = this.Meters * 3.28084;
|
||||
this.Miles = this.Meters * 0.000621371;
|
||||
this.NauticalMiles = this.Meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Miles:
|
||||
this.Miles = distance;
|
||||
this.Meters = this.Miles * 1609.344;
|
||||
this.Feet = this.Meters * 3.28084;
|
||||
this.Kilometers = this.Meters / 1000;
|
||||
this.NauticalMiles = this.Meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.NauticalMiles:
|
||||
this.NauticalMiles = distance;
|
||||
this.Meters = this.NauticalMiles * 1852.001;
|
||||
this.Feet = this.Meters * 3.28084;
|
||||
this.Kilometers = this.Meters / 1000;
|
||||
this.Miles = this.Meters * 0.000621371;
|
||||
break;
|
||||
default:
|
||||
this.Kilometers = distance;
|
||||
this.Meters = distance * 1000;
|
||||
this.Feet = this.Meters * 3.28084;
|
||||
this.Miles = this.Meters * 0.000621371;
|
||||
this.NauticalMiles = this.Meters * 0.0005399565;
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void Vincenty(Coordinate coord1, Coordinate coord2) {
|
||||
Double lat1, lat2, lon1, lon2;
|
||||
Double d, crs12;
|
||||
|
||||
|
||||
lat1 = coord1.Latitude.ToRadians();
|
||||
lat2 = coord2.Latitude.ToRadians();
|
||||
lon1 = coord1.Longitude.ToRadians() * -1; //REVERSE FOR CALC 2.1.1.1
|
||||
lon2 = coord2.Longitude.ToRadians() * -1; //REVERSE FOR CALC 2.1.1.1
|
||||
|
||||
//Ensure datums match between coords
|
||||
if (coord1.equatorial_radius != coord2.equatorial_radius || coord1.inverse_flattening != coord2.inverse_flattening) {
|
||||
throw new InvalidOperationException("The datum set does not match between Coordinate objects.");
|
||||
}
|
||||
Double[] ellipse = new Double[] { coord1.equatorial_radius, coord1.inverse_flattening };
|
||||
|
||||
|
||||
// elliptic code
|
||||
Double[] cde = Distance_Assistant.Dist_Ell(lat1, -lon1, lat2, -lon2, ellipse); // ellipse uses East negative
|
||||
crs12 = cde[1] * (180 / Math.PI); //Bearing
|
||||
_ = cde[2] * (180 / Math.PI); //Reverse Bearing
|
||||
d = cde[0]; //Distance
|
||||
|
||||
this.Bearing = crs12;
|
||||
//reverseBearing = crs21;
|
||||
this.Meters = d;
|
||||
this.Kilometers = d / 1000;
|
||||
this.Feet = d * 3.28084;
|
||||
this.Miles = d * 0.000621371;
|
||||
this.NauticalMiles = d * 0.0005399565;
|
||||
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class Distance_Assistant
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns new geodetic coordinate in radians
|
||||
/// </summary>
|
||||
/// <param name="glat1">Latitude in Radians</param>
|
||||
/// <param name="glon1">Longitude in Radians</param>
|
||||
/// <param name="faz">Bearing</param>
|
||||
/// <param name="s">Distance</param>
|
||||
/// <param name="ellipse">Earth Ellipse Values</param>
|
||||
/// <returns>double[]</returns>
|
||||
public static double[] Direct_Ell(double glat1, double glon1, double faz, double s, double[] ellipse)
|
||||
{
|
||||
glon1 *= -1; //REVERSE LONG FOR CALC 2.1.1.1
|
||||
double EPS = 0.00000000005;//Used to determine if starting at pole.
|
||||
double r, tu, sf, cf, b, cu, su, sa, c2a, x, c, d, y, sy = 0, cy = 0, cz = 0, e = 0;
|
||||
double glat2, glon2, f;
|
||||
private void Haversine(Coordinate coord1, Coordinate coord2) {
|
||||
////RADIANS
|
||||
Double lat1 = coord1.Latitude.ToRadians();
|
||||
Double long1 = coord1.Longitude.ToRadians();
|
||||
Double lat2 = coord2.Latitude.ToRadians();
|
||||
Double long2 = coord2.Longitude.ToRadians();
|
||||
|
||||
//Determine if near pole
|
||||
if ((Math.Abs(Math.Cos(glat1)) < EPS) && !(Math.Abs(Math.Sin(faz)) < EPS))
|
||||
{
|
||||
Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
|
||||
}
|
||||
//Distance Calcs
|
||||
Double R = 6371000; //6378137.0;//6371e3; //meters
|
||||
Double latRad = coord2.Latitude.ToRadians() - coord1.Latitude.ToRadians();
|
||||
Double longRad = coord2.Longitude.ToRadians() - coord1.Longitude.ToRadians();
|
||||
|
||||
Double a = Math.Sin(latRad / 2.0) * Math.Sin(latRad / 2.0) +
|
||||
Math.Cos(lat1) * Math.Cos(lat2) * Math.Sin(longRad / 2.0) * Math.Sin(longRad / 2.0);
|
||||
Double cl = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
|
||||
Double dist = R * cl;
|
||||
|
||||
double a = ellipse[0];//Equitorial Radius
|
||||
f = 1 / ellipse[1];//Flattening
|
||||
r = 1 - f;
|
||||
tu = r * Math.Tan(glat1);
|
||||
sf = Math.Sin(faz);
|
||||
cf = Math.Cos(faz);
|
||||
if (cf == 0)
|
||||
{
|
||||
b = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = 2.0 * Math.Atan2(tu, cf);
|
||||
}
|
||||
cu = 1.0 / Math.Sqrt(1 + tu * tu);
|
||||
su = tu * cu;
|
||||
sa = cu * sf;
|
||||
c2a = 1 - sa * sa;
|
||||
x = 1.0 + Math.Sqrt(1.0 + c2a * (1.0 / (r * r) - 1.0));
|
||||
x = (x - 2.0) / x;
|
||||
c = 1.0 - x;
|
||||
c = (x * x / 4.0 + 1.0) / c;
|
||||
d = (0.375 * x * x - 1.0) * x;
|
||||
tu = s / (r * a * c);
|
||||
y = tu;
|
||||
c = y + 1;
|
||||
while (Math.Abs(y - c) > EPS)
|
||||
{
|
||||
sy = Math.Sin(y);
|
||||
cy = Math.Cos(y);
|
||||
cz = Math.Cos(b + y);
|
||||
e = 2.0 * cz * cz - 1.0;
|
||||
c = y;
|
||||
x = e * cy;
|
||||
y = e + e - 1.0;
|
||||
y = (((sy * sy * 4.0 - 3.0) * y * cz * d / 6.0 + x) *
|
||||
d / 4.0 - cz) * sy * d + tu;
|
||||
}
|
||||
//Get bearing
|
||||
Double dLong = long2 - long1;
|
||||
Double y = Math.Sin(dLong) * Math.Cos(lat2);
|
||||
Double x = Math.Cos(lat1) * Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(dLong);
|
||||
Double brng = Math.Atan2(y, x) * (180 / Math.PI); //Convert bearing back to degrees.
|
||||
|
||||
b = cu * cy * cf - su * sy;
|
||||
c = r * Math.Sqrt(sa * sa + b * b);
|
||||
d = su * cy + cu * sy * cf;
|
||||
//if (brng < 0) { brng -= 180; brng = Math.Abs(brng); }
|
||||
brng = (brng + 360) % 360; //v2.1.1.1 NORMALIZE HEADING
|
||||
|
||||
glat2 = ModM.ModLat(Math.Atan2(d, c));
|
||||
c = cu * cy - su * sy * cf;
|
||||
x = Math.Atan2(sy * sf, c);
|
||||
c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
|
||||
d = ((e * cy * c + cz) * sy * c + y) * sa;
|
||||
glon2 = ModM.ModLon(glon1 + x - (1.0 - c) * d * f); //Adjust for IDL
|
||||
//baz = ModM.ModCrs(Math.Atan2(sa, b) + Math.PI);
|
||||
return new double[] { glat2, glon2 };
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns new geodetic coordinate in radians
|
||||
/// </summary>
|
||||
/// <param name="lat1">Latitude in radians</param>
|
||||
/// <param name="lon1">Longitude in radians</param>
|
||||
/// <param name="crs12">Bearing</param>
|
||||
/// <param name="d12">Distance</param>
|
||||
/// <returns>double[]</returns>
|
||||
public static double[] Direct(double lat1, double lon1, double crs12, double d12)
|
||||
{
|
||||
lon1 *= -1; //REVERSE LONG FOR CALC 2.1.1.1
|
||||
var EPS = 0.00000000005;//Used to determine if near pole.
|
||||
double dlon, lat, lon;
|
||||
d12 = d12 * 0.0005399565; //convert meter to nm
|
||||
d12 = d12 / (180 * 60 / Math.PI);//Convert to Radian
|
||||
//Determine if near pole
|
||||
if ((Math.Abs(Math.Cos(lat1)) < EPS) && !(Math.Abs(Math.Sin(crs12)) < EPS))
|
||||
{
|
||||
Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
|
||||
}
|
||||
|
||||
lat = Math.Asin(Math.Sin(lat1) * Math.Cos(d12) +
|
||||
Math.Cos(lat1) * Math.Sin(d12) * Math.Cos(crs12));
|
||||
if (Math.Abs(Math.Cos(lat)) < EPS)
|
||||
{
|
||||
lon = 0.0; //endpoint a pole
|
||||
}
|
||||
else
|
||||
{
|
||||
dlon = Math.Atan2(Math.Sin(crs12) * Math.Sin(d12) * Math.Cos(lat1),
|
||||
Math.Cos(d12) - Math.Sin(lat1) * Math.Sin(lat));
|
||||
lon = ModM.Mod(lon1 - dlon + Math.PI, 2 * Math.PI) - Math.PI;
|
||||
}
|
||||
|
||||
return new double[] { lat, lon };
|
||||
}
|
||||
public static double[] Dist_Ell(double glat1, double glon1, double glat2, double glon2, double[] ellipse)
|
||||
{
|
||||
double a = ellipse[0]; //Equitorial Radius
|
||||
double f = 1 / ellipse[1]; //Flattening
|
||||
|
||||
double r, tu1, tu2, cu1, su1, cu2, s1, b1, f1;
|
||||
double x = 0, sx = 0, cx = 0, sy = 0, cy = 0, y = 0, sa = 0, c2a = 0, cz = 0, e = 0, c = 0, d = 0;
|
||||
double EPS = 0.00000000005;
|
||||
double faz, baz, s;
|
||||
double iter = 1;
|
||||
double MAXITER = 100;
|
||||
if ((glat1 + glat2 == 0.0) && (Math.Abs(glon1 - glon2) == Math.PI))
|
||||
{
|
||||
Debug.WriteLine("Warning: Course and distance between antipodal points is undefined");
|
||||
glat1 = glat1 + 0.00001; // allow algorithm to complete
|
||||
}
|
||||
if (glat1 == glat2 && (glon1 == glon2 || Math.Abs(Math.Abs(glon1 - glon2) - 2 * Math.PI) < EPS))
|
||||
{
|
||||
Debug.WriteLine("Warning: Points 1 and 2 are identical- course undefined");
|
||||
//D
|
||||
//crs12
|
||||
//crs21
|
||||
return new double[] { 0, 0, Math.PI };
|
||||
}
|
||||
r = 1 - f;
|
||||
tu1 = r * Math.Tan(glat1);
|
||||
tu2 = r * Math.Tan(glat2);
|
||||
cu1 = 1.0 / Math.Sqrt(1.0 + tu1 * tu1);
|
||||
su1 = cu1 * tu1;
|
||||
cu2 = 1.0 / Math.Sqrt(1.0 + tu2 * tu2);
|
||||
s1 = cu1 * cu2;
|
||||
b1 = s1 * tu2;
|
||||
f1 = b1 * tu1;
|
||||
x = glon2 - glon1;
|
||||
d = x + 1; // force one pass
|
||||
while ((Math.Abs(d - x) > EPS) && (iter < MAXITER))
|
||||
{
|
||||
iter = iter + 1;
|
||||
sx = Math.Sin(x);
|
||||
cx = Math.Cos(x);
|
||||
tu1 = cu2 * sx;
|
||||
tu2 = b1 - su1 * cu2 * cx;
|
||||
sy = Math.Sqrt(tu1 * tu1 + tu2 * tu2);
|
||||
cy = s1 * cx + f1;
|
||||
y = Math.Atan2(sy, cy);
|
||||
sa = s1 * sx / sy;
|
||||
c2a = 1 - sa * sa;
|
||||
cz = f1 + f1;
|
||||
if (c2a > 0.0)
|
||||
{
|
||||
cz = cy - cz / c2a;
|
||||
}
|
||||
e = cz * cz * 2.0 - 1.0;
|
||||
c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
|
||||
d = x;
|
||||
x = ((e * cy * c + cz) * sy * c + y) * sa;
|
||||
x = (1.0 - c) * x * f + glon2 - glon1;
|
||||
}
|
||||
faz = ModM.ModCrs(Math.Atan2(tu1, tu2));
|
||||
baz = ModM.ModCrs(Math.Atan2(cu1 * sx, b1 * cx - su1 * cu2) + Math.PI);
|
||||
x = Math.Sqrt((1 / (r * r) - 1) * c2a + 1);
|
||||
x += 1;
|
||||
x = (x - 2.0) / x;
|
||||
c = 1.0 - x;
|
||||
c = (x * x / 4.0 + 1.0) / c;
|
||||
d = (0.375 * x * x - 1.0) * x;
|
||||
x = e * cy;
|
||||
s = ((((sy * sy * 4.0 - 3.0) * (1.0 - e - e) * cz * d / 6.0 - x) * d / 4.0 + cz) * sy * d + y) * c * a * r;
|
||||
|
||||
if (Math.Abs(iter - MAXITER) < EPS)
|
||||
{
|
||||
Debug.WriteLine("Warning: Distance algorithm did not converge");
|
||||
}
|
||||
|
||||
return new double[] { s, faz, baz };
|
||||
}
|
||||
this.Kilometers = dist / 1000;
|
||||
this.Meters = dist;
|
||||
this.Feet = dist * 3.28084;
|
||||
this.Miles = dist * 0.000621371;
|
||||
this.NauticalMiles = dist * 0.0005399565;
|
||||
this.Bearing = brng;
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Kilometers
|
||||
/// </summary>
|
||||
public Double Kilometers { get; private set; }
|
||||
/// <summary>
|
||||
/// Distance in Statute Miles
|
||||
/// </summary>
|
||||
public Double Miles { get; private set; }
|
||||
/// <summary>
|
||||
/// Distance in Nautical Miles
|
||||
/// </summary>
|
||||
public Double NauticalMiles { get; private set; }
|
||||
/// <summary>
|
||||
/// Distance in Meters
|
||||
/// </summary>
|
||||
public Double Meters { get; private set; }
|
||||
/// <summary>
|
||||
/// Distance in Feet
|
||||
/// </summary>
|
||||
public Double Feet { get; private set; }
|
||||
/// <summary>
|
||||
/// Initial Bearing from Coordinate 1 to Coordinate 2
|
||||
/// </summary>
|
||||
public Double Bearing { get; private set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance measurement type
|
||||
/// </summary>
|
||||
public enum DistanceType {
|
||||
/// <summary>
|
||||
/// Distance in Meters
|
||||
/// </summary>
|
||||
Meters,
|
||||
/// <summary>
|
||||
/// Distance in Kilometers
|
||||
/// </summary>
|
||||
Kilometers,
|
||||
/// <summary>
|
||||
/// Distance in Feet
|
||||
/// </summary>
|
||||
Feet,
|
||||
/// <summary>
|
||||
/// Distance in Statute Miles
|
||||
/// </summary>
|
||||
Miles,
|
||||
/// <summary>
|
||||
/// Distance in Nautical Miles
|
||||
/// </summary>
|
||||
NauticalMiles
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class Distance_Assistant {
|
||||
/// <summary>
|
||||
/// Returns new geodetic coordinate in radians
|
||||
/// </summary>
|
||||
/// <param name="glat1">Latitude in Radians</param>
|
||||
/// <param name="glon1">Longitude in Radians</param>
|
||||
/// <param name="faz">Bearing</param>
|
||||
/// <param name="s">Distance</param>
|
||||
/// <param name="ellipse">Earth Ellipse Values</param>
|
||||
/// <returns>double[]</returns>
|
||||
public static Double[] Direct_Ell(Double glat1, Double glon1, Double faz, Double s, Double[] ellipse) {
|
||||
glon1 *= -1; //REVERSE LONG FOR CALC 2.1.1.1
|
||||
Double EPS = 0.00000000005;//Used to determine if starting at pole.
|
||||
Double r, tu, sf, cf, b, cu, su, sa, c2a, x, c, d, y, sy = 0, cy = 0, cz = 0, e = 0;
|
||||
Double glat2, glon2, f;
|
||||
|
||||
//Determine if near pole
|
||||
if (Math.Abs(Math.Cos(glat1)) < EPS && !(Math.Abs(Math.Sin(faz)) < EPS)) {
|
||||
Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
|
||||
}
|
||||
|
||||
|
||||
Double a = ellipse[0];//Equitorial Radius
|
||||
f = 1 / ellipse[1];//Flattening
|
||||
r = 1 - f;
|
||||
tu = r * Math.Tan(glat1);
|
||||
sf = Math.Sin(faz);
|
||||
cf = Math.Cos(faz);
|
||||
b = cf == 0 ? 0.0 : 2.0 * Math.Atan2(tu, cf);
|
||||
cu = 1.0 / Math.Sqrt(1 + tu * tu);
|
||||
su = tu * cu;
|
||||
sa = cu * sf;
|
||||
c2a = 1 - sa * sa;
|
||||
x = 1.0 + Math.Sqrt(1.0 + c2a * (1.0 / (r * r) - 1.0));
|
||||
x = (x - 2.0) / x;
|
||||
c = 1.0 - x;
|
||||
c = (x * x / 4.0 + 1.0) / c;
|
||||
d = (0.375 * x * x - 1.0) * x;
|
||||
tu = s / (r * a * c);
|
||||
y = tu;
|
||||
c = y + 1;
|
||||
while (Math.Abs(y - c) > EPS) {
|
||||
sy = Math.Sin(y);
|
||||
cy = Math.Cos(y);
|
||||
cz = Math.Cos(b + y);
|
||||
e = 2.0 * cz * cz - 1.0;
|
||||
c = y;
|
||||
x = e * cy;
|
||||
y = e + e - 1.0;
|
||||
y = (((sy * sy * 4.0 - 3.0) * y * cz * d / 6.0 + x) *
|
||||
d / 4.0 - cz) * sy * d + tu;
|
||||
}
|
||||
|
||||
b = cu * cy * cf - su * sy;
|
||||
c = r * Math.Sqrt(sa * sa + b * b);
|
||||
d = su * cy + cu * sy * cf;
|
||||
|
||||
glat2 = ModM.ModLat(Math.Atan2(d, c));
|
||||
c = cu * cy - su * sy * cf;
|
||||
x = Math.Atan2(sy * sf, c);
|
||||
c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
|
||||
d = ((e * cy * c + cz) * sy * c + y) * sa;
|
||||
glon2 = ModM.ModLon(glon1 + x - (1.0 - c) * d * f); //Adjust for IDL
|
||||
//baz = ModM.ModCrs(Math.Atan2(sa, b) + Math.PI);
|
||||
return new Double[] { glat2, glon2 };
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns new geodetic coordinate in radians
|
||||
/// </summary>
|
||||
/// <param name="lat1">Latitude in radians</param>
|
||||
/// <param name="lon1">Longitude in radians</param>
|
||||
/// <param name="crs12">Bearing</param>
|
||||
/// <param name="d12">Distance</param>
|
||||
/// <returns>double[]</returns>
|
||||
public static Double[] Direct(Double lat1, Double lon1, Double crs12, Double d12) {
|
||||
lon1 *= -1; //REVERSE LONG FOR CALC 2.1.1.1
|
||||
Double EPS = 0.00000000005;//Used to determine if near pole.
|
||||
Double dlon, lat, lon;
|
||||
d12 *= 0.0005399565; //convert meter to nm
|
||||
d12 /= 180 * 60 / Math.PI;//Convert to Radian
|
||||
//Determine if near pole
|
||||
if (Math.Abs(Math.Cos(lat1)) < EPS && !(Math.Abs(Math.Sin(crs12)) < EPS)) {
|
||||
Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
|
||||
}
|
||||
|
||||
lat = Math.Asin(Math.Sin(lat1) * Math.Cos(d12) +
|
||||
Math.Cos(lat1) * Math.Sin(d12) * Math.Cos(crs12));
|
||||
if (Math.Abs(Math.Cos(lat)) < EPS) {
|
||||
lon = 0.0; //endpoint a pole
|
||||
} else {
|
||||
dlon = Math.Atan2(Math.Sin(crs12) * Math.Sin(d12) * Math.Cos(lat1),
|
||||
Math.Cos(d12) - Math.Sin(lat1) * Math.Sin(lat));
|
||||
lon = ModM.Mod(lon1 - dlon + Math.PI, 2 * Math.PI) - Math.PI;
|
||||
}
|
||||
|
||||
return new Double[] { lat, lon };
|
||||
}
|
||||
public static Double[] Dist_Ell(Double glat1, Double glon1, Double glat2, Double glon2, Double[] ellipse) {
|
||||
Double a = ellipse[0]; //Equitorial Radius
|
||||
Double f = 1 / ellipse[1]; //Flattening
|
||||
|
||||
Double r, tu1, tu2, cu1, su1, cu2, s1, b1, f1;
|
||||
Double sx = 0, cx = 0, sy = 0, cy = 0, y = 0, c2a = 0, cz = 0, e = 0;
|
||||
Double EPS = 0.00000000005;
|
||||
Double faz, baz, s;
|
||||
Double iter = 1;
|
||||
Double MAXITER = 100;
|
||||
if (glat1 + glat2 == 0.0 && Math.Abs(glon1 - glon2) == Math.PI) {
|
||||
Debug.WriteLine("Warning: Course and distance between antipodal points is undefined");
|
||||
glat1 += 0.00001; // allow algorithm to complete
|
||||
}
|
||||
if (glat1 == glat2 && (glon1 == glon2 || Math.Abs(Math.Abs(glon1 - glon2) - 2 * Math.PI) < EPS)) {
|
||||
Debug.WriteLine("Warning: Points 1 and 2 are identical- course undefined");
|
||||
//D
|
||||
//crs12
|
||||
//crs21
|
||||
return new Double[] { 0, 0, Math.PI };
|
||||
}
|
||||
r = 1 - f;
|
||||
tu1 = r * Math.Tan(glat1);
|
||||
tu2 = r * Math.Tan(glat2);
|
||||
cu1 = 1.0 / Math.Sqrt(1.0 + tu1 * tu1);
|
||||
su1 = cu1 * tu1;
|
||||
cu2 = 1.0 / Math.Sqrt(1.0 + tu2 * tu2);
|
||||
s1 = cu1 * cu2;
|
||||
b1 = s1 * tu2;
|
||||
f1 = b1 * tu1;
|
||||
Double x = glon2 - glon1;
|
||||
Double d = x + 1;
|
||||
Double c;
|
||||
while (Math.Abs(d - x) > EPS && iter < MAXITER) {
|
||||
iter += 1;
|
||||
sx = Math.Sin(x);
|
||||
cx = Math.Cos(x);
|
||||
tu1 = cu2 * sx;
|
||||
tu2 = b1 - su1 * cu2 * cx;
|
||||
sy = Math.Sqrt(tu1 * tu1 + tu2 * tu2);
|
||||
cy = s1 * cx + f1;
|
||||
y = Math.Atan2(sy, cy);
|
||||
Double sa = s1 * sx / sy;
|
||||
c2a = 1 - sa * sa;
|
||||
cz = f1 + f1;
|
||||
if (c2a > 0.0) {
|
||||
cz = cy - cz / c2a;
|
||||
}
|
||||
e = cz * cz * 2.0 - 1.0;
|
||||
c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
|
||||
d = x;
|
||||
x = ((e * cy * c + cz) * sy * c + y) * sa;
|
||||
x = (1.0 - c) * x * f + glon2 - glon1;
|
||||
}
|
||||
faz = ModM.ModCrs(Math.Atan2(tu1, tu2));
|
||||
baz = ModM.ModCrs(Math.Atan2(cu1 * sx, b1 * cx - su1 * cu2) + Math.PI);
|
||||
x = Math.Sqrt((1 / (r * r) - 1) * c2a + 1);
|
||||
x += 1;
|
||||
x = (x - 2.0) / x;
|
||||
c = 1.0 - x;
|
||||
c = (x * x / 4.0 + 1.0) / c;
|
||||
d = (0.375 * x * x - 1.0) * x;
|
||||
x = e * cy;
|
||||
s = ((((sy * sy * 4.0 - 3.0) * (1.0 - e - e) * cz * d / 6.0 - x) * d / 4.0 + cz) * sy * d + y) * c * a * r;
|
||||
|
||||
if (Math.Abs(iter - MAXITER) < EPS) {
|
||||
Debug.WriteLine("Warning: Distance algorithm did not converge");
|
||||
}
|
||||
|
||||
return new Double[] { s, faz, baz };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CoordinateSharp.Eclipse
|
||||
{
|
||||
internal class LunarData
|
||||
{
|
||||
static double[] LE1601 = new double[] {
|
||||
namespace CoordinateSharp.Eclipse {
|
||||
internal class LunarData {
|
||||
static readonly Double[] LE1601 = new Double[] {
|
||||
// 1601 1 18
|
||||
2305831.105839, 15.0, 117.3, 0.033, -0.978, 3,
|
||||
-1.13536, 0.98335, 0.26794,
|
||||
@ -1501,8 +1499,8 @@ namespace CoordinateSharp.Eclipse
|
||||
-3.09161, -1.92390, -0.82385, 0.02344, 0.87082, 1.97089, 3.13800,
|
||||
337.8589683, 0.48164, -1.510e-04,
|
||||
-9.4195702, 0.13945, 3.390e-04 };
|
||||
static double[] LE1701 = new double[]
|
||||
{
|
||||
static readonly Double[] LE1701 = new Double[]
|
||||
{
|
||||
// 1701 2 22
|
||||
2342390.479120, 23.0, 8.2, 1.428, 0.463, 2,
|
||||
-14.82816, 1.02374, 0.27894,
|
||||
@ -3039,9 +3037,9 @@ namespace CoordinateSharp.Eclipse
|
||||
-2.69377, -1.12653, 0.00000, -0.22214, 0.00000, 0.67926, 2.24840,
|
||||
9.1688605, 0.46956, -7.000e-05,
|
||||
3.0790301, 0.25315, -2.000e-04
|
||||
};
|
||||
static double[] LE1801 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] LE1801 = new Double[]
|
||||
{
|
||||
// 1801 3 30
|
||||
2378949.725057, 5.0, 13.0, 2.857, 1.840, 1,
|
||||
-6.52639, 0.96247, 0.26225,
|
||||
@ -4536,9 +4534,9 @@ namespace CoordinateSharp.Eclipse
|
||||
-1.50705, 0.00000, 0.00000, 0.44149, 0.00000, 0.00000, 2.38825,
|
||||
72.2570493, 0.64062, -1.660e-04,
|
||||
21.3680795, 0.01873, -1.222e-03
|
||||
};
|
||||
static double[] LE1901 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] LE1901 = new Double[]
|
||||
{
|
||||
// 1901 5 3
|
||||
2415508.271269, 19.0, -0.9, 1.043, -0.033, 3,
|
||||
-14.26838, 0.90110, 0.24553,
|
||||
@ -5913,9 +5911,9 @@ namespace CoordinateSharp.Eclipse
|
||||
-3.17609, -2.02249, -0.94259, -0.05589, 0.83086, 1.91081, 3.06398,
|
||||
296.2552752, 0.52835, -1.150e-04,
|
||||
-21.2212594, 0.04170, 8.250e-04
|
||||
};
|
||||
static double[] LE2001 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] LE2001 = new Double[]
|
||||
{
|
||||
// 2001 1 9
|
||||
2451919.348374, 20.0, 64.1, 2.162, 1.189, 1,
|
||||
3.29475, 1.02253, 0.27861,
|
||||
@ -7284,9 +7282,9 @@ namespace CoordinateSharp.Eclipse
|
||||
-2.37000, 0.00000, 0.00000, -0.25042, 0.00000, 0.00000, 1.86680,
|
||||
329.8184696, 0.49978, -6.760e-04,
|
||||
-13.3626205, 0.22960, 3.990e-04
|
||||
};
|
||||
static double[] LE2101 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] LE2101 = new Double[]
|
||||
{
|
||||
// 2101 2 14
|
||||
2488478.618055, 3.0, 205.1, 2.218, 1.183, 1,
|
||||
12.59941, 0.95660, 0.26065,
|
||||
@ -8715,9 +8713,9 @@ namespace CoordinateSharp.Eclipse
|
||||
-2.67458, -1.48697, 0.00000, -0.25460, 0.00000, 0.97583, 2.16508,
|
||||
28.0294400, 0.59158, 9.000e-05,
|
||||
10.7019400, 0.15900, -6.160e-04
|
||||
};
|
||||
static double[] LE2201 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] LE2201 = new Double[]
|
||||
{
|
||||
// 2201 3 20
|
||||
2525037.204912, 17.0, 444.3, 0.532, -0.560, 3,
|
||||
4.85759, 0.90005, 0.24524,
|
||||
@ -10230,9 +10228,9 @@ namespace CoordinateSharp.Eclipse
|
||||
-2.66449, -1.75055, -0.80821, 0.00923, 0.82677, 1.76918, 2.68236,
|
||||
63.0500500, 0.65278, 8.590e-04,
|
||||
21.0508309, 0.17085, -1.218e-03
|
||||
};
|
||||
static double[] LE2301 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] LE2301 = new Double[]
|
||||
{
|
||||
// 2301 5 23
|
||||
2561625.186996, 16.0, 720.0, 1.809, 0.754, 2,
|
||||
8.04603, 0.91666, 0.24977,
|
||||
@ -11751,8 +11749,8 @@ namespace CoordinateSharp.Eclipse
|
||||
-2.07354, -0.65576, 0.00000, 0.44265, 0.00000, 1.54366, 2.95874,
|
||||
101.2753539, 0.59275, -1.730e-04,
|
||||
23.7726800, -0.09243, -1.170e-03
|
||||
};
|
||||
static double[] LE2401 = new double[] {
|
||||
};
|
||||
static readonly Double[] LE2401 = new Double[] {
|
||||
// 2401 6 26
|
||||
2598183.958214, 11.0, 1059.4, 2.107, 1.139, 1,
|
||||
5.31800, 0.99489, 0.27108,
|
||||
@ -13176,7 +13174,7 @@ namespace CoordinateSharp.Eclipse
|
||||
348.3334732, 0.58130, -3.870e-04,
|
||||
-5.5431301, 0.18349, 2.190e-04
|
||||
};
|
||||
static double[] LE2501 = new double[] {
|
||||
static readonly Double[] LE2501 = new Double[] {
|
||||
// 2501 3 6
|
||||
2634595.801080, 7.0, 1461.0, 0.491, -0.599, 3,
|
||||
17.93340, 0.90700, 0.24714,
|
||||
@ -14541,70 +14539,49 @@ namespace CoordinateSharp.Eclipse
|
||||
8.0835801, 0.28700, -3.300e-04
|
||||
};
|
||||
|
||||
public static double[] LunarDateData(DateTime d)
|
||||
{
|
||||
//Return combined 100 year arrays so in order to grab Last and Next exlipLE.
|
||||
List<double[]> data = new List<double[]>()
|
||||
{
|
||||
public static Double[] LunarDateData(DateTime d) {
|
||||
//Return combined 100 year arrays so in order to grab Last and Next exlipLE.
|
||||
List<Double[]> data = new List<Double[]>()
|
||||
{
|
||||
LE1601, LE1701,LE1801, LE1901, LE2001,
|
||||
LE2101,LE2201, LE2301, LE2401, LE2501
|
||||
};
|
||||
double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
|
||||
int index = GetIndex(cent); //Gets index for calling data list.
|
||||
Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
|
||||
Int32 index = GetIndex(cent); //Gets index for calling data list.
|
||||
|
||||
if (index == -1) { return new double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
|
||||
if (index == -1) { return new Double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
|
||||
|
||||
//Determine data to LEnd if year is near beginning or end of databaLE
|
||||
int halfCent = d.Year - (int)cent;
|
||||
if (index == 0 || index == data.Count - 1)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
if (halfCent <= 50) { return data[0]; }
|
||||
else { return data[0].Concat(data[1]).ToArray(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (halfCent <= 50) { return data[index - 1].Concat(data[index]).ToArray(); }
|
||||
else { return data[index]; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (halfCent <= 50) { return data[index - 1].Concat(data[index]).ToArray(); }
|
||||
else { return data[index].Concat(data[index + 1]).ToArray(); }
|
||||
}
|
||||
//Determine data to LEnd if year is near beginning or end of databaLE
|
||||
Int32 halfCent = d.Year - (Int32)cent;
|
||||
return index == 0 || index == data.Count - 1 ? index == 0 ? halfCent <= 50 ? data[0] : data[0].Concat(data[1]).ToArray() : halfCent <= 50 ? data[index - 1].Concat(data[index]).ToArray() : data[index] : halfCent <= 50 ? data[index - 1].Concat(data[index]).ToArray() : data[index].Concat(data[index + 1]).ToArray();
|
||||
|
||||
}
|
||||
public static double[] LunarDateData_100Year(DateTime d)
|
||||
{
|
||||
//Return combined 100 year arrays
|
||||
List<double[]> data = new List<double[]>()
|
||||
{
|
||||
LE1601, LE1701,LE1801, LE1901, LE2001,
|
||||
LE2101,LE2201, LE2301, LE2401, LE2501
|
||||
};
|
||||
double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
|
||||
int index = GetIndex(cent); //Gets index for calling data list.
|
||||
|
||||
if (index == -1) { return new double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
|
||||
//Return proper 100 year table.
|
||||
return data[index];
|
||||
|
||||
}
|
||||
private static int GetIndex(double cent)
|
||||
{
|
||||
int dex = 0;
|
||||
int c = Convert.ToInt32(cent * .01);
|
||||
//START CENTURY 16
|
||||
//END CENTRURY 26
|
||||
//AJDUST AS DATABALE GROWS
|
||||
for (int i = 16; i < 26; i++)
|
||||
{
|
||||
if (i == c) { return dex; }
|
||||
dex++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public static Double[] LunarDateData_100Year(DateTime d) {
|
||||
//Return combined 100 year arrays
|
||||
List<Double[]> data = new List<Double[]>()
|
||||
{
|
||||
LE1601, LE1701,LE1801, LE1901, LE2001,
|
||||
LE2101,LE2201, LE2301, LE2401, LE2501
|
||||
};
|
||||
Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
|
||||
Int32 index = GetIndex(cent); //Gets index for calling data list.
|
||||
|
||||
if (index == -1) { return new Double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
|
||||
//Return proper 100 year table.
|
||||
return data[index];
|
||||
|
||||
}
|
||||
private static Int32 GetIndex(Double cent) {
|
||||
Int32 dex = 0;
|
||||
Int32 c = Convert.ToInt32(cent * .01);
|
||||
//START CENTURY 16
|
||||
//END CENTRURY 26
|
||||
//AJDUST AS DATABALE GROWS
|
||||
for (Int32 i = 16; i < 26; i++) {
|
||||
if (i == c) { return dex; }
|
||||
dex++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CoordinateSharp.Eclipse
|
||||
{
|
||||
internal class SolarData
|
||||
{
|
||||
//ECLIPSE DATA FROM 1701-2400
|
||||
static double[] SE1601 = new double[]
|
||||
{
|
||||
namespace CoordinateSharp.Eclipse {
|
||||
internal class SolarData {
|
||||
//ECLIPSE DATA FROM 1701-2400
|
||||
static readonly Double[] SE1601 = new Double[]
|
||||
{
|
||||
// 1601 1 4
|
||||
2305817.017109, 12.0, -4.0, 4.0, 117.4, 117.4,
|
||||
-0.2585420, 0.5087563, -7.100e-06, -6.160e-06,
|
||||
@ -2241,9 +2239,9 @@ namespace CoordinateSharp.Eclipse
|
||||
0.5346340, 0.0000437, -1.270e-05,
|
||||
-0.0114460, 0.0000434, -1.270e-05,
|
||||
0.0046524, 0.0046293
|
||||
};
|
||||
static double[] SE1701 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] SE1701 = new Double[]
|
||||
{
|
||||
// 1701 2 7
|
||||
2342375.461729, 23.0, -4.0, 4.0, 8.2, 8.2,
|
||||
-0.1836620, 0.4942406, -1.910e-05, -5.580e-06,
|
||||
@ -4504,8 +4502,8 @@ namespace CoordinateSharp.Eclipse
|
||||
-0.0039760, -0.0000963, -1.230e-05,
|
||||
0.0046973, 0.0046739
|
||||
};
|
||||
static double[] SE1801 = new double[]
|
||||
{
|
||||
static readonly Double[] SE1801 = new Double[]
|
||||
{
|
||||
// 1801 3 14
|
||||
2378934.156652, 16.0, -4.0, 4.0, 13.0, 13.0,
|
||||
0.8100150, 0.4830337, -6.270e-05, -6.820e-06,
|
||||
@ -6684,8 +6682,8 @@ namespace CoordinateSharp.Eclipse
|
||||
0.5676560, -0.0000826, -1.030e-05,
|
||||
0.0214110, -0.0000822, -1.030e-05,
|
||||
0.0047365, 0.0047129};
|
||||
static double[] SE1901 = new double[]
|
||||
{
|
||||
static readonly Double[] SE1901 = new Double[]
|
||||
{
|
||||
// 1901 5 18
|
||||
2415522.731807, 6.0, -4.0, 4.0, -0.9, -0.9,
|
||||
0.3000790, 0.5746928, -4.400e-06, -9.600e-06,
|
||||
@ -8738,9 +8736,9 @@ namespace CoordinateSharp.Eclipse
|
||||
0.5730920, 0.0000514, -1.000e-05,
|
||||
0.0268200, 0.0000511, -1.000e-05,
|
||||
0.0047553, 0.0047316
|
||||
};
|
||||
static double[] SE2001 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] SE2001 = new Double[]
|
||||
{
|
||||
// 2001 6 21
|
||||
2452082.003314, 12.0, -4.0, 4.0, 64.2, 64.2,
|
||||
0.0103400, 0.5653861, 2.920e-05, -8.860e-06,
|
||||
@ -10757,9 +10755,9 @@ namespace CoordinateSharp.Eclipse
|
||||
0.5398730, -0.0001031, -1.210e-05,
|
||||
-0.0062330, -0.0001026, -1.200e-05,
|
||||
0.0046346, 0.0046116
|
||||
};
|
||||
static double[] SE2101 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] SE2101 = new Double[]
|
||||
{
|
||||
// 2101 2 28
|
||||
2488492.594741, 2.0, -4.0, 4.0, 205.2, 205.2,
|
||||
-0.5934920, 0.4746287, -1.290e-05, -6.230e-06,
|
||||
@ -12875,9 +12873,9 @@ namespace CoordinateSharp.Eclipse
|
||||
0.5652510, -0.0000740, -1.020e-05,
|
||||
0.0190180, -0.0000736, -1.010e-05,
|
||||
0.0046769, 0.0046536
|
||||
};
|
||||
static double[] SE2201 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] SE2201 = new Double[]
|
||||
{
|
||||
// 2201 4 4
|
||||
2525051.763849, 6.0, -4.0, 4.0, 444.4, 444.4,
|
||||
-0.1405310, 0.5551418, 1.180e-05, -9.340e-06,
|
||||
@ -15110,9 +15108,9 @@ namespace CoordinateSharp.Eclipse
|
||||
0.5747280, 0.0000236, -9.900e-06,
|
||||
0.0284480, 0.0000235, -9.800e-06,
|
||||
0.0047462, 0.0047226
|
||||
};
|
||||
static double[] SE2301 = new double[]
|
||||
{
|
||||
};
|
||||
static readonly Double[] SE2301 = new Double[]
|
||||
{
|
||||
// 2301 5 9
|
||||
2561611.084014, 14.0, -4.0, 4.0, 719.9, 719.9,
|
||||
0.2556460, 0.5255338, 4.360e-05, -8.080e-06,
|
||||
@ -17345,8 +17343,8 @@ namespace CoordinateSharp.Eclipse
|
||||
0.5389710, -0.0001064, -1.190e-05,
|
||||
-0.0071310, -0.0001059, -1.190e-05,
|
||||
0.0046006, 0.0045776
|
||||
};
|
||||
static double[] SE2401 = new double[] {
|
||||
};
|
||||
static readonly Double[] SE2401 = new Double[] {
|
||||
// 2401 1 14
|
||||
2598021.427310, 22.0, -4.0, 4.0, 1057.8, 1057.8,
|
||||
-0.2870830, 0.5189539, -4.590e-05, -7.000e-06,
|
||||
@ -19481,7 +19479,7 @@ namespace CoordinateSharp.Eclipse
|
||||
0.0163870, -0.0000706, -1.000e-05,
|
||||
0.0046201, 0.0045971
|
||||
};
|
||||
static double[] SE2501 = new double[] {
|
||||
static readonly Double[] SE2501 = new Double[] {
|
||||
// 2501 2 19
|
||||
2634580.691215, 5.0, -4.0, 4.0, 1460.8, 1460.8,
|
||||
0.1813720, 0.5619451, -3.330e-05, -9.490e-06,
|
||||
@ -21508,71 +21506,50 @@ namespace CoordinateSharp.Eclipse
|
||||
0.0248230, 0.0000365, -9.800e-06,
|
||||
0.0046944, 0.0046710 };
|
||||
|
||||
public static double[] SolarDateData(DateTime d)
|
||||
{
|
||||
//Return combined 100 year arrays so in order to grab Last and Next exlipse.
|
||||
List<double[]> data = new List<double[]>()
|
||||
{
|
||||
public static Double[] SolarDateData(DateTime d) {
|
||||
//Return combined 100 year arrays so in order to grab Last and Next exlipse.
|
||||
List<Double[]> data = new List<Double[]>()
|
||||
{
|
||||
SE1601, SE1701, SE1801, SE1901, SE2001,
|
||||
SE2101, SE2201, SE2301, SE2401, SE2501
|
||||
};
|
||||
double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
|
||||
int index = GetIndex(cent); //Gets index for calling data list.
|
||||
Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
|
||||
Int32 index = GetIndex(cent); //Gets index for calling data list.
|
||||
|
||||
if (index == -1) { return new double[] { };} //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
|
||||
if (index == -1) { return new Double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
|
||||
|
||||
//Determine data to send if year is near beginning or end of database
|
||||
int halfCent = d.Year - (int)cent;
|
||||
|
||||
if (index == 0 || index == data.Count - 1)
|
||||
{
|
||||
if(index == 0)
|
||||
{
|
||||
if (halfCent <= 50) { return data[0]; }
|
||||
else { return data[0].Concat(data[1]).ToArray(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (halfCent <= 50) { return data[index - 1].Concat(data[index]).ToArray(); }
|
||||
else { return data[index]; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (halfCent <= 50) { return data[index - 1].Concat(data[index]).ToArray(); }
|
||||
else { return data[index].Concat(data[index+1]).ToArray(); }
|
||||
}
|
||||
|
||||
}
|
||||
public static double[] SolarDateData_100Year(DateTime d)
|
||||
{
|
||||
//Return combined 100 year arrays
|
||||
List<double[]> data = new List<double[]>()
|
||||
{
|
||||
SE1601, SE1701, SE1801, SE1901, SE2001,
|
||||
SE2101, SE2201, SE2301, SE2401, SE2501
|
||||
};
|
||||
double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
|
||||
int index = GetIndex(cent); //Gets index for calling data list.
|
||||
//Determine data to send if year is near beginning or end of database
|
||||
Int32 halfCent = d.Year - (Int32)cent;
|
||||
|
||||
if (index == -1) { return new double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
|
||||
//Return proper 100 year table.
|
||||
return data[index];
|
||||
return index == 0 || index == data.Count - 1 ? index == 0 ? halfCent <= 50 ? data[0] : data[0].Concat(data[1]).ToArray() : halfCent <= 50 ? data[index - 1].Concat(data[index]).ToArray() : data[index] : halfCent <= 50 ? data[index - 1].Concat(data[index]).ToArray() : data[index].Concat(data[index + 1]).ToArray();
|
||||
|
||||
}
|
||||
private static int GetIndex(double cent)
|
||||
{
|
||||
int dex = 0;
|
||||
int c = Convert.ToInt32(cent * .01);
|
||||
//START CENTURY 16
|
||||
//END CENTRURY 26
|
||||
//AJDUST AS DATABASE GROWS
|
||||
for(int i = 16; i<26;i++)
|
||||
{
|
||||
if(i == c) { return dex; }
|
||||
dex++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public static Double[] SolarDateData_100Year(DateTime d) {
|
||||
//Return combined 100 year arrays
|
||||
List<Double[]> data = new List<Double[]>()
|
||||
{
|
||||
SE1601, SE1701, SE1801, SE1901, SE2001,
|
||||
SE2101, SE2201, SE2301, SE2401, SE2501
|
||||
};
|
||||
Double cent = Math.Floor(d.Year * .01) * 100; //Gets turn of century year.
|
||||
Int32 index = GetIndex(cent); //Gets index for calling data list.
|
||||
|
||||
if (index == -1) { return new Double[] { }; } //RETURN EMPTY ARRAY IF OUTSIDE DB RANGE
|
||||
//Return proper 100 year table.
|
||||
return data[index];
|
||||
|
||||
}
|
||||
private static Int32 GetIndex(Double cent) {
|
||||
Int32 dex = 0;
|
||||
Int32 c = Convert.ToInt32(cent * .01);
|
||||
//START CENTURY 16
|
||||
//END CENTRURY 26
|
||||
//AJDUST AS DATABASE GROWS
|
||||
for (Int32 i = 16; i < 26; i++) {
|
||||
if (i == c) { return dex; }
|
||||
dex++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,161 +1,138 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CoordinateSharp {
|
||||
/// <summary>
|
||||
/// Geo Fence class. It helps to check if points/coordinates are inside a polygon,
|
||||
/// Next to a polyline, and counting...
|
||||
/// </summary>
|
||||
public class GeoFence {
|
||||
#region Fields
|
||||
private readonly List<Point> _points = new List<Point>();
|
||||
#endregion
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Geo Fence class. It helps to check if points/coordinates are inside a polygon,
|
||||
/// Next to a polyline, and counting...
|
||||
/// Prepare GeoFence with a list of points
|
||||
/// </summary>
|
||||
public class GeoFence
|
||||
{
|
||||
#region Fields
|
||||
private List<Point> _points = new List<Point>();
|
||||
#endregion
|
||||
/// <param name="points">List of points</param>
|
||||
public GeoFence(List<Point> points) => this._points = points;
|
||||
|
||||
/// <summary>
|
||||
/// Prepare GeoFence with a list of points
|
||||
/// </summary>
|
||||
/// <param name="points">List of points</param>
|
||||
public GeoFence(List<Point> points)
|
||||
{
|
||||
_points = points;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare Geofence with a list of coordinates
|
||||
/// </summary>
|
||||
/// <param name="coordinates">List of coordinates</param>
|
||||
public GeoFence(List<Coordinate> coordinates)
|
||||
{
|
||||
foreach (var c in coordinates)
|
||||
{
|
||||
_points.Add(new Point { Latitude = c.Latitude.ToDouble(), Longitude = c.Longitude.ToDouble() });
|
||||
}
|
||||
}
|
||||
|
||||
#region Utils
|
||||
private Coordinate ClosestPointOnSegment(Point a, Point b, Coordinate p)
|
||||
{
|
||||
var d = new Point
|
||||
{
|
||||
Longitude = b.Longitude - a.Longitude,
|
||||
Latitude = b.Latitude - a.Latitude,
|
||||
};
|
||||
|
||||
double number = (p.Longitude.ToDouble() - a.Longitude) * d.Longitude + (p.Latitude.ToDouble() - a.Latitude) * d.Latitude;
|
||||
|
||||
if (number <= 0.0)
|
||||
return new Coordinate(a.Latitude, a.Longitude);
|
||||
|
||||
double denom = d.Longitude * d.Longitude + d.Latitude * d.Latitude;
|
||||
|
||||
if (number >= denom)
|
||||
return new Coordinate(b.Latitude, b.Longitude);
|
||||
|
||||
return new Coordinate(a.Latitude + (number / denom) * d.Latitude, a.Longitude + (number / denom) * d.Longitude);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is inside the polygon, or
|
||||
/// false if it is not. If the point is exactly on the edge of the polygon,
|
||||
/// then the function may return true or false.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <returns>bool</returns>
|
||||
public bool IsPointInPolygon(Coordinate point)
|
||||
{
|
||||
if (point == null)
|
||||
return false;
|
||||
|
||||
double latitude = point.Latitude.ToDouble();
|
||||
double longitude = point.Longitude.ToDouble();
|
||||
int sides = _points.Count;
|
||||
int j = sides - 1;
|
||||
bool pointStatus = false;
|
||||
for (int i = 0; i < sides; i++)
|
||||
{
|
||||
if (_points[i].Latitude < latitude && _points[j].Latitude >= latitude || _points[j].Latitude < latitude && _points[i].Latitude >= latitude)
|
||||
{
|
||||
if (_points[i].Longitude + (latitude - _points[i].Latitude) / (_points[j].Latitude - _points[i].Latitude) * (_points[j].Longitude - _points[i].Longitude) < longitude)
|
||||
{
|
||||
pointStatus = !pointStatus;
|
||||
}
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
return pointStatus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is next the given range of
|
||||
/// the polyline, or false if it is not.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <param name="range">The range in meters</param>
|
||||
/// <returns>bool</returns>
|
||||
public bool IsPointInRangeOfLine(Coordinate point, double range)
|
||||
{
|
||||
if (point == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < _points.Count - 1; i++)
|
||||
{
|
||||
Coordinate c = ClosestPointOnSegment(_points[i], _points[i + 1], point);
|
||||
if (c.Get_Distance_From_Coordinate(point).Meters <= range)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is next the given range of
|
||||
/// the polyline, or false if it is not.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <param name="range">The range is a distance object</param>
|
||||
/// <returns>bool</returns>
|
||||
public bool IsPointInRangeOfLine(Coordinate point, Distance range)
|
||||
{
|
||||
if (point == null || range == null)
|
||||
return false;
|
||||
|
||||
return IsPointInRangeOfLine(point, range.Meters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class is a help class to simplify GeoFence calculus
|
||||
/// </summary>
|
||||
public class Point
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initialize empty point
|
||||
/// </summary>
|
||||
public Point()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Initialize point with defined Latitude and Longitude
|
||||
/// </summary>
|
||||
/// <param name="lat">Latitude (signed)</param>
|
||||
/// <param name="lng">Longitude (signed)</param>
|
||||
public Point(double lat, double lng)
|
||||
{
|
||||
Latitude = lat;
|
||||
Longitude = lng;
|
||||
}
|
||||
/// <summary>
|
||||
/// The longitude in degrees
|
||||
/// </summary>
|
||||
public double Longitude;
|
||||
/// <summary>
|
||||
/// The latitude in degrees
|
||||
/// </summary>
|
||||
public double Latitude;
|
||||
}
|
||||
/// <summary>
|
||||
/// Prepare Geofence with a list of coordinates
|
||||
/// </summary>
|
||||
/// <param name="coordinates">List of coordinates</param>
|
||||
public GeoFence(List<Coordinate> coordinates) {
|
||||
foreach (Coordinate c in coordinates) {
|
||||
this._points.Add(new Point { Latitude = c.Latitude.ToDouble(), Longitude = c.Longitude.ToDouble() });
|
||||
}
|
||||
}
|
||||
|
||||
#region Utils
|
||||
private Coordinate ClosestPointOnSegment(Point a, Point b, Coordinate p) {
|
||||
Point d = new Point {
|
||||
Longitude = b.Longitude - a.Longitude,
|
||||
Latitude = b.Latitude - a.Latitude,
|
||||
};
|
||||
|
||||
Double number = (p.Longitude.ToDouble() - a.Longitude) * d.Longitude + (p.Latitude.ToDouble() - a.Latitude) * d.Latitude;
|
||||
|
||||
if (number <= 0.0) {
|
||||
return new Coordinate(a.Latitude, a.Longitude);
|
||||
}
|
||||
|
||||
Double denom = d.Longitude * d.Longitude + d.Latitude * d.Latitude;
|
||||
|
||||
return number >= denom ? new Coordinate(b.Latitude, b.Longitude) : new Coordinate(a.Latitude + number / denom * d.Latitude, a.Longitude + number / denom * d.Longitude);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is inside the polygon, or
|
||||
/// false if it is not. If the point is exactly on the edge of the polygon,
|
||||
/// then the function may return true or false.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <returns>bool</returns>
|
||||
public Boolean IsPointInPolygon(Coordinate point) {
|
||||
if (point == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Double latitude = point.Latitude.ToDouble();
|
||||
Double longitude = point.Longitude.ToDouble();
|
||||
Int32 sides = this._points.Count;
|
||||
Int32 j = sides - 1;
|
||||
Boolean pointStatus = false;
|
||||
for (Int32 i = 0; i < sides; i++) {
|
||||
if (this._points[i].Latitude < latitude && this._points[j].Latitude >= latitude || this._points[j].Latitude < latitude && this._points[i].Latitude >= latitude) {
|
||||
if (this._points[i].Longitude + (latitude - this._points[i].Latitude) / (this._points[j].Latitude - this._points[i].Latitude) * (this._points[j].Longitude - this._points[i].Longitude) < longitude) {
|
||||
pointStatus = !pointStatus;
|
||||
}
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
return pointStatus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is next the given range of
|
||||
/// the polyline, or false if it is not.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <param name="range">The range in meters</param>
|
||||
/// <returns>bool</returns>
|
||||
public Boolean IsPointInRangeOfLine(Coordinate point, Double range) {
|
||||
if (point == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Int32 i = 0; i < this._points.Count - 1; i++) {
|
||||
Coordinate c = this.ClosestPointOnSegment(this._points[i], this._points[i + 1], point);
|
||||
if (c.Get_Distance_From_Coordinate(point).Meters <= range) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is next the given range of
|
||||
/// the polyline, or false if it is not.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <param name="range">The range is a distance object</param>
|
||||
/// <returns>bool</returns>
|
||||
public Boolean IsPointInRangeOfLine(Coordinate point, Distance range) => point == null || range == null ? false : this.IsPointInRangeOfLine(point, range.Meters);
|
||||
|
||||
/// <summary>
|
||||
/// This class is a help class to simplify GeoFence calculus
|
||||
/// </summary>
|
||||
public class Point {
|
||||
|
||||
/// <summary>
|
||||
/// Initialize empty point
|
||||
/// </summary>
|
||||
public Point() {
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Initialize point with defined Latitude and Longitude
|
||||
/// </summary>
|
||||
/// <param name="lat">Latitude (signed)</param>
|
||||
/// <param name="lng">Longitude (signed)</param>
|
||||
public Point(Double lat, Double lng) {
|
||||
this.Latitude = lat;
|
||||
this.Longitude = lng;
|
||||
}
|
||||
/// <summary>
|
||||
/// The longitude in degrees
|
||||
/// </summary>
|
||||
public Double Longitude;
|
||||
/// <summary>
|
||||
/// The latitude in degrees
|
||||
/// </summary>
|
||||
public Double Latitude;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.Reflection;
|
||||
#if !NETCOREAPP
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@ -34,3 +35,4 @@ using System.Runtime.InteropServices;
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.1.5.2")]
|
||||
[assembly: AssemblyFileVersion("1.1.5.2")]
|
||||
#endif
|
25
CoordinateSharp_Core.sln
Normal file
25
CoordinateSharp_Core.sln
Normal 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
|
Loading…
Reference in New Issue
Block a user