From 24aaf24c3145f46e62a4d48ce2c36c75e49c155a Mon Sep 17 00:00:00 2001 From: Sam Blackburn Date: Mon, 16 Nov 2015 19:26:15 -0500 Subject: [PATCH] Initial Code Commit Adding the source code files. --- GFC.sln | 22 + GFC/CEarth.cpp | 1193 ++++++++++++++++++++++++++++++++++++++ GFC/CEarth.hpp | 43 ++ GFC/CEarthCoordinate.cpp | 181 ++++++ GFC/CMath.hpp | 53 ++ GFC/CMath.inl | 151 +++++ GFC/CPolarCoordinate.cpp | 180 ++++++ GFC/GFC.h | 340 +++++++++++ GFC/GFC.vcxproj | 156 +++++ GFC/GFC.vcxproj.filters | 44 ++ README.md | 4 +- 11 files changed, 2366 insertions(+), 1 deletion(-) create mode 100644 GFC.sln create mode 100644 GFC/CEarth.cpp create mode 100644 GFC/CEarth.hpp create mode 100644 GFC/CEarthCoordinate.cpp create mode 100644 GFC/CMath.hpp create mode 100644 GFC/CMath.inl create mode 100644 GFC/CPolarCoordinate.cpp create mode 100644 GFC/GFC.h create mode 100644 GFC/GFC.vcxproj create mode 100644 GFC/GFC.vcxproj.filters diff --git a/GFC.sln b/GFC.sln new file mode 100644 index 0000000..b70298e --- /dev/null +++ b/GFC.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GFC", "GFC\GFC.vcxproj", "{86D51DA2-9B90-400E-BFE1-EDD24981BF6C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {86D51DA2-9B90-400E-BFE1-EDD24981BF6C}.Debug|x64.ActiveCfg = Debug|x64 + {86D51DA2-9B90-400E-BFE1-EDD24981BF6C}.Debug|x64.Build.0 = Debug|x64 + {86D51DA2-9B90-400E-BFE1-EDD24981BF6C}.Release|x64.ActiveCfg = Release|x64 + {86D51DA2-9B90-400E-BFE1-EDD24981BF6C}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/GFC/CEarth.cpp b/GFC/CEarth.cpp new file mode 100644 index 0000000..4692195 --- /dev/null +++ b/GFC/CEarth.cpp @@ -0,0 +1,1193 @@ +/* +Author: Samuel R. Blackburn +Internet: wfc@pobox.com + +"You can get credit for something or get it done, but not both." +Dr. Richard Garwin + +The MIT License (MIT) + +Copyright (c) 1997-2015 Sam Blackburn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "GFC.h" +#pragma hdrstop + +CEarth::CEarth( ELLIPSOID ellipsoid_identifier ) +{ + m_Initialize(); + SetEllipsoid( ellipsoid_identifier ); +} + +CEarth::CEarth( const CEarth& source ) +{ + m_Initialize(); + Copy( source ); +} + +CEarth::~CEarth() +{ + m_Initialize(); +} + +void CEarth::AddLineOfSightDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2, double height_above_surface_of_point_2 ) +{ + // The method used here is to convert the straight (line-of-sight) distance to + // a surface distance and then find out the position using the surface distance. + // This is a translation of the MMDIST routine found in the FORWRD3D program at + // ftp://ftp.ngs.noaa.gov/pub/pcsoft/for_inv.3d/source/forwrd3d.for + + double c = 0.0; + double cosine_of_latitude_squared = 0.0; + double cosine_of_direction_squared = 0.0; + double cosine_of_point_1_latitude = 0.0; + double difference_in_height = 0.0; + double direction_in_radians = 0.0; + double distance_adjusted_for_differences_in_height = 0.0; + double height_above_surface_of_point_1 = 0.0; + double n = 0.0; + double point_1_latitude_in_radians = 0.0; + double polar_eccentricity_squared = 0.0; + double r = 0.0; + double surface_distance = 0.0; + double term_1 = 0.0; + double term_2 = 0.0; + double term_3 = 0.0; + double two_r = 0.0; + + // Many thanks to Peter Dana (pdana@mail.utexas.edu) for educating me + // on the finer points of Geodesy, one of which was how to compute + // "second eccentricity squared" + + polar_eccentricity_squared = ( ( m_EquatorialRadiusInMeters * m_EquatorialRadiusInMeters ) - ( m_PolarRadiusInMeters * m_PolarRadiusInMeters ) ) / ( m_PolarRadiusInMeters * m_PolarRadiusInMeters ); + + point_1_latitude_in_radians = CMath::ConvertDegreesToRadians( point_1.GetUpDownAngleInDegrees() ); + direction_in_radians = CMath::ConvertDegreesToRadians( direction ); + + cosine_of_point_1_latitude = CMath::Cosine( point_1_latitude_in_radians ); + cosine_of_latitude_squared = cosine_of_point_1_latitude * cosine_of_point_1_latitude; + + cosine_of_direction_squared = CMath::Cosine( direction_in_radians ) * CMath::Cosine( direction_in_radians ); + + c = ( m_EquatorialRadiusInMeters * m_EquatorialRadiusInMeters ) / m_PolarRadiusInMeters; + + n = c / CMath::SquareRoot( 1.0 + ( polar_eccentricity_squared * cosine_of_latitude_squared ) ); + + r = n / ( 1.0 + ( polar_eccentricity_squared * cosine_of_latitude_squared * cosine_of_direction_squared ) ); + + height_above_surface_of_point_1 = point_1.GetDistanceFromSurfaceInMeters(); + + difference_in_height = height_above_surface_of_point_2 - height_above_surface_of_point_1; + + term_1 = ( distance * distance ) - ( difference_in_height * difference_in_height ); + term_2 = 1.0 + ( height_above_surface_of_point_1 / r ); + term_3 = 1.0 + ( height_above_surface_of_point_2 / r ); + distance_adjusted_for_differences_in_height = CMath::SquareRoot( term_1 / ( term_2 * term_3 ) ); + + // printf( "distance_adjusted_for_differences_in_height is %.11lf\n", distance_adjusted_for_differences_in_height ); + + two_r = 2.0 * r; + + surface_distance = two_r * CMath::ArcSine( distance_adjusted_for_differences_in_height / two_r ); + + // printf( "surface_distance is %.11lf\n", surface_distance ); + + AddSurfaceDistanceAndDirectionToCoordinate( point_1, surface_distance, direction, point_2 ); +} + +void CEarth::AddSurfaceDistanceAndDirectionToCoordinate( const CEarthCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2 ) +{ + CPolarCoordinate polar_point_1; + + Convert( point_1, polar_point_1 ); + + AddSurfaceDistanceAndDirectionToCoordinate( polar_point_1, distance, direction, point_2 ); +} + +void CEarth::AddSurfaceDistanceAndDirectionToCoordinate( const CEarthCoordinate& point_1, double distance, double direction, CEarthCoordinate& point_2 ) +{ + CPolarCoordinate polar_point_1; + CPolarCoordinate polar_point_2; + + Convert( point_1, polar_point_1 ); + + AddSurfaceDistanceAndDirectionToCoordinate( polar_point_1, distance, direction, polar_point_2 ); + + Convert( polar_point_2, point_2 ); +} + +void CEarth::AddSurfaceDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CEarthCoordinate& point_2 ) +{ + CPolarCoordinate polar_coordinate; + + AddSurfaceDistanceAndDirectionToCoordinate( point_1, distance, direction, polar_coordinate ); + + Convert( polar_coordinate, point_2 ); +} + +void CEarth::AddSurfaceDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2 ) +{ + // This is a translation of the Fortran routine DIRCT1 found in the + // FORWRD3D program at: + // ftp://ftp.ngs.noaa.gov/pub/pcsoft/for_inv.3d/source/forwrd3d.for + + double c = 0.0; + double c2a = 0.0; + double cosine_of_direction = 0.0; + double cosine_of_y = 0.0; + double cu = 0.0; + double cz = 0.0; + double d = 0.0; + double e = 0.0; + double direction_in_radians = 0.0; + double eps = 0.0; + double heading_from_point_2_to_point_1_in_radians = 0.0; + double point_1_latitude_in_radians = 0.0; + double point_1_longitude_in_radians = 0.0; + double point_2_latitude_in_radians = 0.0; + double point_2_longitude_in_radians = 0.0; + double r = 0.0; + double sa = 0.0; + double sine_of_direction = 0.0; + double sine_of_y = 0.0; + double su = 0.0; + double tangent_u = 0.0; + double term_1 = 0.0; + double term_2 = 0.0; + double term_3 = 0.0; + double x = 0.0; + double y = 0.0; + + direction_in_radians = CMath::ConvertDegreesToRadians( direction ); + + eps = 0.000000000000005; + + r = 1.0 - m_Flattening; + + point_1_latitude_in_radians = CMath::ConvertDegreesToRadians( point_1.GetUpDownAngleInDegrees() ); + point_1_longitude_in_radians = CMath::ConvertDegreesToRadians( point_1.GetLeftRightAngleInDegrees() ); + + tangent_u = ( r * CMath::Sine( point_1_latitude_in_radians ) ) / CMath::Cosine( point_1_latitude_in_radians ); + + sine_of_direction = CMath::Sine( direction_in_radians ); + + cosine_of_direction = CMath::Cosine( direction_in_radians ); + + heading_from_point_2_to_point_1_in_radians = 0.0; + + if ( cosine_of_direction != 0.0 ) + { + heading_from_point_2_to_point_1_in_radians = CMath::ArcTangentOfYOverX( tangent_u, cosine_of_direction ) * 2.0; + } + + cu = 1.0 / CMath::SquareRoot( ( tangent_u * tangent_u ) + 1.0 ); + su = tangent_u * cu; + sa = cu * sine_of_direction; + c2a = ( (-sa) * sa ) + 1.0; + x = CMath::SquareRoot( ( ( ( 1.0 / r / r ) - 1.0 ) * c2a ) + 1.0 ) + 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; + + tangent_u = distance / r / m_EquatorialRadiusInMeters / c; + + y = tangent_u; + + bool exit_loop = false; + + while( exit_loop != true ) + { + sine_of_y = CMath::Sine( y ); + cosine_of_y = CMath::Cosine( y ); + cz = CMath::Cosine( heading_from_point_2_to_point_1_in_radians + y ); + e = ( cz * cz * 2.0 ) - 1.0; + c = y; + x = e * cosine_of_y; + y = ( e + e ) - 1.0; + + term_1 = ( sine_of_y * sine_of_y * 4.0 ) - 3.0; + term_2 = ( ( term_1 * y * cz * d ) / 6.0 ) + x; + term_3 = ( ( term_2 * d ) / 4.0 ) - cz; + y = ( term_3 * sine_of_y * d ) + tangent_u; + + if ( CMath::AbsoluteValue( y - c ) > eps ) + { + exit_loop = false; + } + else + { + exit_loop = true; + } + } + + heading_from_point_2_to_point_1_in_radians = ( cu * cosine_of_y * cosine_of_direction ) - ( su * sine_of_y ); + + c = r * CMath::SquareRoot( ( sa * sa ) + ( heading_from_point_2_to_point_1_in_radians * heading_from_point_2_to_point_1_in_radians ) ); + d = ( su * cosine_of_y ) + ( cu * sine_of_y * cosine_of_direction ); + + point_2_latitude_in_radians = CMath::ArcTangentOfYOverX( d, c ); + + c = ( cu * cosine_of_y ) - ( su * sine_of_y * cosine_of_direction ); + x = CMath::ArcTangentOfYOverX( sine_of_y * sine_of_direction, c ); + c = ( ( ( ( ( -3.0 * c2a ) + 4.0 ) * m_Flattening ) + 4.0 ) * c2a * m_Flattening ) / 16.0; + d = ( ( ( ( e * cosine_of_y * c ) + cz ) * sine_of_y * c ) + y ) * sa; + + point_2_longitude_in_radians = ( point_1_longitude_in_radians + x ) - ( ( 1.0 - c ) * d * m_Flattening ); + + heading_from_point_2_to_point_1_in_radians = CMath::ArcTangentOfYOverX( sa, heading_from_point_2_to_point_1_in_radians ) + CMath::Pi(); + + point_2.SetUpDownAngleInDegrees( CMath::ConvertRadiansToDegrees( point_2_latitude_in_radians ) ); + point_2.SetLeftRightAngleInDegrees( CMath::ConvertRadiansToDegrees( point_2_longitude_in_radians ) ); +} + +void CEarth::Convert( const CEarthCoordinate& cartesian_coordinate, CPolarCoordinate& polar_coordinate ) const +{ + // convert from cartesian to polar + + double equatorial_radius_times_eccentricity_squared = 0.0; + + equatorial_radius_times_eccentricity_squared = m_EquatorialRadiusInMeters * m_EccentricitySquared; + + double p = 0.0; + + p = CMath::SquareRoot( ( cartesian_coordinate.GetXCoordinateInMeters() * cartesian_coordinate.GetXCoordinateInMeters() ) + + ( cartesian_coordinate.GetYCoordinateInMeters() * cartesian_coordinate.GetYCoordinateInMeters() ) ); + + double temp_latitude = 0.0; + double z_coordinate = cartesian_coordinate.GetZCoordinateInMeters(); // for convienance + double one_minus_eccentricity_squared = 1.0 - m_EccentricitySquared; + + temp_latitude = z_coordinate / p / one_minus_eccentricity_squared; + + double old_value = 0.0; + double part_a = 0.0; + double part_b = 0.0; + double part_c = 0.0; + + uint32_t loop_index = 0; + uint32_t maximum_number_of_tries = 1024; + + bool convergence_was_acheived = false; + + while( convergence_was_acheived != true && loop_index < maximum_number_of_tries ) + { + old_value = temp_latitude; + + part_a = one_minus_eccentricity_squared * temp_latitude * temp_latitude; + part_b = equatorial_radius_times_eccentricity_squared / CMath::SquareRoot( 1.0 + part_a ); + part_c = p - part_b; + + temp_latitude = z_coordinate / part_c; + + loop_index++; + + if ( CMath::AbsoluteValue( temp_latitude - old_value ) > 0.000000000000000000001 ) + { + // Oh well, try again... + } + else + { + // YIPEE!! We've reached convergence! + convergence_was_acheived = true; + } + } + + if ( convergence_was_acheived == true ) + { + double latitude_angle_in_radians = 0.0; + + // Save the UpDown angle in degrees + + latitude_angle_in_radians = CMath::ArcTangent( temp_latitude ); + + polar_coordinate.SetUpDownAngleInDegrees( CMath::ConvertRadiansToDegrees( latitude_angle_in_radians ) ); // Latitude + + double sine_of_latitude_in_radians = 0.0; + double cosine_of_latitude_in_radians = 0.0; + + sine_of_latitude_in_radians = CMath::Sine( latitude_angle_in_radians ); + cosine_of_latitude_in_radians = CMath::Cosine( latitude_angle_in_radians ); + + double longitude_in_radians = 0.0; + + longitude_in_radians = CMath::ArcTangentOfYOverX( cartesian_coordinate.GetYCoordinateInMeters(), cartesian_coordinate.GetXCoordinateInMeters() ); + + polar_coordinate.SetLeftRightAngleInDegrees( CMath::ConvertRadiansToDegrees( longitude_in_radians ) ); // Longitude + + double w = 0.0; + + w = CMath::SquareRoot( 1.0 - ( m_EccentricitySquared * sine_of_latitude_in_radians * sine_of_latitude_in_radians ) ); + + double distance_from_center_to_surface_of_the_ellipsoid = 0.0; + + distance_from_center_to_surface_of_the_ellipsoid = m_EquatorialRadiusInMeters / w; + + double distance_from_surface = 0.0; + + if ( CMath::AbsoluteValue( latitude_angle_in_radians ) < 0.7854 ) + { + distance_from_surface = ( p / cosine_of_latitude_in_radians ) - distance_from_center_to_surface_of_the_ellipsoid; + } + else + { + distance_from_surface = ( z_coordinate / sine_of_latitude_in_radians ) - distance_from_center_to_surface_of_the_ellipsoid + ( m_EccentricitySquared * distance_from_center_to_surface_of_the_ellipsoid ); + } + + polar_coordinate.SetDistanceFromSurfaceInMeters( distance_from_surface ); + } + else + { + // Oh well, we gave it a shot.. + polar_coordinate.Set( 0.0, 0.0, 0.0 ); + } +} + +void CEarth::Convert( const CPolarCoordinate& polar_coordinate, CEarthCoordinate& cartesian_coordinate ) const +{ + // convert from polar to cartesian + + double up_down_radians = 0.0; // latitude + double left_right_radians = 0.0; // longitude angle + + up_down_radians = CMath::ConvertDegreesToRadians( polar_coordinate.GetUpDownAngleInDegrees() ); + left_right_radians = CMath::ConvertDegreesToRadians( polar_coordinate.GetLeftRightAngleInDegrees() ); + + double sine_of_up_down_radians = 0.0; + double cosine_of_left_right_radians = 0.0; // cosine_of_longitude + double cosine_of_up_down_radians = 0.0; // cosine_of_latitude + + sine_of_up_down_radians = CMath::Sine( up_down_radians ); + cosine_of_left_right_radians = CMath::Cosine( left_right_radians ); + cosine_of_up_down_radians = CMath::Cosine( up_down_radians ); + + // Now we need to calculate the distance from the center of the ellipsoid to the surface of the ellipsoid + double w = 0.0; + + w = CMath::SquareRoot( 1.0 - ( m_EccentricitySquared * sine_of_up_down_radians * sine_of_up_down_radians ) ); + + double distance_from_center_to_surface_of_the_ellipsoid = 0.0; + + distance_from_center_to_surface_of_the_ellipsoid = m_EquatorialRadiusInMeters / w; + + double coordinate = 0.0; + + coordinate = ( distance_from_center_to_surface_of_the_ellipsoid + polar_coordinate.GetDistanceFromSurfaceInMeters() ) * cosine_of_up_down_radians * cosine_of_left_right_radians; + cartesian_coordinate.SetXCoordinateInMeters( coordinate ); + + coordinate = ( distance_from_center_to_surface_of_the_ellipsoid + polar_coordinate.GetDistanceFromSurfaceInMeters() ) * cosine_of_up_down_radians * CMath::Sine( left_right_radians ); + cartesian_coordinate.SetYCoordinateInMeters( coordinate ); + + coordinate = ( distance_from_center_to_surface_of_the_ellipsoid * ( 1.0 - m_EccentricitySquared ) + polar_coordinate.GetDistanceFromSurfaceInMeters() ) * sine_of_up_down_radians; + cartesian_coordinate.SetZCoordinateInMeters( coordinate ); +} + +void CEarth::Copy( const CEarth& source ) +{ + if ( &source != this ) + { + m_PolarRadiusInMeters = source.m_PolarRadiusInMeters; + m_EquatorialRadiusInMeters = source.m_EquatorialRadiusInMeters; + m_Flattening = source.m_Flattening; + m_EccentricitySquared = source.m_EccentricitySquared; + m_EllipsoidID = source.m_EllipsoidID; + } +} + +double CEarth::GetDistanceToHorizon( const CEarthCoordinate& point_1 ) const +{ + CPolarCoordinate polar_coordinate; + + Convert( point_1, polar_coordinate ); + + return( GetDistanceToHorizon( polar_coordinate ) ); +} + +double CEarth::GetDistanceToHorizon( const CPolarCoordinate& point_1 ) const +{ + double distance_to_horizon = 0.0; + + // d = ::sqrt( feet ) * 1.144 for nmi + // optical horizon is 1.317 * sqrt( h ); + // d= ::sqrt( 17 * height_in_meters ); d is in meters + + distance_to_horizon = CMath::SquareRoot( 17.0 * point_1.GetDistanceFromSurfaceInMeters() ); + + return( distance_to_horizon ); +} + +double CEarth::GetEquatorialRadiusInMeters( void ) const +{ + return( m_EquatorialRadiusInMeters ); +} + +double CEarth::GetPolarRadiusInMeters( void ) const +{ + return( m_PolarRadiusInMeters ); +} + +double CEarth::GetLineOfSightDistanceFromCourse( const CEarthCoordinate& current_location, const CEarthCoordinate& point_a, const CEarthCoordinate& point_b ) const +{ + // This function tells you how far off course you are from a straight line between + // point_a and point_b. + + /* + ** References: + ** I got the formula from: + ** Engineering Mathematics Handbook + ** Jan J. Tuma, Ph.D. + ** McGraw-Hill Book Company + ** 1970 + ** Library of Congress Catalog Number 78-101174 + ** page 19, (a) Oblique triangle + ** + ** Teach Yourself Trigonometry + ** P. Abbott, B.A. + ** English Universities Press Ltd. + ** 102 Newgate Street + ** London, E.C.I + ** Originally published 1940 + ** I used the 1964 printing. + ** Page 22, Figure 12 calls this "the altitude from the vertex A" + */ + + double distance_from_current_location_to_point_a = 0.0; + double distance_from_current_location_to_point_b = 0.0; + double distance_from_point_a_to_point_b = 0.0; + + distance_from_current_location_to_point_a = GetLineOfSightDistance( current_location, point_a ); + distance_from_current_location_to_point_b = GetLineOfSightDistance( current_location, point_b ); + distance_from_point_a_to_point_b = GetLineOfSightDistance( point_a, point_b ); + + double p = 0.0; + + p = distance_from_current_location_to_point_a; + p += distance_from_current_location_to_point_b; + p += distance_from_point_a_to_point_b; + p /= 2.0; + + double temp_double = 0.0; + + temp_double = p; + temp_double *= (double) ( p - distance_from_current_location_to_point_a ); + temp_double *= (double) ( p - distance_from_current_location_to_point_b ); + temp_double *= (double) ( p - distance_from_point_a_to_point_b ); + + double area = 0.0; + + area = CMath::SquareRoot( temp_double ); + + double distance_from_course = 0.0; + + // The altitude from the vertex A is two times the area of the triangle divided by the baseline + + distance_from_course = ( 2.0 * area ) / distance_from_point_a_to_point_b; + + return( distance_from_course ); +} + +double CEarth::GetLineOfSightDistance( const CEarthCoordinate& point_1, const CEarthCoordinate& point_2 ) const +{ + // This function implements the Pythagoras method of computing the distance + // between two points. + // This is a line-of-sight algorithm. It does not take into account the + // curvature of the Earth. It is not a distance on the surface algorithm. + // If you had a laser and connected the two points, this algorithm tells + // you how long the laser beam is. + + double distance = 0.0; + double x_coordinate = 0.0; + double y_coordinate = 0.0; + double z_coordinate = 0.0; + + x_coordinate = point_1.GetXCoordinateInMeters() - point_2.GetXCoordinateInMeters(); + y_coordinate = point_1.GetYCoordinateInMeters() - point_2.GetYCoordinateInMeters(); + z_coordinate = point_1.GetZCoordinateInMeters() - point_2.GetZCoordinateInMeters(); + + // Square the coordinates + x_coordinate *= x_coordinate; + y_coordinate *= y_coordinate; + z_coordinate *= z_coordinate; + + distance = CMath::SquareRoot( x_coordinate + y_coordinate + z_coordinate ); + + return( distance ); +} + +double CEarth::GetLineOfSightDistance( const CEarthCoordinate& point_1, const CPolarCoordinate& point_2 ) const +{ + CEarthCoordinate earth_center_earth_fixed_point_2; + + Convert( point_2, earth_center_earth_fixed_point_2 ); + + return( GetLineOfSightDistance( point_1, earth_center_earth_fixed_point_2 ) ); +} + +double CEarth::GetLineOfSightDistance( const CPolarCoordinate& point_1, const CEarthCoordinate& point_2 ) const +{ + CEarthCoordinate earth_center_earth_fixed_point_1; + + Convert( point_1, earth_center_earth_fixed_point_1 ); + + return( GetLineOfSightDistance( earth_center_earth_fixed_point_1, point_2 ) ); +} + +double CEarth::GetLineOfSightDistance( const CPolarCoordinate& point_1, const CPolarCoordinate& point_2 ) const +{ + CEarthCoordinate earth_center_earth_fixed_point_1; + CEarthCoordinate earth_center_earth_fixed_point_2; + + Convert( point_1, earth_center_earth_fixed_point_1 ); + Convert( point_2, earth_center_earth_fixed_point_2 ); + + return( GetLineOfSightDistance( earth_center_earth_fixed_point_1, earth_center_earth_fixed_point_2 ) ); +} + +double CEarth::GetSurfaceDistance( const CEarthCoordinate& point_1, const CEarthCoordinate& point_2, double * heading_from_point_1_to_point_2_p, double * heading_from_point_2_to_point_1_p ) const +{ + CPolarCoordinate polar_point_1; + CPolarCoordinate polar_point_2; + + Convert( point_1, polar_point_1 ); + Convert( point_2, polar_point_2 ); + + return( GetSurfaceDistance( polar_point_1, polar_point_2, heading_from_point_1_to_point_2_p, heading_from_point_2_to_point_1_p ) ); +} + +double CEarth::GetSurfaceDistance( const CEarthCoordinate& point_1, const CPolarCoordinate& point_2, double * heading_from_point_1_to_point_2_p, double * heading_from_point_2_to_point_1_p ) const +{ + CPolarCoordinate polar_point_1; + + Convert( point_1, polar_point_1 ); + + return( GetSurfaceDistance( polar_point_1, point_2, heading_from_point_1_to_point_2_p, heading_from_point_2_to_point_1_p ) ); +} + +double CEarth::GetSurfaceDistance( const CPolarCoordinate& point_1, const CEarthCoordinate& point_2, double * heading_from_point_1_to_point_2_p, double * heading_from_point_2_to_point_1_p ) const +{ + CPolarCoordinate polar_point_2; + + Convert( point_2, polar_point_2 ); + + return( GetSurfaceDistance( point_1, polar_point_2, heading_from_point_1_to_point_2_p, heading_from_point_2_to_point_1_p ) ); +} + +double CEarth::GetSurfaceDistance( const CPolarCoordinate& point_1, const CPolarCoordinate& point_2, double * heading_from_point_1_to_point_2_p, double * heading_from_point_2_to_point_1_p ) const +{ + // This is a translation of the Fortran routine INVER1 found in the + // INVERS3D program at: + // ftp://ftp.ngs.noaa.gov/pub/pcsoft/for_inv.3d/source/invers3d.for + + // Eugeny Toukh [jecat@mail.ru] found a bug in the code. + // Given the input valus of point1 1 deg S, 180 deg E and + // point2 0 deg N, 1 deg W, we go into an endless loop. + // The values of d and x will begin to oscillate, so he suggested + // testing for this condition (if the current value of x equals + // the last value of d) and exit the loop accordingly. + + // The ton of variables used... + + double c = 0.0; + double c_value_1 = 0.0; + double c_value_2 = 0.0; + double c2a = 0.0; + double cosine_of_x = 0.0; + double cy = 0.0; + double cz = 0.0; + double d = 0.0; + double e = 0.0; + double r_value = 0.0; + double s = 0.0; + double s_value_1 = 0.0; + double sa = 0.0; + double sine_of_x = 0.0; + double sy = 0.0; + double tangent_1 = 0.0; + double tangent_2 = 0.0; + double x = 0.0; + double y = 0.0; + double last_value_of_d = 0.00; + + //int loop_count = 0; + + double heading_from_point_1_to_point_2 = 0.0; + double heading_from_point_2_to_point_1 = 0.0; + + // UpDown == Latitude + // LeftRight == Longitude + + double point_1_latitude_in_radians = CMath::ConvertDegreesToRadians( point_1.GetUpDownAngleInDegrees() ); + double point_1_longitude_in_radians = CMath::ConvertDegreesToRadians( point_1.GetLeftRightAngleInDegrees() ); + double point_2_latitude_in_radians = CMath::ConvertDegreesToRadians( point_2.GetUpDownAngleInDegrees() ); + double point_2_longitude_in_radians = CMath::ConvertDegreesToRadians( point_2.GetLeftRightAngleInDegrees() ); + + r_value = 1.0 - m_Flattening; + tangent_1 = ( r_value * CMath::Sine( point_1_latitude_in_radians ) ) / CMath::Cosine( point_1_latitude_in_radians ); + tangent_2 = ( r_value * CMath::Sine( point_2_latitude_in_radians ) ) / CMath::Cosine( point_2_latitude_in_radians ); + c_value_1 = 1.0 / CMath::SquareRoot( ( tangent_1 * tangent_1 ) + 1.0 ); + s_value_1 = c_value_1 * tangent_1; + c_value_2 = 1.0 / CMath::SquareRoot( ( tangent_2 * tangent_2 ) + 1.0 ); + s = c_value_1 * c_value_2; + + heading_from_point_2_to_point_1 = s * tangent_2; // backward_azimuth + heading_from_point_1_to_point_2 = heading_from_point_2_to_point_1 * tangent_1; + + x = point_2_longitude_in_radians - point_1_longitude_in_radians; + + bool exit_loop = false; + + while( exit_loop != true ) + { + sine_of_x = CMath::Sine( x ); + cosine_of_x = CMath::Cosine( x ); + tangent_1 = c_value_2 * sine_of_x; + tangent_2 = heading_from_point_2_to_point_1 - ( s_value_1 * c_value_2 * cosine_of_x ); + sy = CMath::SquareRoot( ( tangent_1 * tangent_1 ) + ( tangent_2 * tangent_2 ) ); + cy = ( s * cosine_of_x ) + heading_from_point_1_to_point_2; + y = CMath::ArcTangentOfYOverX( sy, cy ); + + // Thanks to John Werner (werner@tij.wb.xerox.com) for + // finding a bug where sy could be zero. Here's his fix: + + if ( ( s * sine_of_x ) == 0.0 && ( sy == 0.0 ) ) + { + sa = 1.0; + } + else + { + sa = ( s * sine_of_x ) / sy; + } + + c2a = ( (-sa) * sa ) + 1.0; + cz = heading_from_point_1_to_point_2 + heading_from_point_1_to_point_2; + + if ( c2a > 0.0 ) + { + cz = ( (-cz) / c2a ) + cy; + } + + e = ( cz * cz * 2.0 ) - 1.0; + c = ( ( ( ( ( -3.0 * c2a ) + 4.0 ) * m_Flattening ) + 4.0 ) * c2a * m_Flattening ) / 16.0; + d = x; + x = ( ( ( ( e * cy * c ) + cz ) * sy * c ) + y ) * sa; + x = ( ( 1.0 - c ) * x * m_Flattening ) + point_2_longitude_in_radians - point_1_longitude_in_radians; + + if ( CMath::AbsoluteValue( d - x ) > 0.00000000000000000000005 && + x != last_value_of_d ) + { + exit_loop = false; + last_value_of_d = d; + } + else + { + exit_loop = true; + } + } + + heading_from_point_1_to_point_2 = CMath::ArcTangentOfYOverX( tangent_1, tangent_2 ); + + double temp_decimal_degrees = 0.0; + + temp_decimal_degrees = CMath::ConvertRadiansToDegrees( heading_from_point_1_to_point_2 ); + + if ( temp_decimal_degrees < 0.0 ) + { + temp_decimal_degrees += 360.0; + } + + if ( heading_from_point_1_to_point_2_p != nullptr ) + { + // The user passed us a pointer, don't trust it. + // If you are using Visual C++ on Windows NT, the following + // try/catch block will ensure you won't blow up when random + // pointers are passed to you. If you are on a legacy operating + // system like Unix, you are screwed. + + try + { + *heading_from_point_1_to_point_2_p = temp_decimal_degrees; + } + catch( ... ) + { + // Do Nothing + } + } + + heading_from_point_2_to_point_1 = CMath::ArcTangentOfYOverX( c_value_1 * sine_of_x, ( (heading_from_point_2_to_point_1 * cosine_of_x ) - ( s_value_1 * c_value_2 ) ) ) + CMath::Pi(); + + temp_decimal_degrees = CMath::ConvertRadiansToDegrees( heading_from_point_2_to_point_1 ); + + if ( temp_decimal_degrees < 0 ) + { + temp_decimal_degrees += 360.0; + } + + if ( heading_from_point_2_to_point_1_p != nullptr) + { + // The user passed us a pointer, don't trust it. + // If you are using Visual C++ on Windows NT, the following + // try/catch block will ensure you won't blow up when random + // pointers are passed to you. If you are on a legacy operating + // system like Unix, you are screwed. + + try + { + *heading_from_point_2_to_point_1_p = temp_decimal_degrees; + } + catch( ... ) + { + // Do Nothing + } + } + + x = CMath::SquareRoot( ( ( ( 1.0 / r_value / r_value ) - 1 ) * c2a ) + 1.0 ) + 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; + + // 1998-09-01 + // Thanks go to Gerard Murphy (bjmillar@dera.gov.uk) for finding a typo here. + + x = e * cy; + + s = ( 1.0 - e ) - e; + + double term_1 = 0.0; + double term_2 = 0.0; + double term_3 = 0.0; + double term_4 = 0.0; + double term_5 = 0.0; + + term_1 = ( sy * sy * 4.0 ) - 3.0; + term_2 = ( ( s * cz * d ) / 6.0 ) - x; + term_3 = term_1 * term_2; + term_4 = ( ( term_3 * d ) / 4.0 ) + cz; + term_5 = ( term_4 * sy * d ) + y; + + s = term_5 * c * m_EquatorialRadiusInMeters * r_value; + + return( s ); +} + +void CEarth::m_ComputeEccentricitySquared( void ) +{ + if ( m_Flattening == 0.0 ) + { + m_EccentricitySquared = 0.0; + return; + } + + m_EccentricitySquared = ( 2.0 * m_Flattening ) - ( m_Flattening * m_Flattening ); +} + +void CEarth::m_ComputeFlattening( void ) +{ + if ( m_EquatorialRadiusInMeters == 0.0 || m_PolarRadiusInMeters == 0.0 ) + { + return; + } + + m_Flattening = CMath::AbsoluteValue( m_EquatorialRadiusInMeters - m_PolarRadiusInMeters ) / m_EquatorialRadiusInMeters; +} + +void CEarth::m_Initialize( void ) +{ + m_EllipsoidID = 0; + m_PolarRadiusInMeters = 0.0; + m_EquatorialRadiusInMeters = 0.0; + m_Flattening = 0.0; + m_EccentricitySquared = 0.0; +} + +void CEarth::SetEllipsoid(ELLIPSOID ellipsoid_identifier ) +{ + m_EllipsoidID = ellipsoid_identifier; + + switch( ellipsoid_identifier ) + { + case Perfect_Sphere: + + m_EquatorialRadiusInMeters = 6378137.0; + m_PolarRadiusInMeters = 6378137.0; + + break; + + case Airy: + + m_EquatorialRadiusInMeters = 6377563.396; + m_PolarRadiusInMeters = 6356256.909237; + + break; + + case Austrailian_National: + + m_EquatorialRadiusInMeters = 6378160.0; + m_PolarRadiusInMeters = 6356774.719195; + + break; + + case Bessell_1841: + + m_EquatorialRadiusInMeters = 6377397.155; + m_PolarRadiusInMeters = 6356078.962818; + + break; + + case Bessel_1841_Nambia: + + m_EquatorialRadiusInMeters = 6377483.865; + m_PolarRadiusInMeters = 6356165.382966; + + break; + + case Clarke_1866: + + m_EquatorialRadiusInMeters = 6378206.4; + m_PolarRadiusInMeters = 6356583.799999; + + break; + + case Clarke_1880: + + m_EquatorialRadiusInMeters = 6378249.145; + m_PolarRadiusInMeters = 6356514.86955; + + break; + + case Everest: + + m_EquatorialRadiusInMeters = 6377276.345; + m_PolarRadiusInMeters = 6356075.41314; + + break; + + case Fischer_1960_Mercury: + + m_EquatorialRadiusInMeters = 6378166.0; + m_PolarRadiusInMeters = 6356784.283607; + + break; + + case Fischer_1968: + + m_EquatorialRadiusInMeters = 6378150.0; + m_PolarRadiusInMeters = 6356768.337244; + + break; + + case GRS_1967: + + m_EquatorialRadiusInMeters = 6378160.0; + m_PolarRadiusInMeters = 6356774.516091; + + break; + + case GRS_1980: + + m_EquatorialRadiusInMeters = 6378137.0; + m_PolarRadiusInMeters = 6356752.31414; + + break; + + case Helmert_1906: + + m_EquatorialRadiusInMeters = 6378200.0; + m_PolarRadiusInMeters = 6356818.169628; + + break; + + case Hough: + + m_EquatorialRadiusInMeters = 6378270.0; + m_PolarRadiusInMeters = 6356794.343434; + + break; + + case International: + + m_EquatorialRadiusInMeters = 6378388.0; + m_PolarRadiusInMeters = 6356911.946128; + + break; + + case Krassovsky: + + m_EquatorialRadiusInMeters = 6378245.0; + m_PolarRadiusInMeters = 6356863.018773; + + break; + + case Modified_Airy: + + m_EquatorialRadiusInMeters = 6377340.189; + m_PolarRadiusInMeters = 6356034.447939; + + break; + + case Modified_Everest: + + m_EquatorialRadiusInMeters = 6377304.063; + m_PolarRadiusInMeters = 6356103.038993; + + break; + + case Modified_Fischer_1960: + + m_EquatorialRadiusInMeters = 6378155.0; + m_PolarRadiusInMeters = 6356773.320483; + + break; + + case South_American_1969: + + m_EquatorialRadiusInMeters = 6378160.0; + m_PolarRadiusInMeters = 6356774.719195; + + break; + + case Topex_Poseidon_Pathfinder_ITRF: // Source is http://neptune.gsfc.nasa.gov/~krachlin/corr/refframe.html + + m_EquatorialRadiusInMeters = 6378136.3; + m_PolarRadiusInMeters = 6356751.6005629376; + + break; + + case WGS_60: + + m_EquatorialRadiusInMeters = 6378165.0; + m_PolarRadiusInMeters = 6356783.286959; + + break; + + case WGS_66: + + m_EquatorialRadiusInMeters = 6378145.0; + m_PolarRadiusInMeters = 6356759.769489; + + break; + + case WGS_72: + + m_EquatorialRadiusInMeters = 6378135.0; + m_PolarRadiusInMeters = 6356750.520016; + + break; + + case WGS_84: + + // Computed polar radius from the flattening value specified at + // http://acro.harvard.edu/SSA/BGA/wg84figs.html + // because it had the most digits after the decimal point. + + m_EquatorialRadiusInMeters = 6378137.0; + m_PolarRadiusInMeters = 6356752.3142451793; + + break; + + case Unknown: + default: + + m_EllipsoidID = Unknown; + + m_Initialize(); + return; + } + + m_ComputeFlattening(); + m_ComputeEccentricitySquared(); +} + +void CEarth::SetEllipsoidByRadii( double equatorial_radius, double polar_radius ) +{ + m_EquatorialRadiusInMeters = equatorial_radius; + m_PolarRadiusInMeters = polar_radius; + m_EllipsoidID = Custom; + + m_ComputeFlattening(); + m_ComputeEccentricitySquared(); +} + +void CEarth::SetEllipsoidByEquatorialRadiusAndFlattening( double equatorial_radius, double flattening ) +{ + m_EquatorialRadiusInMeters = equatorial_radius; + m_Flattening = flattening; + m_EllipsoidID = Custom; + + // We must compute the polar radius + + double temp_double = m_Flattening * m_EquatorialRadiusInMeters; + + m_PolarRadiusInMeters = m_EquatorialRadiusInMeters - temp_double; + + m_ComputeEccentricitySquared(); +} + +CEarth& CEarth::operator=( const CEarth& source ) +{ + Copy( source ); + return( *this ); +} + +#if 0 + +GFC - CEarth + +

CEarth

+$Revision: 14 $ +
+

Description

+This class encapsulates the Earth. It holds the data necessary to perform the +calculations of distance and direction. The Earth is not a perfect sphere. +It is an ellipsoid (flattened at the top and bottom). All angles are expressed +in degrees and all distances are expressed in meters. +

Methods

+
+
void AddLineOfSightDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2, double height_above_surface_of_point_2 = 0.0 )
+If you were to shine a laser from point_1 pointing towards direction +for distance meters, this function will tell you what location you would +be at. It will also let you specify a point height_above_surface_of_point_2 +meters above the surface. This method does not take into account the curvature of +the Earth. +
void AddSurfaceDistanceAndDirectionToCoordinate( const CEarthCoordinate& point_1, double distance, double direction, CEarthCoordinate& point_2 )
+void AddSurfaceDistanceAndDirectionToCoordinate( const CEarthCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2 )
+void AddSurfaceDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CEarthCoordinate& point_2 )
+void AddSurfaceDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2 )
+This allows you to add a distance over the surface of the Earth to a location and +get a new location. It answers the question "If I head out in this direction +for that amout of meters, where will I be?" +
void Convert( const CEarthCoordinate& cartesian_coordinate, CPolarCoordinate& polar_coordinate ) const
+void Convert( const CPolarCoordinate& polar_coordinate, CEarthCoordinate& cartesian_coordinate ) const
+This method allows you to convert from polar and cartestian coordinates. +
double GetDistanceToHorizon( const CEarthCoordinate& point_1 ) const
+double GetDistanceToHorizon( const CPolarCoordinate& point_1 ) const
+This tells you how far (in meters) from the horizon point_1 is. +
double GetEquatorialRadiusInMeters( void ) const
+This tells you what the equatorial radius is in meters for the selected ellipsoid. +
double GetPolarRadiusInMeters( void ) const
+This tells you what the polar radius is in meters for the selected ellipsoid. +
double GetLineOfSightDistanceFromCourse( const CEarthCoordinate& current_location, const CEarthCoordinate& point_a, const CEarthCoordinate& point_b ) const
+Draw a line from point_a to point_b. This function will tell +you how far current_location is from that line. +
double GetLineOfSightDistance( const CEarthCoordinate& point_1, const CEarthCoordinate& point_2 ) const
+double GetLineOfSightDistance( const CPolarCoordinate& point_1, const CEarthCoordinate& point_2 ) const
+double GetLineOfSightDistance( const CEarthCoordinate& point_1, const CPolarCoordinate& point_2 ) const
+double GetLineOfSightDistance( const CPolarCoordinate& point_1, const CPolarCoordinate& point_2 ) const
+This will tell you how many meters it is between two points. It answers the question, "If I +pointed a laser from point_1 to point_2, how far would the +laser beam travel?" +
double GetSurfaceDistance( const CEarthCoordinate& point_1, const CEarthCoordinate& point_2, double * heading_from_point_1_to_point_2 = 0, double * heading_from_point_2_to_point_1 = 0 ) const
+double GetSurfaceDistance( const CEarthCoordinate& point_1, const CPolarCoordinate& point_2, double * heading_from_point_1_to_point_2 = 0, double * heading_from_point_2_to_point_1 = 0 ) const
+double GetSurfaceDistance( const CPolarCoordinate& point_1, const CEarthCoordinate& point_2, double * heading_from_point_1_to_point_2 = 0, double * heading_from_point_2_to_point_1 = 0 ) const
+double GetSurfaceDistance( const CPolarCoordinate& point_1, const CPolarCoordinate& point_2, double * heading_from_point_1_to_point_2 = 0, double * heading_from_point_2_to_point_1 = 0 ) const
+This will tell you how many meters it is between two points. It answers the question, "If I +were to walk from point_1 to point_2, how far would I walk?" +
void SetEllipsoid( int ellipsoid )
+This allows you to set the ellipsoid used by CEarth in its calculations. The +default is WGS84 which is generally accepted as being the closest +approximation of the Earth's ellipsoid. The ellipsoid parameter +may be one of the following: +
    +
  • Perfect_Sphere +
  • Airy +
  • Austrailian_National +
  • Bessell_1841 +
  • Bessel_1841_Nambia +
  • Clarke_1866 +
  • Clarke_1880 +
  • Everest +
  • Fischer_1960_Mercury +
  • Fischer_1968 +
  • GRS_1967 +
  • GRS_1980 +
  • Helmert_1906 +
  • Hough +
  • International +
  • Krassovsky +
  • Modified_Airy +
  • Modified_Everest +
  • Modified_Fischer_1960 +
  • South_American_1969 +
  • Topex_Poseidon_Pathfinder_ITRF +
  • WGS_60 +
  • WGS_66 +
  • WGS_72 +
  • WGS_84 +
  • NAD_27 +
  • Tokyo +
