/// <summary> /// Equality test which is really a proximity. /// </summary> public bool Equals(CGeoLatLong Other) { bool bLatClose; bool bLongClose; if (m_dLat == 0) { bLatClose = Other.GetLat() == 0; } else { bLatClose = Math.Abs((Other.GetLat() - m_dLat) / m_dLat) < Constants.conEqualityTolerance; } if (!bLatClose) { return(false); // Get out early if we can. } if (m_dLong == 0) { bLongClose = Other.GetLong() == 0; } else { bLongClose = Math.Abs((Other.GetLong() - m_dLong) / m_dLong) < Constants.conEqualityTolerance; } return(bLongClose); }
/// <summary> /// Rotation. /// </summary> public void Rotate(CGeoLatLong Other) { m_dLat += Other.GetLat(); m_dLong += Other.GetLong(); if (m_dLat < -Constants.conHALFPI) { m_dLat = Constants.conPI + m_dLat; } if (m_dLat > Constants.conHALFPI) { m_dLat = -Constants.conPI + m_dLat; } if (m_dLong < -Constants.conPI) { m_dLong = Constants.conTWOPI + m_dLong; } if (m_dLong > Constants.conPI) { m_dLong = -Constants.conTWOPI + m_dLong; } }
/// <summary> /// Set using a heading and a range from an origin. Range in metres. /// </summary> public void Set(double dHeading, double dRange, CGeoLatLong Origin) { // alpha is the angular Distance travelled round the earths surface double alpha = dRange / Constants.conEARTH_RADIUS_METRES; double sin_alpha = Math.Sin(alpha); double cos_alpha = Math.Cos(alpha); double latO = Origin.GetLat(); double longO = Origin.GetLong(); double sin_Olat = Math.Sin(latO); double cos_Olat = Math.Cos(latO); m_dLat = Math.Asin(sin_Olat * cos_alpha + cos_Olat * sin_alpha * Math.Cos(dHeading)); m_dLong = longO + Math.Atan2(Math.Sin(dHeading) * sin_alpha * cos_Olat, cos_alpha - sin_Olat * Math.Sin(m_dLat)); while (m_dLong > Constants.conPI) { m_dLong -= Constants.conTWOPI; } while (m_dLong < -Constants.conPI) { m_dLong += Constants.conTWOPI; } }
/// <summary> /// Project the given lat long to x, y using the input parameters to store the result and retaining /// the lat long in the class passed. /// </summary> public override void Project(CGeoLatLong rLatLong, double dx, double dy) { dy = rLatLong.GetLat(); dx = rLatLong.GetLong(); Project(dy, dx); }
/// <summary> /// Assigment. /// </summary> public CGeoLatLong Set(CGeoLatLong Other) { // Simple assignment m_dLat = Other.GetLat(); m_dLong = Other.GetLong(); // Return reference to this return(this); }
/// <summary> /// Finds the range from one position to another based on sperical earth and /// great circles. Range is in metres. Error between this and WSG84 slant range is /// less than 1% at ranges up to 2000km. (Spherical Law of Math.Cosines). /// </summary> public double Range(CGeoLatLong Other) { double latO = Other.GetLat(); double longO = Other.GetLong(); if (m_dLat == latO && m_dLong == longO) { return(0); } double A = Math.Sin(m_dLat) * Math.Sin(latO) + Math.Cos(m_dLat) * Math.Cos(latO) * Math.Cos(m_dLong - longO); return(Math.Acos(A) * Constants.conEARTH_RADIUS_METRES); }
/// <summary> /// Copy constructor. /// </summary> public CGeoLatLong(CGeoLatLong Other) { // simple assignment m_dLat = Other.GetLat(); m_dLong = Other.GetLong(); }
/// <summary> /// Calculates the Range and heading to another location in degrees. /// </summary> public void RangeAndHeading(CGeoLatLong Other, out double dRangeMetres, out double hdng) { double latO = Other.GetLat(); double longO = Other.GetLong(); if (m_dLat == latO && m_dLong == longO) { dRangeMetres = 0; hdng = 0; return; } double sin_lat = Math.Sin(m_dLat); double sin_latO = Math.Sin(latO); double cos_lat = Math.Cos(m_dLat); double cos_latO = Math.Cos(latO); double cos_alpha = sin_latO * sin_lat + cos_latO * cos_lat * Math.Cos(longO - m_dLong); double alpha = Math.Acos(cos_alpha); dRangeMetres = alpha * Constants.conEARTH_RADIUS_METRES; //check to see if they are on the same line of longitude if (m_dLong == longO) { // No need to check if the locations are the same as done already. if (m_dLat > latO) { hdng = Constants.conPI; return; } else { hdng = 0; //may as well return 0 as any other return; } } if ((Math.Abs(m_dLat) == -Constants.conHALFPI) | (Math.Abs(latO) == Constants.conHALFPI)) { //check to see if the first is at the south pole or the second is at the north pole if ((m_dLat == -Constants.conHALFPI) | (latO == Constants.conHALFPI)) { hdng = 0; return; } //check to see if the first is at the north pole or the second is at the south if ((m_dLat == Constants.conHALFPI) | (latO == -Constants.conHALFPI)) { hdng = Constants.conPI; return; } } if (longO > m_dLong) { hdng = Math.Acos((sin_latO - sin_lat * cos_alpha) / (cos_lat * Math.Sin(alpha))); if ((longO - m_dLong) > Constants.conPI) { // gone from e.g. e179 to w179 hdng = Constants.conTWOPI - hdng; } } else { hdng = Constants.conTWOPI - Math.Acos((sin_latO - sin_lat * cos_alpha) / (cos_lat * Math.Sin(alpha))); if ((m_dLong - longO) > Constants.conPI) { // gone from e.g. w179 to e179 hdng = Constants.conTWOPI - hdng; } } if (hdng == Constants.conTWOPI) { hdng = 0; } }
/// <summary> /// Calculates the heading to another location in degrees. /// </summary> double Heading(CGeoLatLong Other) { double latO = Other.GetLat(); double longO = Other.GetLong(); //check to see if they are on the same line of longitude if (m_dLong == longO) { // first check to see if the locations are the same if (m_dLat == latO) { return(0); //may as well return 0 as any other } if (m_dLat > latO) { return(180); } else { return(0); } } if ((Math.Abs(m_dLat) == -Constants.conHALFPI) | (Math.Abs(latO) == Constants.conHALFPI)) { //check to see if the first is at the south pole or the second is at the north pole if ((m_dLat == -Constants.conHALFPI) | (latO == Constants.conHALFPI)) { return(0); } //check to see if the first is at the north pole or the second is at the south if ((m_dLat == Constants.conHALFPI) | (latO == -Constants.conHALFPI)) { return(180); } } double sin_lat = Math.Sin(m_dLat); double sin_latO = Math.Sin(latO); double cos_lat = Math.Cos(m_dLat); double cos_latO = Math.Cos(latO); double cos_alpha = sin_latO * sin_lat + cos_latO * cos_lat * Math.Cos(longO - m_dLong); double alpha = Math.Acos(cos_alpha); double hdng; if (longO > m_dLong) { hdng = Math.Acos((sin_latO - sin_lat * cos_alpha) / (cos_lat * Math.Sin(alpha))); if ((longO - m_dLong) > Constants.conPI) { // gone from e.g. e179 to w179 hdng = Constants.conTWOPI - hdng; } } else { hdng = Constants.conTWOPI - Math.Acos((sin_latO - sin_lat * cos_alpha) / (cos_lat * Math.Sin(alpha))); if ((m_dLong - longO) > Constants.conPI) { // gone from e.g. w179 to e179 hdng = Constants.conTWOPI - hdng; } } if (hdng == Constants.conTWOPI) { return(0); } return(hdng); }
/// <summary> /// Calculates the Range and heading to another location in degrees. /// </summary> public void RangeAndHeading(CGeoLatLong Other, out double dRangeMetres, out double hdng) { double latO = Other.GetLat(); double longO = Other.GetLong(); if (m_dLat == latO && m_dLong == longO) { dRangeMetres = 0; hdng = 0; return; } double sin_lat = Math.Sin(m_dLat); double sin_latO = Math.Sin(latO); double cos_lat = Math.Cos(m_dLat); double cos_latO = Math.Cos(latO); double cos_alpha = sin_latO * sin_lat + cos_latO * cos_lat * Math.Cos(longO - m_dLong); double alpha = Math.Acos(cos_alpha); dRangeMetres = alpha * Constants.conEARTH_RADIUS_METRES; //check to see if they are on the same line of longitude if(m_dLong == longO) { // No need to check if the locations are the same as done already. if(m_dLat > latO) { hdng = Constants.conPI; return; } else { hdng = 0;//may as well return 0 as any other return ; } } if((Math.Abs(m_dLat) == -Constants.conHALFPI) | (Math.Abs(latO) == Constants.conHALFPI)) { //check to see if the first is at the south pole or the second is at the north pole if((m_dLat == -Constants.conHALFPI) | (latO == Constants.conHALFPI)) { hdng = 0; return; } //check to see if the first is at the north pole or the second is at the south if((m_dLat == Constants.conHALFPI) | (latO ==-Constants.conHALFPI)) { hdng = Constants.conPI; return; } } if(longO > m_dLong) { hdng = Math.Acos( ( sin_latO - sin_lat * cos_alpha )/( cos_lat * Math.Sin(alpha) ) ); if ( (longO - m_dLong) > Constants.conPI) { // gone from e.g. e179 to w179 hdng = Constants.conTWOPI - hdng; } } else { hdng = Constants.conTWOPI - Math.Acos( ( sin_latO - sin_lat * cos_alpha )/( cos_lat * Math.Sin(alpha) ) ); if ( (m_dLong - longO) > Constants.conPI) { // gone from e.g. w179 to e179 hdng = Constants.conTWOPI - hdng; } } if (hdng == Constants.conTWOPI) hdng = 0; }
/// <summary> /// Equality test which is really a proximity. /// </summary> public bool Equals(CGeoLatLong Other) { bool bLatClose; bool bLongClose; if ( m_dLat == 0 ) bLatClose = Other.GetLat() == 0; else bLatClose = Math.Abs(( Other.GetLat() - m_dLat ) / m_dLat ) < Constants.conEqualityTolerance; if (!bLatClose) return false; // Get out early if we can. if ( m_dLong == 0 ) bLongClose = Other.GetLong() == 0; else bLongClose = Math.Abs((Other.GetLong() - m_dLong) / m_dLong) < Constants.conEqualityTolerance; return (bLongClose); }
/// <summary> /// Calculates the heading to another location in degrees. /// </summary> double Heading(CGeoLatLong Other) { double latO = Other.GetLat(); double longO = Other.GetLong(); //check to see if they are on the same line of longitude if(m_dLong == longO) { // first check to see if the locations are the same if (m_dLat == latO) return 0; //may as well return 0 as any other if(m_dLat > latO) return 180; else return 0; } if ((Math.Abs(m_dLat) == -Constants.conHALFPI) | (Math.Abs(latO) == Constants.conHALFPI)) { //check to see if the first is at the south pole or the second is at the north pole if((m_dLat == -Constants.conHALFPI) | (latO == Constants.conHALFPI)) return 0; //check to see if the first is at the north pole or the second is at the south if((m_dLat == Constants.conHALFPI) | (latO ==-Constants.conHALFPI)) return 180; } double sin_lat = Math.Sin(m_dLat); double sin_latO = Math.Sin(latO); double cos_lat = Math.Cos(m_dLat); double cos_latO = Math.Cos(latO); double cos_alpha = sin_latO * sin_lat + cos_latO * cos_lat * Math.Cos(longO - m_dLong); double alpha = Math.Acos(cos_alpha); double hdng; if(longO > m_dLong) { hdng = Math.Acos( ( sin_latO - sin_lat * cos_alpha )/( cos_lat * Math.Sin(alpha) ) ); if ( (longO - m_dLong) > Constants.conPI) { // gone from e.g. e179 to w179 hdng = Constants.conTWOPI - hdng; } } else { hdng = Constants.conTWOPI - Math.Acos( ( sin_latO - sin_lat * cos_alpha )/( cos_lat * Math.Sin(alpha) ) ); if ( (m_dLong - longO) > Constants.conPI) { // gone from e.g. w179 to e179 hdng = Constants.conTWOPI - hdng; } } if (hdng == Constants.conTWOPI) return 0; return hdng; }
/// <summary> /// Set using a heading and a range from an origin. Range in metres. /// </summary> public void Set(double dHeading, double dRange, CGeoLatLong Origin) { // alpha is the angular Distance travelled round the earths surface double alpha = dRange /Constants.conEARTH_RADIUS_METRES; double sin_alpha = Math.Sin(alpha); double cos_alpha = Math.Cos(alpha); double latO = Origin.GetLat(); double longO = Origin.GetLong(); double sin_Olat = Math.Sin(latO); double cos_Olat = Math.Cos(latO); m_dLat = Math.Asin( sin_Olat * cos_alpha + cos_Olat * sin_alpha * Math.Cos(dHeading) ); m_dLong = longO + Math.Atan2(Math.Sin(dHeading) * sin_alpha * cos_Olat, cos_alpha - sin_Olat * Math.Sin(m_dLat)); while (m_dLong > Constants.conPI) m_dLong -= Constants.conTWOPI; while (m_dLong < -Constants.conPI) m_dLong += Constants.conTWOPI; }
/// <summary> /// Assigment. /// </summary> public CGeoLatLong Set(CGeoLatLong Other) { // Simple assignment m_dLat = Other.GetLat(); m_dLong = Other.GetLong(); // Return reference to this return this; }
/// <summary> /// Rotation. /// </summary> public void Rotate(CGeoLatLong Other) { m_dLat += Other.GetLat(); m_dLong += Other.GetLong(); if (m_dLat < -Constants.conHALFPI) m_dLat = Constants.conPI + m_dLat; if (m_dLat > Constants.conHALFPI) m_dLat = -Constants.conPI + m_dLat; if (m_dLong < -Constants.conPI) m_dLong = Constants.conTWOPI + m_dLong; if (m_dLong > Constants.conPI) m_dLong = -Constants.conTWOPI + m_dLong; }
/// <summary> /// Finds the range from one position to another based on sperical earth and /// great circles. Range is in metres. Error between this and WSG84 slant range is /// less than 1% at ranges up to 2000km. (Spherical Law of Math.Cosines). /// </summary> public double Range(CGeoLatLong Other) { double latO = Other.GetLat(); double longO = Other.GetLong(); if (m_dLat == latO && m_dLong == longO) return 0; double A = Math.Sin(m_dLat) * Math.Sin(latO) + Math.Cos(m_dLat) * Math.Cos(latO) * Math.Cos(m_dLong - longO); return Math.Acos(A) * Constants.conEARTH_RADIUS_METRES; }