926 lines
34 KiB
C#
926 lines
34 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using System.Text.RegularExpressions;
|
|||
|
namespace CoordinateSharp
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Type of format a Coordinate parsed from.
|
|||
|
/// </summary>
|
|||
|
[Serializable]
|
|||
|
public enum Parse_Format_Type
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Coordinate was not initialized from a parser method.
|
|||
|
/// </summary>
|
|||
|
None,
|
|||
|
/// <summary>
|
|||
|
/// Signed Degree
|
|||
|
/// DD.dddd
|
|||
|
/// </summary>
|
|||
|
Signed_Degree,
|
|||
|
/// <summary>
|
|||
|
/// Decimal Degree
|
|||
|
/// P DD.dddd
|
|||
|
/// </summary>
|
|||
|
Decimal_Degree,
|
|||
|
/// <summary>
|
|||
|
/// Degree Decimal Minute
|
|||
|
/// P DD MM.sss
|
|||
|
/// </summary>
|
|||
|
Degree_Decimal_Minute,
|
|||
|
/// <summary>
|
|||
|
/// Degree Minute Second
|
|||
|
/// P DD MM SS.sss
|
|||
|
/// </summary>
|
|||
|
Degree_Minute_Second,
|
|||
|
/// <summary>
|
|||
|
/// Universal Transverse Mercator
|
|||
|
/// </summary>
|
|||
|
UTM,
|
|||
|
/// <summary>
|
|||
|
/// Military Grid Reference System
|
|||
|
/// </summary>
|
|||
|
MGRS,
|
|||
|
/// <summary>
|
|||
|
/// Spherical Cartesian
|
|||
|
/// </summary>
|
|||
|
Cartesian_Spherical,
|
|||
|
/// <summary>
|
|||
|
/// Earth Centered Earth Fixed
|
|||
|
/// </summary>
|
|||
|
Cartesian_ECEF
|
|||
|
}
|
|||
|
|
|||
|
internal class FormatFinder
|
|||
|
{
|
|||
|
//Add main to Coordinate and tunnel to Format class. Add private methods to format.
|
|||
|
//WHEN PARSING NO EXCPETIONS FOR OUT OF RANGE ARGS WILL BE THROWN
|
|||
|
public static bool TryParse(string coordString, CartesianType ct, out Coordinate c)
|
|||
|
{
|
|||
|
//Turn of eagerload for efficiency
|
|||
|
EagerLoad eg = new EagerLoad();
|
|||
|
eg.Cartesian = false;
|
|||
|
eg.Celestial = false;
|
|||
|
eg.UTM_MGRS = false;
|
|||
|
|
|||
|
c = new Coordinate(eg);
|
|||
|
string s = coordString;
|
|||
|
s = s.Trim(); //Trim all spaces before and after string
|
|||
|
double[] d;
|
|||
|
//Try Signed Degree
|
|||
|
if (TrySignedDegree(s, out d))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
c = new Coordinate(d[0], d[1], eg);
|
|||
|
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//Try Decimal Degree
|
|||
|
if (TryDecimalDegree(s, out d))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
c = new Coordinate(d[0], d[1], eg);
|
|||
|
c.Parse_Format = Parse_Format_Type.Decimal_Degree;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
//Try DDM
|
|||
|
if (TryDegreeDecimalMinute(s, out d))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
//0 Lat Degree
|
|||
|
//1 Lat Minute
|
|||
|
//2 Lat Direction (0 = N, 1 = S)
|
|||
|
//3 Long Degree
|
|||
|
//4 Long Minute
|
|||
|
//5 Long Direction (0 = E, 1 = W)
|
|||
|
CoordinatesPosition latP = CoordinatesPosition.N;
|
|||
|
CoordinatesPosition lngP = CoordinatesPosition.E;
|
|||
|
if (d[2] != 0) { latP = CoordinatesPosition.S; }
|
|||
|
if (d[5] != 0) { lngP = CoordinatesPosition.W; }
|
|||
|
CoordinatePart lat = new CoordinatePart((int)d[0], d[1], latP);
|
|||
|
CoordinatePart lng = new CoordinatePart((int)d[3], d[4], lngP);
|
|||
|
c = new Coordinate(eg);
|
|||
|
c.Latitude = lat;
|
|||
|
c.Longitude = lng;
|
|||
|
c.Parse_Format = Parse_Format_Type.Degree_Decimal_Minute;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
//Try DMS
|
|||
|
if (TryDegreeMinuteSecond(s, out d))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
//0 Lat Degree
|
|||
|
//1 Lat Minute
|
|||
|
//2 Lat Second
|
|||
|
//3 Lat Direction (0 = N, 1 = S)
|
|||
|
//4 Long Degree
|
|||
|
//5 Long Minute
|
|||
|
//6 Long Second
|
|||
|
//7 Long Direction (0 = E, 1 = W)
|
|||
|
CoordinatesPosition latP = CoordinatesPosition.N;
|
|||
|
CoordinatesPosition lngP = CoordinatesPosition.E;
|
|||
|
if (d[3] != 0) { latP = CoordinatesPosition.S; }
|
|||
|
if (d[7] != 0) { lngP = CoordinatesPosition.W; }
|
|||
|
|
|||
|
CoordinatePart lat = new CoordinatePart((int)d[0], (int)d[1], d[2], latP);
|
|||
|
CoordinatePart lng = new CoordinatePart((int)d[4], (int)d[5], d[6], lngP);
|
|||
|
c = new Coordinate(eg);
|
|||
|
c.Latitude = lat;
|
|||
|
c.Longitude = lng;
|
|||
|
c.Parse_Format = Parse_Format_Type.Degree_Minute_Second;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
string[] um;
|
|||
|
//Try MGRS
|
|||
|
if (TryMGRS(s, out um))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
double zone = Convert.ToDouble(um[0]);
|
|||
|
double easting = Convert.ToDouble(um[3]);
|
|||
|
double northing = Convert.ToDouble(um[4]);
|
|||
|
MilitaryGridReferenceSystem mgrs = new MilitaryGridReferenceSystem(um[1], (int)zone, um[2], easting, northing);
|
|||
|
c = MilitaryGridReferenceSystem.MGRStoLatLong(mgrs);
|
|||
|
c.Parse_Format = Parse_Format_Type.MGRS;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
//Try UTM
|
|||
|
if (TryUTM(s, out um))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
double zone = Convert.ToDouble(um[0]);
|
|||
|
double easting = Convert.ToDouble(um[2]);
|
|||
|
double northing = Convert.ToDouble(um[3]);
|
|||
|
UniversalTransverseMercator utm = new UniversalTransverseMercator(um[1], (int)zone, easting, northing);
|
|||
|
c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
|
|||
|
c.Parse_Format = Parse_Format_Type.UTM;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
//Try Cartesian
|
|||
|
if (TryCartesian(s.ToUpper().Replace("KM", "").Replace("X","").Replace("Y", "").Replace("Z", ""), out d))
|
|||
|
{
|
|||
|
if (ct == CartesianType.Cartesian)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
Cartesian cart = new Cartesian(d[0], d[1], d[2]);
|
|||
|
c = Cartesian.CartesianToLatLong(cart);
|
|||
|
c.Parse_Format = Parse_Format_Type.Cartesian_Spherical;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
if (ct == CartesianType.ECEF)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
ECEF ecef = new ECEF(d[0], d[1], d[2]);
|
|||
|
c = ECEF.ECEFToLatLong(ecef);
|
|||
|
c.Parse_Format = Parse_Format_Type.Cartesian_ECEF;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
c = null;
|
|||
|
return false;
|
|||
|
}
|
|||
|
private static bool TrySignedDegree(string s, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
if (Regex.Matches(s, @"[a-zA-Z]").Count != 0) { return false; } //Should contain no letters
|
|||
|
|
|||
|
string[] sA = SpecialSplit(s,false);
|
|||
|
double lat;
|
|||
|
double lng;
|
|||
|
|
|||
|
double degLat;
|
|||
|
double minLat; //Minutes & MinSeconds
|
|||
|
double secLat;
|
|||
|
|
|||
|
int signLat = 1;
|
|||
|
|
|||
|
double degLng;
|
|||
|
double minLng; //Minutes & MinSeconds
|
|||
|
double secLng;
|
|||
|
|
|||
|
int signLng = 1;
|
|||
|
|
|||
|
switch (sA.Count())
|
|||
|
{
|
|||
|
case 2:
|
|||
|
if (!double.TryParse(sA[0], out lat))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out lng))
|
|||
|
{ return false; }
|
|||
|
d = new double[] { lat, lng };
|
|||
|
return true;
|
|||
|
case 4:
|
|||
|
if (!double.TryParse(sA[0], out degLat))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out minLat))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out degLng))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[3], out minLng))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
if (degLat < 0) { signLat = -1; }
|
|||
|
if (degLng < 0) { signLng = -1; }
|
|||
|
if (minLat >= 60 || minLat < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
if (minLng >= 60 || minLng < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
lat = (Math.Abs(degLat) + (minLat / 60.0)) * signLat;
|
|||
|
lng = (Math.Abs(degLng) + (minLng / 60.0)) * signLng;
|
|||
|
d = new double[] { lat, lng };
|
|||
|
return true;
|
|||
|
case 6:
|
|||
|
if (!double.TryParse(sA[0], out degLat))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out minLat))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out secLat))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[3], out degLng))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[4], out minLng))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[5], out secLng))
|
|||
|
{ return false; }
|
|||
|
if (degLat < 0) { signLat = -1; }
|
|||
|
if (degLng < 0) { signLng = -1; }
|
|||
|
if (minLat >= 60 || minLat < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
if (minLng >= 60 || minLng < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
if (secLat >= 60 || secLat < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
if (secLng >= 60 || secLng < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
lat = (Math.Abs(degLat) + (minLat / 60.0) + (secLat / 3600)) * signLat;
|
|||
|
lng = (Math.Abs(degLng) + (minLng / 60.0) + (secLng / 3600)) * signLng;
|
|||
|
d = new double[] { lat, lng };
|
|||
|
return true;
|
|||
|
default:
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
private static bool TryDecimalDegree(string s, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
|
|||
|
|
|||
|
string[] sA = SpecialSplit(s,true);
|
|||
|
if (sA.Count() == 2 || sA.Count() == 4)
|
|||
|
{
|
|||
|
double lat;
|
|||
|
double lng;
|
|||
|
|
|||
|
double latR = 1; //Sets negative if South
|
|||
|
double lngR = 1; //Sets negative if West
|
|||
|
|
|||
|
//Contact get brin directional indicator together with string
|
|||
|
if (sA.Count() == 4)
|
|||
|
{
|
|||
|
sA[0] += sA[1];
|
|||
|
sA[1] = sA[2] + sA[3];
|
|||
|
}
|
|||
|
|
|||
|
//Find Directions
|
|||
|
if (!sA[0].Contains("N") && !sA[0].Contains("n"))
|
|||
|
{
|
|||
|
if (!sA[0].Contains("S") && !sA[0].Contains("s"))
|
|||
|
{
|
|||
|
return false;//No Direction Found
|
|||
|
}
|
|||
|
latR = -1;
|
|||
|
}
|
|||
|
if (!sA[1].Contains("E") && !sA[1].Contains("e"))
|
|||
|
{
|
|||
|
if (!sA[1].Contains("W") && !sA[1].Contains("w"))
|
|||
|
{
|
|||
|
return false;//No Direction Found
|
|||
|
}
|
|||
|
lngR = -1;
|
|||
|
}
|
|||
|
|
|||
|
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
|||
|
sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
|
|||
|
|
|||
|
if (!double.TryParse(sA[0], out lat))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out lng))
|
|||
|
{ return false; }
|
|||
|
lat *= latR;
|
|||
|
lng *= lngR;
|
|||
|
d = new double[] { lat, lng };
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
private static bool TryDegreeDecimalMinute(string s, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
|
|||
|
|
|||
|
string[] sA = SpecialSplit(s,true);
|
|||
|
if (sA.Count() == 4 || sA.Count() == 6)
|
|||
|
{
|
|||
|
double latD;
|
|||
|
double latMS;
|
|||
|
double lngD;
|
|||
|
double lngMS;
|
|||
|
|
|||
|
double latR = 0; //Sets 1 if South
|
|||
|
double lngR = 0; //Sets 1 if West
|
|||
|
|
|||
|
//Contact get in order to combine directional indicator together with string
|
|||
|
//Should reduce 6 items to 4
|
|||
|
if (sA.Count() == 6)
|
|||
|
{
|
|||
|
if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; }
|
|||
|
else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; }
|
|||
|
else if (char.IsLetter(sA[2][0])) { sA[0] += sA[2]; }
|
|||
|
else { return false; }
|
|||
|
|
|||
|
if (char.IsLetter(sA[3][0])) { sA[3] += sA[4]; sA[4] = sA[5]; }
|
|||
|
else if (char.IsLetter(sA[4][0])) { sA[3] += sA[4]; sA[4] = sA[5]; }
|
|||
|
else if (char.IsLetter(sA[5][0])) { sA[3] += sA[5]; }
|
|||
|
else { return false; }
|
|||
|
|
|||
|
//Shift values for below logic
|
|||
|
sA[2] = sA[3];
|
|||
|
sA[3] = sA[4];
|
|||
|
}
|
|||
|
|
|||
|
//Find Directions
|
|||
|
if (!sA[0].Contains("N") && !sA[0].Contains("n") && !sA[1].Contains("N") && !sA[1].Contains("n"))
|
|||
|
{
|
|||
|
if (!sA[0].Contains("S") && !sA[0].Contains("s") && !sA[1].Contains("S") && !sA[1].Contains("s"))
|
|||
|
{
|
|||
|
return false;//No Direction Found
|
|||
|
}
|
|||
|
latR = 1;
|
|||
|
}
|
|||
|
if (!sA[2].Contains("E") && !sA[2].Contains("e") && !sA[3].Contains("E") && !sA[3].Contains("e"))
|
|||
|
{
|
|||
|
if (!sA[2].Contains("W") && !sA[2].Contains("w") && !sA[3].Contains("W") && !sA[3].Contains("w"))
|
|||
|
{
|
|||
|
return false;//No Direction Found
|
|||
|
}
|
|||
|
lngR = 1;
|
|||
|
}
|
|||
|
|
|||
|
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
|||
|
sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
|
|||
|
sA[2] = Regex.Replace(sA[2], "[^0-9.]", "");
|
|||
|
sA[3] = Regex.Replace(sA[3], "[^0-9.]", "");
|
|||
|
|
|||
|
if (!double.TryParse(sA[0], out latD))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out latMS))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out lngD))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[3], out lngMS))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
d = new double[] { latD, latMS, latR, lngD, lngMS, lngR };
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
private static bool TryDegreeMinuteSecond(string s, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
|
|||
|
|
|||
|
string[] sA = SpecialSplit(s,true);
|
|||
|
if (sA.Count() == 6 || sA.Count() == 8)
|
|||
|
{
|
|||
|
double latD;
|
|||
|
double latM;
|
|||
|
double latS;
|
|||
|
double lngD;
|
|||
|
double lngM;
|
|||
|
double lngS;
|
|||
|
|
|||
|
double latR = 0; //Sets 1 if South
|
|||
|
double lngR = 0; //Sets 1 if West
|
|||
|
|
|||
|
//Contact get in order to combine directional indicator together with string
|
|||
|
//Should reduce 8 items to 6
|
|||
|
if (sA.Count() == 8)
|
|||
|
{
|
|||
|
if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
|||
|
else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
|||
|
else if (char.IsLetter(sA[3][0])) { sA[0] += sA[3]; }
|
|||
|
else { return false; }
|
|||
|
|
|||
|
if (char.IsLetter(sA[4][0])) { sA[4] += sA[5]; sA[5] = sA[6]; sA[6] = sA[7]; }
|
|||
|
else if (char.IsLetter(sA[5][0])) { sA[4] += sA[5]; sA[5] = sA[6]; sA[6] = sA[7]; }
|
|||
|
else if (char.IsLetter(sA[7][0])) { sA[4] += sA[7]; }
|
|||
|
else { return false; }
|
|||
|
|
|||
|
//Shift values for below logic
|
|||
|
sA[3] = sA[4];
|
|||
|
sA[4] = sA[5];
|
|||
|
sA[5] = sA[6];
|
|||
|
}
|
|||
|
|
|||
|
//Find Directions
|
|||
|
if (!sA[0].Contains("N") && !sA[0].Contains("n") && !sA[2].Contains("N") && !sA[2].Contains("n"))
|
|||
|
{
|
|||
|
if (!sA[0].Contains("S") && !sA[0].Contains("s") && !sA[2].Contains("S") && !sA[2].Contains("s"))
|
|||
|
{
|
|||
|
return false;//No Direction Found
|
|||
|
}
|
|||
|
latR = 1;
|
|||
|
}
|
|||
|
if (!sA[3].Contains("E") && !sA[3].Contains("e") && !sA[5].Contains("E") && !sA[5].Contains("e"))
|
|||
|
{
|
|||
|
if (!sA[3].Contains("W") && !sA[3].Contains("w") && !sA[5].Contains("W") && !sA[5].Contains("w"))
|
|||
|
{
|
|||
|
return false;//No Direction Found
|
|||
|
}
|
|||
|
lngR = 1;
|
|||
|
}
|
|||
|
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
|||
|
sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
|
|||
|
sA[2] = Regex.Replace(sA[2], "[^0-9.]", "");
|
|||
|
sA[3] = Regex.Replace(sA[3], "[^0-9.]", "");
|
|||
|
sA[4] = Regex.Replace(sA[4], "[^0-9.]", "");
|
|||
|
sA[5] = Regex.Replace(sA[5], "[^0-9.]", "");
|
|||
|
|
|||
|
if (!double.TryParse(sA[0], out latD))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out latM))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out latS))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[3], out lngD))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[4], out lngM))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[5], out lngS))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
d = new double[] { latD, latM, latS, latR, lngD, lngM, lngS, lngR };
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
private static bool TryUTM(string s, out string[] utm)
|
|||
|
{
|
|||
|
utm = null;
|
|||
|
string[] sA = SpecialSplit(s,false);
|
|||
|
if (sA.Count() == 3 || sA.Count() == 4)
|
|||
|
{
|
|||
|
double zone;
|
|||
|
string zoneL;
|
|||
|
double easting;
|
|||
|
double northing;
|
|||
|
|
|||
|
if (sA.Count() == 4)
|
|||
|
{
|
|||
|
|
|||
|
if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
|||
|
else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
|||
|
else { return false; }
|
|||
|
}
|
|||
|
zoneL = new string(sA[0].Where(Char.IsLetter).ToArray());
|
|||
|
if (zoneL == string.Empty) { return false; }
|
|||
|
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
|||
|
|
|||
|
if (!double.TryParse(sA[0], out zone))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out easting))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out northing))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
utm = new string[] { zone.ToString(), zoneL, easting.ToString(), northing.ToString() };
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
private static bool TryMGRS(string s, out string[] mgrs)
|
|||
|
{
|
|||
|
mgrs = null;
|
|||
|
string[] sA = SpecialSplit(s,false);
|
|||
|
if (sA.Count() == 4 || sA.Count() == 5)
|
|||
|
{
|
|||
|
double zone;
|
|||
|
string zoneL;
|
|||
|
string diagraph;
|
|||
|
double easting;
|
|||
|
double northing;
|
|||
|
|
|||
|
if (sA.Count() == 5)
|
|||
|
{
|
|||
|
if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
|||
|
else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
|||
|
else { return false; }
|
|||
|
}
|
|||
|
zoneL = new string(sA[0].Where(Char.IsLetter).ToArray());
|
|||
|
if (zoneL == string.Empty) { return false; }
|
|||
|
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
|||
|
diagraph = sA[1];
|
|||
|
if (!double.TryParse(sA[0], out zone))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out easting))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[3], out northing))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
mgrs = new string[] { zone.ToString(), zoneL, diagraph, easting.ToString(), northing.ToString() };
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
private static bool TryCartesian(string s, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
string[] sA = SpecialSplit(s,false);
|
|||
|
|
|||
|
if (sA.Count() == 3)
|
|||
|
{
|
|||
|
double x;
|
|||
|
double y;
|
|||
|
double z;
|
|||
|
if (!double.TryParse(sA[0], out x))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out y))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out z))
|
|||
|
{ return false; }
|
|||
|
d = new double[] { x, y, z };
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
//KEEP DASHES FOR SIGNED AND CARTESIAN AS THEY ARE USED FOR NEGATVE VALUES
|
|||
|
private static string[] SpecialSplit(string s, bool removeDashes)
|
|||
|
{
|
|||
|
s = s.Replace("°", " ");
|
|||
|
s = s.Replace("º", " ");
|
|||
|
s = s.Replace("'", " ");
|
|||
|
s = s.Replace("\"", " ");
|
|||
|
s = s.Replace(",", " ");
|
|||
|
s = s.Replace("mE", " ");
|
|||
|
s = s.Replace("mN", " ");
|
|||
|
if (removeDashes)
|
|||
|
{
|
|||
|
s = s.Replace("-", " ");
|
|||
|
}
|
|||
|
return s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
|
|||
|
}
|
|||
|
}
|
|||
|
internal class FormatFinder_CoordPart
|
|||
|
{
|
|||
|
//Add main to Coordinate and tunnel to Format class. Add private methods to format.
|
|||
|
//WHEN PARSING NO EXCPETIONS FOR OUT OF RANGE ARGS WILL BE THROWN
|
|||
|
public static bool TryParse(string coordString, out CoordinatePart cp)
|
|||
|
{
|
|||
|
//Turn of eagerload for efficiency
|
|||
|
EagerLoad eg = new EagerLoad();
|
|||
|
int type = 0; //0 = unspecifed, 1 = lat, 2 = long;
|
|||
|
eg.Cartesian = false;
|
|||
|
eg.Celestial = false;
|
|||
|
eg.UTM_MGRS = false;
|
|||
|
cp = null;
|
|||
|
Coordinate c = new Coordinate(eg);
|
|||
|
string s = coordString;
|
|||
|
s = s.Trim(); //Trim all spaces before and after string
|
|||
|
double[] d;
|
|||
|
|
|||
|
if (s[0] == ',')
|
|||
|
{
|
|||
|
type = 2;
|
|||
|
s = s.Replace(",", "");
|
|||
|
s = s.Trim();
|
|||
|
}
|
|||
|
if (s[0] == '*')
|
|||
|
{
|
|||
|
type = 1;
|
|||
|
s = s.Replace("*", "");
|
|||
|
s = s.Trim();
|
|||
|
}
|
|||
|
|
|||
|
if (TrySignedDegree(s, type, out d))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
switch (type)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
//Attempt Lat first (default for signed)
|
|||
|
try
|
|||
|
{
|
|||
|
cp = new CoordinatePart(d[0], CoordinateType.Lat);
|
|||
|
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
cp = new CoordinatePart(d[0], CoordinateType.Long);
|
|||
|
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
|||
|
return true;
|
|||
|
}
|
|||
|
case 1:
|
|||
|
//Attempt Lat
|
|||
|
cp = new CoordinatePart(d[0], CoordinateType.Lat);
|
|||
|
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
|||
|
return true;
|
|||
|
case 2:
|
|||
|
//Attempt long
|
|||
|
cp = new CoordinatePart(d[0], CoordinateType.Long);
|
|||
|
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
//silent fail
|
|||
|
}
|
|||
|
}
|
|||
|
//SIGNED DEGREE FAILED, REMOVE DASHES FOR OTHER FORMATS
|
|||
|
s = s.Replace("-", " ");
|
|||
|
|
|||
|
//All other formats should contain 1 letter.
|
|||
|
if (Regex.Matches(s, @"[a-zA-Z]").Count != 1) { return false; } //Should only contain 1 letter.
|
|||
|
//Get Coord Direction
|
|||
|
int direction = Find_Position(s);
|
|||
|
|
|||
|
if (direction == -1)
|
|||
|
{
|
|||
|
return false; //No direction found
|
|||
|
}
|
|||
|
//If Coordinate type int specified, look for mismatch
|
|||
|
if (type == 1 && (direction == 1 || direction == 3))
|
|||
|
{
|
|||
|
return false; //mismatch
|
|||
|
}
|
|||
|
if (type == 2 && (direction == 0 || direction == 2))
|
|||
|
{
|
|||
|
return false; //mismatch
|
|||
|
}
|
|||
|
CoordinateType t;
|
|||
|
if (direction == 0 || direction == 2) { t = CoordinateType.Lat; }
|
|||
|
else { t = CoordinateType.Long; }
|
|||
|
|
|||
|
s = Regex.Replace(s, "[^0-9. ]", ""); //Remove directional character
|
|||
|
s = s.Trim(); //Trim all spaces before and after string
|
|||
|
|
|||
|
//Try Decimal Degree with Direction
|
|||
|
if (TryDecimalDegree(s, direction, out d))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
cp = new CoordinatePart(d[0], t);
|
|||
|
c.Parse_Format = Parse_Format_Type.Decimal_Degree;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
//Try DDM
|
|||
|
if (TryDegreeDecimalMinute(s, out d))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
//0 Degree
|
|||
|
//1 Minute
|
|||
|
//2 Direction (0 = N, 1 = E, 2 = S, 3 = W)
|
|||
|
cp = new CoordinatePart((int)d[0], d[1], (CoordinatesPosition)direction);
|
|||
|
c.Parse_Format = Parse_Format_Type.Degree_Decimal_Minute;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
//Try DMS
|
|||
|
if (TryDegreeMinuteSecond(s, out d))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
//0 Degree
|
|||
|
//1 Minute
|
|||
|
//2 Second
|
|||
|
//3 Direction (0 = N, 1 = E, 2 = S, 3 = W)
|
|||
|
cp = new CoordinatePart((int)d[0], (int)d[1], d[2], (CoordinatesPosition)direction);
|
|||
|
c.Parse_Format = Parse_Format_Type.Degree_Minute_Second;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch
|
|||
|
{//Parser failed try next method
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
private static bool TrySignedDegree(string s, int t, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
if (Regex.Matches(s, @"[a-zA-Z]").Count != 0) { return false; } //Should contain no letters
|
|||
|
|
|||
|
string[] sA = SpecialSplit(s, false);
|
|||
|
double deg;
|
|||
|
double min; //Minutes & MinSeconds
|
|||
|
double sec;
|
|||
|
|
|||
|
int sign = 1;
|
|||
|
switch (sA.Count())
|
|||
|
{
|
|||
|
case 1:
|
|||
|
if (!double.TryParse(sA[0], out deg))
|
|||
|
{ return false; }
|
|||
|
d = new double[] { deg };
|
|||
|
return true;
|
|||
|
case 2:
|
|||
|
if (!double.TryParse(sA[0], out deg))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out min))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
if (deg < 0) { sign = -1; }
|
|||
|
if (min >= 60 || min < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
d = new double[] { (Math.Abs(deg) + (min / 60.0)) * sign };
|
|||
|
return true;
|
|||
|
case 3:
|
|||
|
if (!double.TryParse(sA[0], out deg))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out min))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out sec))
|
|||
|
{ return false; }
|
|||
|
if (min >= 60 || min < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
if (sec >= 60 || sec < 0) { return false; } //Handle in parser as degree will be incorrect.
|
|||
|
|
|||
|
if (deg < 0) { sign = -1; }
|
|||
|
d = new double[] { (Math.Abs(deg) + (min / 60.0) + (sec / 3600.0)) * sign };
|
|||
|
return true;
|
|||
|
default:
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
private static bool TryDecimalDegree(string s, int direction, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
int sign = 1;
|
|||
|
//S or W
|
|||
|
if (direction == 2 || direction == 3)
|
|||
|
{
|
|||
|
sign = -1;
|
|||
|
}
|
|||
|
double coord;
|
|||
|
|
|||
|
string[] sA = SpecialSplit(s, true);
|
|||
|
|
|||
|
if (sA.Count() == 1)
|
|||
|
{
|
|||
|
if (!double.TryParse(s, out coord))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
coord *= sign;
|
|||
|
d = new double[] { coord };
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
private static bool TryDegreeDecimalMinute(string s, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
|
|||
|
double deg;
|
|||
|
double minSec;
|
|||
|
|
|||
|
|
|||
|
string[] sA = SpecialSplit(s,true);
|
|||
|
if (sA.Count() == 2)
|
|||
|
{
|
|||
|
if (!double.TryParse(sA[0], out deg))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out minSec))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
d = new double[] { deg, minSec };
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
private static bool TryDegreeMinuteSecond(string s, out double[] d)
|
|||
|
{
|
|||
|
d = null;
|
|||
|
|
|||
|
|
|||
|
double deg;
|
|||
|
double min;
|
|||
|
double sec;
|
|||
|
|
|||
|
string[] sA = SpecialSplit(s,true);
|
|||
|
if (sA.Count() == 3)
|
|||
|
{
|
|||
|
|
|||
|
if (!double.TryParse(sA[0], out deg))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[1], out min))
|
|||
|
{ return false; }
|
|||
|
if (!double.TryParse(sA[2], out sec))
|
|||
|
{ return false; }
|
|||
|
|
|||
|
d = new double[] { deg, min, sec };
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
private static int Find_Position(string s)
|
|||
|
{
|
|||
|
//N=0
|
|||
|
//E=1
|
|||
|
//S=2
|
|||
|
//W=3
|
|||
|
//NOPOS = -1
|
|||
|
//Find Directions
|
|||
|
|
|||
|
int part = -1;
|
|||
|
if (s.Contains("N") || s.Contains("n"))
|
|||
|
{
|
|||
|
part = 0;
|
|||
|
}
|
|||
|
if (s.Contains("E") || s.Contains("e"))
|
|||
|
{
|
|||
|
part = 1;
|
|||
|
}
|
|||
|
if (s.Contains("S") || s.Contains("s"))
|
|||
|
{
|
|||
|
part = 2;
|
|||
|
|
|||
|
}
|
|||
|
if (s.Contains("W") || s.Contains("w"))
|
|||
|
{
|
|||
|
part = 3;
|
|||
|
}
|
|||
|
return part;
|
|||
|
}
|
|||
|
|
|||
|
//KEEP DASHES FOR SIGNED AND CARTESIAN AS THEY ARE USED FOR NEGATVE VALUES
|
|||
|
private static string[] SpecialSplit(string s, bool removeDashes)
|
|||
|
{
|
|||
|
s = s.Replace("°", " ");
|
|||
|
s = s.Replace("º", " ");
|
|||
|
s = s.Replace("'", " ");
|
|||
|
s = s.Replace("\"", " ");
|
|||
|
s = s.Replace(",", " ");
|
|||
|
s = s.Replace("mE", " ");
|
|||
|
s = s.Replace("mN", " ");
|
|||
|
if(removeDashes)
|
|||
|
{
|
|||
|
s = s.Replace("-", " ");
|
|||
|
}
|
|||
|
return s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|