+
void SetEllipsoidByRadii( double equatorial_radius, double polar_radius )
+This let's you use your own (custom) values to describe the ellipsoid of the Earth. +
void SetEllipsoidByEquatorialRadiusAndFlattening( double equatorial_radius, double flattening )
+This let's you use your own (custom) values to describe the ellipsoid of the Earth. +
+

Example

+
#include <stdio.h>
+#include <GFC.h>
+#pragma hdrstop
+
+void main( void )
+{
+   // Let's figure out how far it is from here to there
+
+   CPolarCoordinate here;
+   CPolarCoordinate there;
+
+   // Convert from Latitude/Longitude to coordinates our system understands
+
+   // here is 39 degrees 12.152 minutes North Latitude, 76 degrees 46.795 minutes West Longitude
+   here.SetUpDownAngleInDegrees(     CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees(  39.0, 12.152, 0.0 ) );
+   here.SetLeftRightAngleInDegrees(  CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees( -76.0, 46.795, 0.0 ) );
+
+   // there is 12 degrees 8.535 minutes North Latitude, 68 degrees 16.547 West Longitude
+   there.SetUpDownAngleInDegrees(    CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees(  12.0,  8.535, 0.0 ) );
+   there.SetLeftRightAngleInDegrees( CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees( -68.0, 16.547, 0.0 ) );
+
+   CEarth earth; // We are talking about the earth...
+
+   double distance_in_meters         = 0.0;
+   double heading_from_here_to_there = 0.0;
+   double heading_from_there_to_here = 0.0;
+
+   distance_in_meters = earth.GetSurfaceDistance( here, there, &heading_from_here_to_there, &heading_from_there_to_here );
+
+   printf( "Distance between here and there: %.23lf meters\nHeading from here to there:      %.19lf degrees\nHeading from there to here:      %.19lf degrees\n",
+           distance_in_meters,
+           heading_from_here_to_there,
+           heading_from_there_to_here );
+
+   double degrees = 0.0;
+   double minutes = 0.0;
+   double seconds = 0.0;
+
+   CMath::ConvertDecimalDegreesToDegreesMinutesSeconds( heading_from_here_to_there, degrees, minutes, seconds );
+   printf( "Heading %lf degrees, %lf minutes, %lf seconds\n", degrees, minutes, seconds );
+
+   CMath::ConvertDecimalDegreesToDegreesMinutesSeconds( heading_from_there_to_here, degrees, minutes, seconds );
+   printf( "Heading %lf degrees, %lf minutes, %lf seconds\n", degrees, minutes, seconds );
+}
+
Copyright, 1998, Samuel R. Blackburn
+$Workfile: CEarth.cpp $
+$Modtime: 8/06/00 10:30a $ + + +ToolTipFormatLine=CEarth=m_EllipsoidID= +#endif diff --git a/GFC/CEarth.hpp b/GFC/CEarth.hpp new file mode 100644 index 0000000..c58232a --- /dev/null +++ b/GFC/CEarth.hpp @@ -0,0 +1,43 @@ +/* +Author: Samuel R. Blackburn +Internet: wfc@pobox.com + +"You can get credit for something or get it done, but not both." +Dr. Richard Garwin + +The MIT License (MIT) + +Copyright (c) 1997-2015 Sam Blackburn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#if ! defined( EARTH_CLASS_HEADER_FILE ) + +#define EARTH_CLASS_HEADER_FILE + +class CEarth +{ + public: + + CEarth(); + virtual ~CEarth(); +}; + +#endif // EARTH_CLASS_HEADER_FILE diff --git a/GFC/CEarthCoordinate.cpp b/GFC/CEarthCoordinate.cpp new file mode 100644 index 0000000..92b9af6 --- /dev/null +++ b/GFC/CEarthCoordinate.cpp @@ -0,0 +1,181 @@ +/* +Author: Samuel R. Blackburn +Internet: wfc@pobox.com + +"You can get credit for something or get it done, but not both." +Dr. Richard Garwin + +The MIT License (MIT) + +Copyright (c) 1997-2015 Sam Blackburn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "GFC.h" +#pragma hdrstop + +CEarthCoordinate::CEarthCoordinate( void ) +{ + m_X_CoordinateInMeters = 0.0; + m_Y_CoordinateInMeters = 0.0; + m_Z_CoordinateInMeters = 0.0; +} + +CEarthCoordinate::CEarthCoordinate( const CEarthCoordinate& source ) +{ + Copy( source ); +} + +CEarthCoordinate::~CEarthCoordinate( void ) +{ + m_X_CoordinateInMeters = 0.0; + m_Y_CoordinateInMeters = 0.0; + m_Z_CoordinateInMeters = 0.0; +} + +void CEarthCoordinate::Copy( const CEarthCoordinate& source ) +{ + m_X_CoordinateInMeters = source.m_X_CoordinateInMeters; + m_Y_CoordinateInMeters = source.m_Y_CoordinateInMeters; + m_Z_CoordinateInMeters = source.m_Z_CoordinateInMeters; +} + +void CEarthCoordinate::Get( double& x_coordinate, double& y_coordinate, double& z_coordinate ) const +{ + x_coordinate = m_X_CoordinateInMeters; + y_coordinate = m_Y_CoordinateInMeters; + z_coordinate = m_Z_CoordinateInMeters; +} + +double CEarthCoordinate::GetXCoordinateInMeters( void ) const +{ + return( m_X_CoordinateInMeters ); +} + +double CEarthCoordinate::GetYCoordinateInMeters( void ) const +{ + return( m_Y_CoordinateInMeters ); +} + +double CEarthCoordinate::GetZCoordinateInMeters( void ) const +{ + return( m_Z_CoordinateInMeters ); +} + +void CEarthCoordinate::Set( double x_coordinate, double y_coordinate, double z_coordinate ) +{ + m_X_CoordinateInMeters = x_coordinate; + m_Y_CoordinateInMeters = y_coordinate; + m_Z_CoordinateInMeters = z_coordinate; +} + +void CEarthCoordinate::SetXCoordinateInMeters( double x_coordinate ) +{ + m_X_CoordinateInMeters = x_coordinate; +} + +void CEarthCoordinate::SetYCoordinateInMeters( double y_coordinate ) +{ + m_Y_CoordinateInMeters = y_coordinate; +} + +void CEarthCoordinate::SetZCoordinateInMeters( double z_coordinate ) +{ + m_Z_CoordinateInMeters = z_coordinate; +} + +CEarthCoordinate& CEarthCoordinate::operator=( const CEarthCoordinate& source ) +{ + Copy( source ); + return( *this ); +} + +#if 0 + +GFC - CEarthCoordinate + +

CEarthCoordinate

+$Revision: 5 $ +
+

Description

+This class encapsulates an Earth-Centered-Earth-Fixed coordinate. +This is also known as a cartesian coordinate. It is made up of three +distances all originating at the center of the Earth. +

Constructors

+
+
CEarthCoordinate()
+CEarthCoordinate( const CEarthCoordinate& source )
+Constructs an empty coordinate or copies another CEarthCoordinate. +
+

Methods

+
+
void Copy( const CEarthCoordinate& coordinate )
+Copies the contents of another CEarthCoordinate. +
void Get( double& x_coordinate, double& y_coordinate, double& z_coordinate )
+This allows you to retrieve all the data members in one function call. +
double GetXCoordinateInMeters( void ) const
+This method returns the X axis coordinate in meters. +Positive values point towards the intersection of the Prime Meridian and the Equator. +
double GetYCoordinateInMeters( void ) const
+This method returns the Y axis coordinate in meters. +Positive values point towards the intersection of 90 degrees east of Prime Meridian and the Equator. +
double GetZCoordinateInMeters( void ) const
+This method returns the Z axis coordinate in meters. +Positive values point towards the North Pole, negative values towards the South Pole. +
void Set( double x_coordinate, double y_coordinate, double z_coordinate )
+This lets you set all of the data members in a single function call. +
void SetXCoordinateInMeters( double x_coordinate )
+This method sets the X axis coordinate in meters. +
void SetYCoordinateInMeters( double y_coordinate )
+This method sets the Y axis coordinate in meters. +
void SetZCoordinateInMeters( double z_coordinate )
+This method sets the Z axis coordinate in meters. +
+

Operators

+
+
= ( const CEarthCoordinate& source )
+Basically calls Copy(). +
+

Example

+
#include <stdio.h>
+#include <GFC.h>
+#pragma hdrstop
+
+void main( void )
+{
+   CPolarCoordinate here;
+   CEarthCoordinate there;
+
+   // here is 39 degrees 12.152 minutes North Latitude, 76 degrees 46.795 minutes West Longitude
+   here.SetUpDownAngleInDegrees(     CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees(  39.0, 12.152, 0.0 ) );
+   here.SetLeftRightAngleInDegrees(  CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees( -76.0, 46.795, 0.0 ) );
+   here.SetDistanceFromSurfaceInMeters( 1000.0 );
+
+   CEarth earth;
+   
+   earth.Convert( here, there );
+}
+
Copyright, 1998, Samuel R. Blackburn
+$Workfile: CEarthCoordinate.cpp $
+$Modtime: 5/16/00 8:20a $ + + +#endif + diff --git a/GFC/CMath.hpp b/GFC/CMath.hpp new file mode 100644 index 0000000..8af067d --- /dev/null +++ b/GFC/CMath.hpp @@ -0,0 +1,53 @@ +/* +Author: Samuel R. Blackburn +Internet: wfc@pobox.com + +"You can get credit for something or get it done, but not both." +Dr. Richard Garwin + +The MIT License (MIT) + +Copyright (c) 1997-2015 Sam Blackburn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#if ! defined( MATH_CLASS_HEADER_FILE ) + +#define MATH_CLASS_HEADER_FILE + +#define HALF_OF_PI 1.5707963267948966 +#define ONE_FOURTH_OF_PI 0.78539816339744833 +#define PI 3.14159265358979323846 +#define TWO_TIMES_PI 6.2831853071795864769 +#define RADIANS_TO_DEGREES 57.29577951308232 +#define DEGREES_TO_RADIANS .0174532925199432958 + +class CMath +{ + public: + + CMath(); + virtual ~CMath(); + + double Cosine( const double value ); + double Tangent( const double value ); +}; + +#endif // EARTH_CLASS_HEADER_FILE diff --git a/GFC/CMath.inl b/GFC/CMath.inl new file mode 100644 index 0000000..2932627 --- /dev/null +++ b/GFC/CMath.inl @@ -0,0 +1,151 @@ +/* +Author: Samuel R. Blackburn +Internet: wfc@pobox.com + +"You can get credit for something or get it done, but not both." +Dr. Richard Garwin + +The MIT License (MIT) + +Copyright (c) 1997-2015 Sam Blackburn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +inline double CMath::AbsoluteValue( const double& value ) +{ + return( ::fabs( value ) ); +} + +inline double CMath::ArcCosine( const double& value ) +{ + return( ::acos( value ) ); +} + +inline double CMath::ArcSine( const double& value ) +{ + return( ::asin( value ) ); +} + +inline double CMath::ArcTangent( const double& value ) +{ + return( ::atan( value ) ); +} + +inline double CMath::ArcTangentOfYOverX( const double& y, const double& x ) +{ + return( ::atan2( y, x ) ); +} + +inline double CMath::Ceiling( const double& value ) +{ + return( ::ceil( value ) ); +} + +inline void CMath::ConvertDecimalDegreesToDegreesMinutesSeconds( double decimal_degrees, double& degrees, double& minutes, double& seconds ) +{ + double fractional_part = 0.0; + + double integer_part = 0; + + fractional_part = ::modf( decimal_degrees, &integer_part ); + + degrees = integer_part; + + if ( decimal_degrees < 0.0 ) + { + fractional_part *= (-1.0); + } + + minutes = fractional_part * 60.0; + + fractional_part = ::modf( minutes, &integer_part ); + + minutes = integer_part; + + seconds = fractional_part * 60.0; +} + +inline double CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees( double degrees, double minutes, double seconds ) +{ + double decimal_degrees = 0.0; + + decimal_degrees = degrees; + + if ( decimal_degrees < 0.0 ) + { + decimal_degrees *= (-1.0); + } + + decimal_degrees += (double) ( minutes / 60.0 ); + decimal_degrees += (double) ( seconds / 3600.0 ); + + if ( degrees < 0.0 ) + { + decimal_degrees *= (-1.0); + } + + return( decimal_degrees ); +} + +inline double CMath::ConvertDegreesToRadians( const double& degrees ) +{ + double radians = 0.0; + double pi_divided_by_180 = CMath::Pi() / 180.0; + + radians = degrees * pi_divided_by_180; + + return( radians ); +} + +inline double CMath::ConvertRadiansToDegrees( const double& radians ) +{ + double degrees = 0.0; + + double conversion_factor = 180.0 / CMath::Pi(); + + degrees = radians * conversion_factor; + + return( degrees ); +} + +inline double CMath::Cosine( const double& value ) +{ + return( ::cos( value ) ); +} + +inline double CMath::HyperbolicCosine( const double& value ) +{ + return( ::cosh( value ) ); +} + +inline double CMath::Pi( void ) +{ + return( 3.1415926535897932384626433832795028841971693993751058209749445923078164 ); +} + +inline double CMath::Sine( const double& value ) +{ + return( ::sin( value ) ); +} + +inline double CMath::SquareRoot( const double& value ) +{ + return( ::sqrt( value ) ); +} \ No newline at end of file diff --git a/GFC/CPolarCoordinate.cpp b/GFC/CPolarCoordinate.cpp new file mode 100644 index 0000000..5b61f6a --- /dev/null +++ b/GFC/CPolarCoordinate.cpp @@ -0,0 +1,180 @@ +/* +Author: Samuel R. Blackburn +Internet: wfc@pobox.com + +"You can get credit for something or get it done, but not both." +Dr. Richard Garwin + +The MIT License (MIT) + +Copyright (c) 1997-2015 Sam Blackburn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "GFC.h" +#pragma hdrstop + +CPolarCoordinate::CPolarCoordinate( void ) +{ + m_UpDownAngleInDegrees = 0.0; + m_LeftRightAngleInDegrees = 0.0; + m_DistanceFromSurfaceInMeters = 0.0; +} + +CPolarCoordinate::CPolarCoordinate( const CPolarCoordinate& source ) +{ + Copy( source ); +} + +CPolarCoordinate::~CPolarCoordinate( void ) +{ + m_UpDownAngleInDegrees = 0.0; + m_LeftRightAngleInDegrees = 0.0; + m_DistanceFromSurfaceInMeters = 0.0; +} + +void CPolarCoordinate::Copy( const CPolarCoordinate& source ) +{ + m_UpDownAngleInDegrees = source.m_UpDownAngleInDegrees; + m_LeftRightAngleInDegrees = source.m_LeftRightAngleInDegrees; + m_DistanceFromSurfaceInMeters = source.m_DistanceFromSurfaceInMeters; +} + +void CPolarCoordinate::Get( double& up_down_angle, double& left_right_angle, double& length ) const +{ + up_down_angle = m_UpDownAngleInDegrees; + left_right_angle = m_LeftRightAngleInDegrees; + length = m_DistanceFromSurfaceInMeters; +} + +double CPolarCoordinate::GetUpDownAngleInDegrees( void ) const +{ + return( m_UpDownAngleInDegrees ); +} + +double CPolarCoordinate::GetLeftRightAngleInDegrees( void ) const +{ + return( m_LeftRightAngleInDegrees ); +} + +double CPolarCoordinate::GetDistanceFromSurfaceInMeters( void ) const +{ + return( m_DistanceFromSurfaceInMeters ); +} + +void CPolarCoordinate::Set( double up_down_angle, double left_right_angle, double length ) +{ + m_UpDownAngleInDegrees = up_down_angle; + m_LeftRightAngleInDegrees = left_right_angle; + m_DistanceFromSurfaceInMeters = length; +} + +void CPolarCoordinate::SetUpDownAngleInDegrees( double up_down_angle ) +{ + m_UpDownAngleInDegrees = up_down_angle; +} + +void CPolarCoordinate::SetLeftRightAngleInDegrees( double left_right_angle ) +{ + m_LeftRightAngleInDegrees = left_right_angle; +} + +void CPolarCoordinate::SetDistanceFromSurfaceInMeters( double distance_from_surface ) +{ + m_DistanceFromSurfaceInMeters = distance_from_surface; +} + +CPolarCoordinate& CPolarCoordinate::operator=( const CPolarCoordinate& source ) +{ + Copy( source ); + return( *this ); +} + +#if 0 + + +GFC - CPolarCoordinate + +

CPolarCoordinate

+$Revision: 5 $ +
+

Description

+This class encapsulates a polar coordinate. A polar coordinate is +made up of two angles and one distance. The angles originate at the +center of the Earth. One angle measures up and down (latitude) while +the other measures left and right (longitude). The distance is the +altitude above the surface of the Earth. Positive angles approach north +and east while negative values for an angle run south and west. +

Constructors

+
+
CPolarCoordinate()
+CPolarCoordinate( const CPolarCoordinate& source )
+Constructs an empty coordinate or copies another CPolarCoordinate. +
+

Methods

+
+
void Copy( const CPolarCoordinate& coordinate )
+Copies the contents of another CPolarCoordinate. +
void Get( double& up_down_angle, double& left_right_angle, double& distance )
+This allows you to retrieve all the data members in one function call. +
double GetUpDownAngleInDegrees( void ) const
+This method returns the up/down angle in degrees. +
double GetLeftRightAngleInDegrees( void ) const
+This method returns the left/right angle in degrees. +
double GetDistanceFromSurfaceInMeters( void ) const
+This method returns the distance from the surface of the ellipsoid. +
void Set( double up_down_angle, double left_right_angle, double distance )
+This lets you set all of the data members in a single function call. +
void SetUpDownAngleInDegrees( double up_down_angle )
+This method sets the up/down angle. +
void SetLeftRightAngleInDegrees( double left_right_angle )
+This method sets the left/right angle. +
void SetDistanceFromSurfaceInMeters( double distance )
+This method sets the distance from the surface of the ellipsoid. +
+

Operators

+
+
= ( const CPolarCoordinate& source )
+Basically calls Copy(). +
+

Example

+
#include <stdio.h>
+#include <GFC.h>
+#pragma hdrstop
+
+void main( void )
+{
+   CPolarCoordinate here;
+   CPolarCoordinate there;
+
+   // here is 39 degrees 12.152 minutes North Latitude, 76 degrees 46.795 minutes West Longitude
+   here.SetUpDownAngleInDegrees(     CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees(  39.0, 12.152, 0.0 ) );
+   here.SetLeftRightAngleInDegrees(  CMath::ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees( -76.0, 46.795, 0.0 ) );
+   here.SetDistanceFromSurfaceInMeters( 1000.0 );
+
+   there = here;
+}
+
Copyright, 1998, Samuel R. Blackburn
+$Workfile: CPolarCoordinate.cpp $
+$Modtime: 5/16/00 8:21a $ + + +
+#endif diff --git a/GFC/GFC.h b/GFC/GFC.h new file mode 100644 index 0000000..0ec69c9 --- /dev/null +++ b/GFC/GFC.h @@ -0,0 +1,340 @@ +/* +Author: Samuel R. Blackburn +Internet: wfc@pobox.com + +"You can get credit for something or get it done, but not both." +Dr. Richard Garwin + +The MIT License (MIT) + +Copyright (c) 1997-2015 Sam Blackburn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +// Definitions +// Ellipsoid +// A flattened sphere. Take a basketball (a sphere), let some air out of it then +// stand on it. You now have an ellipsoid. The basketball is flat on the bottom +// and the top but still round in the middle. +// Equator +// 0 degrees Latitude +// Flattening +// This is a ratio between polar radius and equatorial radius. Other names for +// flattening are elliptocyte or oblateness. +// Latitude +// The lines that run around the Earth like belts. They measure up/down angles. +// Longituide +// The lines that slice the Earth like an orange from top to bottom. They +// measure left/right angles. +// Meridian +// One of the imaginary circles on the earth's surface passing through the north +// and south poles +// Pi +// The most famous constant. It is a ratio. +// It is the Circumference of a circle divided by +// the diameter of the circle. It is 3.14 (or roughly 22 divivded by 7). +// Prime Meridian +// 0 degrees Longitude +// Radian +// The unit of measurement of a circle. It is a ratio. +// It's kind of hard to explain what +// a radian is so let me give you an example. Take the basketball and cut +// a length of string equal to the radius (i.e. half the width) of the +// ball. Now, lay this string on top of the ball. See how it forms an arc? +// Now, draw a line from each end of the string to the center of the ball. +// The angle of these two lines at the center of the ball is roughly +// 57.2958 degrees. This is true no matter what the size of the ball is. +// Why? Because as the size of the ball increases, so does the radius. +// So, a radian can be considered as a relationship between the radius of +// a sphere (ball) and the circumference of the sphere. Now, there's something +// interesting about the number of degrees in a radian (52.2958). It is +// equal to 180 divided by Pi. Yup! Go Figure! OK. Now we're getting somewhere. +// To find the length of the arc when all you have is the number of radians +// in the angle at the center of the sphere, you multiply the radius times +// the number of radians. It's that simple (on a perfect sphere anyway). + +// Geodetic Datum - description of the shape of the earth + +// Reference Ellipsoid - A flattened sphere. Let some air out of +// a basketball, then stand on it. The ball is now an ellipsoid. +// Your feet are standing on the North Pole and the floor is the +// South Pole. + +// Ellipsoids are described by their polar and equatorial radii. +// Polar radius is also known as semi-minor axis. +// Equatorial radius is also know as semi-major axis. +// All other items of interest about the ellipsoid are derived +// from these two data. +// Flattening is ( Equatorial radius - Polar radius ) / Equatorial radius +// There's another thing called First Eccentricity Squared, this is computed +// by ( 2 * Flattening ) - ( Flattening squared ). + +// Coordinates - a means of expressing a point in space +// +// Cartesian coordinates are X, Y, and Z coordinates. These are always +// expressed in distances from 0, 0, 0 (i,e, the center of the earth). +// +// Polar coordinates are theta (often seen as a letter O with a line +// through its middle running left-to-right), phi (often seen as a +// letter O with a line through its middle running top-to-bottom), and +// r (a distance). +// These are two angles and a distance. The angles are measured from +// a common origin (the center of the earth). Theta is the plane that +// runs through the equator, phi runs through the poles. R is the +// distance along the line running along the phi angle. For simplicity +// sake, we will refer to theta as Equatorial angle, phi as the +// polar angle, and r as Polar Distance. +// +// Converting coordinates +// +// You can convert from polar to cartesian cordinates using the following +// formula: +// X = Polar distance * cosine of Polar angle * cosine of Equatorial angle +// Y = Polar distance * cosine of Polar angle * sine of Equatorial angle +// Z = Polar distance * sine of Polar angle + +// Applying this to the real world +// +// Cartesian coordinates ar commonly refered to an ECEF X,Y,Z coordinates. +// This means Earth Centered, Earth Fixed. The 0,0,0 coordinate is the +// center of the earth. The X axis runs towards the Prime Meridian. +// The Y axis runs towards the equator and the Z axis runs toward +// the poles. Positive Z numbers go towards the North pole while +// negative numbers go towards the South Pole. Positive + +// Computing Distance +// +// If you have two cartesian coordinates, you can compute a line +// of sight (as the bullet flies, aiming a laser, pointing in a straight line) +// by this formula (some guy named Pythagoras figured this out): +// SQRT( ( X1 - X2 ) ^ 2 + ( Y1 - Y2 ) ^ 2 + ( Z1 - Z2 ) ^ 2 ) +// +// or in pseudo code: +// +// cartesian_coordinate first_location; +// cartesian_coordinate second_location; +// +// double temp_x; +// double temp_y; +// double temp_z; +// +// temp_x = first_location.X - second_location.X; +// temp_y = first_location.Y - second_location.Y; +// temp_z = first_location.Z - second_location.Z; +// +// temp_x = temp_x * temp_x; // square them +// temp_y = temp_y * temp_y; +// temp_z = temp_z * temp_z; +// +// double temp_double; +// +// temp_double = temp_x + temp_y + temp_z; +// +// double distance; +// +// distance = sqrt( temp_double ); +// +// While this will give you distance, it will not give you direction. + +#include +#include + +class CMath +{ + // This class encapsulates all of the math functions. It is here to allow you + // to replace the C Runtime functions with your home-grown (and maybe better + // implementation) routines + + public: + + static inline double AbsoluteValue( const double& value ); + static inline double ArcCosine( const double& value ); + static inline double ArcSine( const double& value ); + static inline double ArcTangent( const double& value ); + static inline double ArcTangentOfYOverX( const double& y, const double& x ); + static inline double Ceiling( const double& value ); + static inline double ConvertDegreesToRadians( const double& degrees ); + static inline double ConvertRadiansToDegrees( const double& radians ); + static inline void ConvertDecimalDegreesToDegreesMinutesSeconds( double decimal_degrees, double& degrees, double& minutes, double& seconds ); + // West is negative, East is positive, North is positive, south is negative + static inline double ConvertDegreesMinutesSecondsCoordinateToDecimalDegrees( double degrees, double minutes, double seconds ); + static inline double Cosine( const double& value ); + static inline double HyperbolicCosine( const double& value ); + static inline double Pi( void ); + static inline double Sine( const double& value ); + static inline double SquareRoot( const double& value ); +}; + +#include "CMath.inl" // Implementations of the inline functions + +class CEarthCoordinate +{ + // This is a Cartesian coordinate (Earth Centered, Earth Fixed) + + protected: + + double m_X_CoordinateInMeters; // Positive points to intersection of the Prime Meridian and the equator + double m_Y_CoordinateInMeters; // Positive points to the intersection of 90 degrees east of Prime Meridian and the equator + double m_Z_CoordinateInMeters; // Positive points to the North Pole, Negative towards the South Pole + + public: + + CEarthCoordinate(); + CEarthCoordinate( const CEarthCoordinate& source ); + ~CEarthCoordinate(); + + void Copy( const CEarthCoordinate& source ); + void Get( double& x_coordinate, double& y_coordinate, double& z_coordinate ) const; + double GetXCoordinateInMeters( void ) const; + double GetYCoordinateInMeters( void ) const; + double GetZCoordinateInMeters( void ) const; + void Set( double x_coordinate, double y_coordinate, double z_coordinate ); + void SetXCoordinateInMeters( double x_coordinate ); + void SetYCoordinateInMeters( double y_coordinate ); + void SetZCoordinateInMeters( double z_coordinate ); + + CEarthCoordinate& operator = ( const CEarthCoordinate& source ); +}; + +class CPolarCoordinate +{ + protected: + + double m_UpDownAngleInDegrees; // Polar Angle, Phi + double m_LeftRightAngleInDegrees; // Equatorial Angle, Theta + double m_DistanceFromSurfaceInMeters; + + public: + + CPolarCoordinate(); + CPolarCoordinate( const CPolarCoordinate& source ); + ~CPolarCoordinate(); + + void Copy( const CPolarCoordinate& source ); + void Get( double& up_down_angle, double& left_right_angle, double& distance_from_surface ) const; + double GetUpDownAngleInDegrees( void ) const; + double GetLeftRightAngleInDegrees( void ) const; + double GetDistanceFromSurfaceInMeters( void ) const; + void Set( double up_down_angle, double left_right_angle, double distance_from_surface ); + void SetUpDownAngleInDegrees( double up_down_angle ); + void SetLeftRightAngleInDegrees( double left_right_angle ); + void SetDistanceFromSurfaceInMeters( double distance_from_surface ); + + CPolarCoordinate& operator = ( const CPolarCoordinate& source ); +}; + +class CEarth +{ + protected: + + // These are the magic numbers. They are the "real" data. They are facts, + // measurements. Everything else about an ellipse is derived (or computed from) + // these two data items. + + double m_PolarRadiusInMeters; + double m_EquatorialRadiusInMeters; + + // Here be the things that can be derived from our hard data. + // We compute these values using the two pieces of data that we + // know about the ellipse. + + double m_Flattening; + double m_EccentricitySquared; + + // Here's stuff specific to the C++ class + + int m_EllipsoidID; + + void m_ComputeFlattening( void ); + void m_ComputeEccentricitySquared( void ); + void m_Initialize( void ); + + public: + + typedef enum _EllipsoidType + { + Unknown, + Perfect_Sphere, + Airy, + Austrailian_National, + Bessell_1841, + Bessel_1841_Nambia, + Clarke_1866, + Clarke_1880, + Everest, + Fischer_1960_Mercury, + Fischer_1968, + GRS_1967, + GRS_1980, + Helmert_1906, + Hough, + International, + Krassovsky, + Modified_Airy, + Modified_Everest, + Modified_Fischer_1960, + South_American_1969, + Topex_Poseidon_Pathfinder_ITRF, + WGS_60, + WGS_66, + WGS_72, + WGS_84, + Custom + } + ELLIPSOID; + + typedef enum _DatumTypes + { + NAD_27 = Clarke_1866, + Tokyo = Bessell_1841, + } + DATUM; + + CEarth( ELLIPSOID ellipsoid = WGS_84 ); + CEarth( const CEarth& source ); + ~CEarth(); + + virtual void AddLineOfSightDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2, double height_above_surface_of_point_2 = 0.0 ); + virtual void AddSurfaceDistanceAndDirectionToCoordinate( const CEarthCoordinate& point_1, double distance, double direction, CEarthCoordinate& point_2 ); + virtual void AddSurfaceDistanceAndDirectionToCoordinate( const CEarthCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2 ); + virtual void AddSurfaceDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CEarthCoordinate& point_2 ); + virtual void AddSurfaceDistanceAndDirectionToCoordinate( const CPolarCoordinate& point_1, double distance, double direction, CPolarCoordinate& point_2 ); + virtual void Convert( const CEarthCoordinate& cartesian_coordinate, CPolarCoordinate& polar_coordinate ) const; + virtual void Convert( const CPolarCoordinate& polar_coordinate, CEarthCoordinate& cartesian_coordinate ) const; + virtual double GetDistanceToHorizon( const CEarthCoordinate& point_1 ) const; + virtual double GetDistanceToHorizon( const CPolarCoordinate& point_1 ) const; + virtual double GetEquatorialRadiusInMeters( void ) const; + virtual double GetPolarRadiusInMeters( void ) const; + virtual double GetLineOfSightDistanceFromCourse( const CEarthCoordinate& current_location, const CEarthCoordinate& point_a, const CEarthCoordinate& point_b ) const; + virtual double GetLineOfSightDistance( const CEarthCoordinate& point_1, const CEarthCoordinate& point_2 ) const; + virtual double GetLineOfSightDistance( const CPolarCoordinate& point_1, const CEarthCoordinate& point_2 ) const; + virtual double GetLineOfSightDistance( const CEarthCoordinate& point_1, const CPolarCoordinate& point_2 ) const; + virtual double GetLineOfSightDistance( const CPolarCoordinate& point_1, const CPolarCoordinate& point_2 ) const; + virtual double GetSurfaceDistance( const CEarthCoordinate& point_1, const CEarthCoordinate& point_2, double * heading_from_point_1_to_point_2 = nullptr, double * heading_from_point_2_to_point_1 = nullptr) const; + virtual double GetSurfaceDistance( const CEarthCoordinate& point_1, const CPolarCoordinate& point_2, double * heading_from_point_1_to_point_2 = nullptr, double * heading_from_point_2_to_point_1 = nullptr) const; + virtual double GetSurfaceDistance( const CPolarCoordinate& point_1, const CEarthCoordinate& point_2, double * heading_from_point_1_to_point_2 = nullptr, double * heading_from_point_2_to_point_1 = nullptr) const; + virtual double GetSurfaceDistance( const CPolarCoordinate& point_1, const CPolarCoordinate& point_2, double * heading_from_point_1_to_point_2 = nullptr, double * heading_from_point_2_to_point_1 = nullptr) const; + virtual void SetEllipsoid( ELLIPSOID ellipsoid ); + virtual void SetEllipsoidByRadii( double equatorial_radius, double polar_radius ); + virtual void SetEllipsoidByEquatorialRadiusAndFlattening( double equatorial_radius, double flattening ); + + virtual void Copy( const CEarth& source ); + CEarth& operator = ( const CEarth& source ); +}; diff --git a/GFC/GFC.vcxproj b/GFC/GFC.vcxproj new file mode 100644 index 0000000..99c2df9 --- /dev/null +++ b/GFC/GFC.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {86D51DA2-9B90-400E-BFE1-EDD24981BF6C} + Win32Proj + GFC + 8.1 + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + GFC.h + + + Windows + true + + + + + Use + Level3 + Disabled + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + GFC.h + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + GFC.h + + + Windows + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + GFC.h + + + Windows + true + true + true + + + + + + + + + + Create + Create + + + + + + + + + + + \ No newline at end of file diff --git a/GFC/GFC.vcxproj.filters b/GFC/GFC.vcxproj.filters new file mode 100644 index 0000000..614accc --- /dev/null +++ b/GFC/GFC.vcxproj.filters @@ -0,0 +1,44 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/README.md b/README.md index 19f6065..23e3141 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # GFC -Geodesy Foundation Classes - Simple C++ library for doing basic navigation calculations +Geodesy Foundation Classes - Simple C++ library for doing basic navigation calculations. + +This library let's you set an ellipsoid and caclulate the surface distance between two points on the globe. You can also calculate headings between two points, find out how far off course your current position is from a line between two other points, etc.