// -*- text -*- /** * \file GeographicLib.dox * \brief Documentation for GeographicLib * * Written by Charles Karney and licensed under the * MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ namespace GeographicLib { /** \mainpage GeographicLib library \author Charles F. F. Karney (charles@karney.com) \version @PROJECT_VERSION@ \date 2019-12-13 The documentation for other versions is available at https://geographiclib.sourceforge.io/m.nn/ for versions numbers m.nn ≥ 1.0. \section abstract Abstract GeographicLib is a small set of C++ classes for performing conversions between geographic, UTM, UPS, MGRS, geocentric, and local cartesian coordinates, for gravity (e.g., EGM2008), geoid height and geomagnetic field (e.g., WMM2020) calculations, and for solving geodesic problems. The emphasis is on returning accurate results with errors close to round-off (about 5--15 nanometers). Accurate algorithms for \ref geodesic and \ref transversemercator have been developed for this library. The functionality of the library can be accessed from user code, from the \ref utilities provided, or via the \ref other. Also included is a .NET wrapper library NETGeographicLib which exposes the functionality to .NET applications. For a sample of the geodesic capabilities in JavaScript, check out the online geodesic calculator and the script for displaying geodesics in Google Maps This library is not a general purpose projection library nor does it perform datum conversions; instead use PROJ. On the other hand, it does provide the core functionality offered by GEOTRANS. \section download Download The main project page is at - https://sourceforge.net/projects/geographiclib . The code is available for download at - GeographicLib-@PROJECT_VERSION@.tar.gz - GeographicLib-@PROJECT_VERSION@.zip . as either a compressed tar file (tar.gz) or a zip file. (The two archives have identical contents, except that the zip file has DOS line endings.) Alternatively you can get the latest release using git \verbatim git clone git://git.code.sourceforge.net/p/geographiclib/code geographiclib \endverbatim Each release is tagged, e.g., with r@PROJECT_VERSION@. There are also binary installers available for some platforms. See \ref binaryinst. GeographicLib is licensed under the MIT/X11 License; see LICENSE.txt for the terms. For more information on GeographicLib, see - https://geographiclib.sourceforge.io/. \section citint Citing GeographicLib When citing GeographicLib, use (adjust the version number and date as appropriate) - C. F. F. Karney, GeographicLib, Version @PROJECT_VERSION@ (2019-09-24), https://geographiclib.sourceforge.io/@PROJECT_VERSION@ \section contents Contents - \ref intro - \ref install - \ref start - \ref utilities - \ref organization - \ref other - \ref geoid - \ref gravity - \ref normalgravity - \ref magnetic - \ref geodesic - \ref nearest - \ref triaxial - \ref jacobi - \ref rhumb - \ref greatellipse - \ref transversemercator - \ref geocentric - \ref auxlat - \ref highprec - \ref changes
Forward to \ref intro.
**********************************************************************/ /** \page intro Introduction
Forward to \ref install. Up to \ref contents.
GeographicLib offers a C++ interfaces to a small (but important!) set of geographic transformations. It grew out of a desire to improve on the GEOTRANS package for transforming between geographic and MGRS coordinates. At present, GeographicLib provides UTM, UPS, MGRS, geocentric, and local cartesian projections, gravity and geomagnetic models, and classes for geodesic calculations. The goals of GeographicLib are: - Accuracy. In most applications the accuracy is close to round-off, about 5 nm (5 nanometers). Even though in many geographic applications 1 cm is considered "accurate enough", there is little penalty in providing much better accuracy. In situations where a faster approximate algorithm is necessary, GeographicLib offers an accurate benchmark to guide the development. - Completeness. For each of the projections included, an attempt is made to provide a complete solution. For example, Geodesic::Inverse works for anti-podal points. Similarly, Geocentric::Reverse will return accurate geodetic coordinates even for points close to the center of the earth. - C++ interface. For the projection methods, this allows encapsulation of the ellipsoid parameters. - Emphasis on projections necessary for analyzing military data. - Uniform treatment of UTM/UPS. The UTMUPS class treats UPS as zone 0. This simplifies conversions between UTM and UPS coordinates, etc. - Well defined and stable conventions for the conversion between UTM/UPS to MGRS coordinates. - Detailed internal documentation on the algorithms. For the most part GeographicLib uses published algorithms and references are given. If changes have been made (usually to improve the numerical accuracy), these are described in the code. Various \ref utilities are provided with the library. These illustrate the use of the library and are useful in their own right. This library and the utilities have been tested with g++ 5.3.1 under Linux, with Apple LLVM 7.0.2 under Mac OS X, and with MS Visual Studio 10 (2010), 11 (2012), 12 (2013), 14 (2015), 15 (2017), and 16 (2019) compiled for 32 bit and 64 bit on Windows. MATLAB, JavaScript, and Python interfaces are provided to portions of GeographicLib; see \ref other. The section \ref geodesic documents the method of solving the geodesic problem. The section \ref transversemercator documents various properties of this projection. The bulk of the testing has used geographically relevant values of the flattening. Thus, you can expect close to full accuracy for −0.01 ≤ \e f ≤ 0.01 (but note that TransverseMercatorExact is restricted to \e f > 0). However, reasonably accurate results can be expected if −0.1 ≤ \e f ≤ 0.1. Outside this range, you should attempt to verify the accuracy of the routines independently. Two types of problems may occur with larger values of f: - Some classes, specifically Geodesic, GeodesicLine, and TransverseMercator, use series expansions using \e f as a small parameter. The accuracy of these routines will degrade as \e f becomes large. - Even when exact formulas are used, many of the classes need to invert the exact formulas (e.g., to invert a projection), typically, using Newton's method. This usually provides an essentially exact inversion. However, the choice of starting guess and the exit conditions have been tuned to cover small values of \e f and the inversion may be incorrect if \e f is large. Undoubtedly, bugs lurk in this code and in the documentation. Please report any you find to charles@karney.com.
Forward to \ref install. Up to \ref contents.
**********************************************************************/ /** \page install Installing GeographicLib
Back to \ref intro. Forward to \ref start. Up to \ref contents.
GeographicLib has been developed under Linux with the g++ compiler (versions 4.0 and later), under Mac OS X with Xcode (version 8.2), and under Windows with Visual Studio 2010 and later. Earlier versions were tested also under Visual Studio 2005 and 2008 and under Solaris. It should compile on a wide range of other systems. First download either GeographicLib-@PROJECT_VERSION@.tar.gz or GeographicLib-@PROJECT_VERSION@.zip (or GeographicLib-@PROJECT_VERSION@-win32.exe or GeographicLib-@PROJECT_VERSION@-win64.exe for binary installation under Windows). Then pick one of the first five options below: - \ref cmake. This is the preferred installation method as it will work on the widest range of platforms. However it requires that you have cmake installed. - \ref autoconf. This method works for most Unix-like systems, including Linux and Mac OS X. - \ref gnu. This is a simple installation method that works with g++ and GNU make on Linux and many Unix platforms. - \ref windows. This is a simple installation method that works with Visual Studio 2010 under Windows. - \ref binaryinst. Use this installation method if you only need to use the \ref utilities supplied with GeographicLib. (This method also installs the header files and the library for use by Visual Studio 14 2015.) - \ref qt. How to compile GeographicLib so that it can be used by Qt programs. - \ref maintainer. This describes addition tasks of interest only to the maintainers of this code. . This section documents only how to install the software. If you wish to use GeographicLib to evaluate geoid heights or the earth's gravitational or magnetic fields, then you must also install the relevant data files. See \ref geoidinst, \ref gravityinst, and \ref magneticinst for instructions. The first two installation methods use two important techniques which make software maintenance simpler - Out-of-source builds: This means that you create a separate directory for compiling the code. In the description here the directories are called BUILD and are located in the top-level of the source tree. You might want to use a suffix to denote the type of build, e.g., BUILD-vc14 for Visual Studio 14 (2015), or BUILD-shared for a build which creates a shared library. The advantages of out-of-source builds are: - You don't mess up the source tree, so it's easy to "clean up". Indeed the source tree might be on a read-only file system. - Builds for multiple platforms or compilers don't interfere with each other. - The library is installed: After compilation, there is a separate install step which copies the headers, libraries, tools, and documentation to a "central" location. You may at this point delete the source and build directories. If you have administrative privileges, you can install GeographicLib for the use of all users (e.g., in /usr/local). Otherwise, you can install it for your personal use (e.g., in $HOME/packages). \section cmake Installation with cmake This is the recommended method of installation; however it requires that cmake, version 3.1.0 or later, be installed on your system. This permits GeographicLib to be built either as a shared or a static library on a wide variety of systems. cmake can also determine the capabilities of your system and adjust the compilation of the libraries and examples appropriately. cmake is available for most computer platforms. On Linux systems cmake will typically one of the standard packages and can be installed by a command like \verbatim yum install cmake \endverbatim (executed as root). The minimum version of cmake supported for building GeographicLib is 3.1.0 (which was released on 2014-12-15). On other systems, download a binary installer from https://www.cmake.org click on download, and save and run the appropriate installer. Run the cmake command with no arguments to get help. Other useful tools are ccmake and cmake-gui which offer curses and graphical interfaces to cmake. Building under cmake depends on whether it is targeting an IDE (interactive development environment) or generating Unix-style makefiles. The instructions below have been tested with makefiles and g++ on Linux and with the Visual Studio IDE on Windows. It is known to work also for Visual Studio 2017 Build Tools. Here are the steps to compile and install GeographicLib: - Unpack the source, running one of \verbatim tar xfpz GeographicLib-@PROJECT_VERSION@.tar.gz unzip -q GeographicLib-@PROJECT_VERSION@.zip \endverbatim then enter the directory created with \verbatim cd GeographicLib-@PROJECT_VERSION@ \endverbatim - Create a separate build directory and enter it, for example, \verbatim mkdir BUILD cd BUILD \endverbatim - Run cmake, pointing it to the source directory (..). On Linux, Unix, and MacOSX systems, the command is \verbatim cmake .. \endverbatim For Windows, the command is typically something like \verbatim cmake -G "Visual Studio 14" -A win32 -D CMAKE_INSTALL_PREFIX="C:/Program Files (x86)/GeographicLib-@PROJECT_VERSION@" .. cmake -G "Visual Studio 14" -A x64 -D CMAKE_INSTALL_PREFIX="C:/Program Files/GeographicLib-@PROJECT_VERSION@" ..\endverbatim The definitions of CMAKE_INSTALL_PREFIX point to system directories. You might instead prefer to install to a user directory such as C:/Users/jsmith/projects/GeographicLib-@PROJECT_VERSION@. The settings given above are recommended to ensure that packages that use GeographicLib use the version compiled with the right compiler. If you need to rerun cmake, use \verbatim cmake . \endverbatim possibly including some options via -D (see the next step). - cmake allows you to configure how GeographicLib is built and installed by supplying options, for example \verbatim cmake -D CMAKE_INSTALL_PREFIX=/tmp/geographic . \endverbatim The options you might need to change are - COMMON_INSTALL_PATH governs the installation convention. If it is on ON (the Linux default), the installation is to a common directory, e.g., /usr/local. If it is OFF (the Windows default), the installation directory contains the package name, e.g., C:/Program Files/GeographicLib-@PROJECT_VERSION@. The installation directories for the documentation, cmake configuration, Python and MATLAB interfaces all depend on the variable with deeper paths relative to CMAKE_INSTALL_PREFIX being used when it's ON: - cmake configuration: OFF cmake; ON: lib/cmake/GeographicLib; - documentation: OFF: doc/html; ON: share/doc/GeographicLib/html; - JavaScript interface: OFF: node_modules; ON: lib/node_modules; - Python interface: OFF: python; ON: lib/python/site-packages; - MATLAB interface: OFF: matlab; ON: share/matlab. . - CMAKE_INSTALL_PREFIX (default: /usr/local on non-Windows systems, C:/Program Files (x86)/GeographicLib on Windows systems) specifies where the library will be installed. For Windows systems, you might want to use a prefix which includes the compiler version, in order to keep the libraries built with different versions of the compiler in distinct locations. If you just want to try the library to see if it suits your needs, pick, for example, CMAKE_INSTALL_PREFIX=/tmp/geographic. - GEOGRAPHICLIB_DATA (default: /usr/local/share/GeographicLib for non-Windows systems, C:/ProgramData/GeographicLib for Windows systems) specifies the default location for the various datasets for use by Geoid, GravityModel, and MagneticModel. See \ref geoidinst, \ref gravityinst, and \ref magneticinst for more information. - GEOGRAPHICLIB_LIB_TYPE (allowed values: SHARED, STATIC, or BOTH), specifies the types of libraries build. The default is STATIC for Windows and SHARED otherwise. If building GeographicLib for system-wide use, BOTH is recommended, because this provides users with the choice of which library to use. - CMAKE_BUILD_TYPE (default: Release). This flags only affects non-IDE compile environments (like make + g++). The default is actually blank, but this is treated as Release. Choose one of \verbatim Debug Release RelWithDebInfo MinSizeRel \endverbatim (With IDE compile environments, you get to select the build type in the IDE.) - GEOGRAPHICLIB_DOCUMENTATION (default: OFF). If set to ON, then html documentation is created from the source files, provided a sufficiently recent version of doxygen can be found. Otherwise, the html documentation will redirect to the appropriate version of the online documentation. - BUILD_NETGEOGRAPHICLIB (default: OFF). If set to ON, build the managed C++ wrapper library NETGeographicLib. This only makes sense for Windows systems. - GEOGRAPHICLIB_PRECISION specifies the precision to be used for "real" (i.e., floating point) numbers. Here are the possible values -# float (24-bit precision); typically this is far to inaccurate for geodetic applications. -# double precision (53-bit precision, the default). -# long double (64-bit precision); this does not apply for Visual Studio (long double is the same as double with that compiler). -# quad precision (113-bit precision). -# arbitrary precision. . See \ref highprec for addition information about the last two values. Nearly all the testing has been carried out with doubles and that's the recommended configuration. In particular you should avoid "installing" the library with a precision different from double. - USE_BOOST_FOR_EXAMPLES (default: OFF). If set to ON, then the Boost library is searched for in order to build the NearestNeighbor example. - APPLE_MULTIPLE_ARCHITECTURES (default: OFF). If set to ON, build for i386 and x86_64 and Mac OS X systems. Otherwise, build for the default architecture. - CONVERT_WARNINGS_TO_ERRORS (default: OFF). If set to ON, then compiler warnings are treated as errors. (This happens also if you are a "developer", i.e., if the file tests/CMakeLists.txt is present.) - Build and install the software. In non-IDE environments, run \verbatim make # compile the library and utilities make test # run some tests make install # as root, if CMAKE_INSTALL_PREFIX is a system directory \endverbatim Possible additional targets are \verbatim make dist make exampleprograms make netexamples (supported only for Release configuration) \endverbatim On IDE environments, run your IDE (e.g., Visual Studio), load GeographicLib.sln, pick the build type (e.g., Release), and select "Build Solution". If this succeeds, select "RUN_TESTS" to build; finally, select "INSTALL" to install (RUN_TESTS and INSTALL are in the CMakePredefinedTargets folder). Alternatively (for example, if you are using the Visual Studio 2017 Build Tools), you run the Visual Studio compiler from the command line with \verbatim cmake --build . --config Release --target ALL_BUILD cmake --build . --config Release --target RUN_TESTS cmake --build . --config Release --target INSTALL \endverbatim For maximum flexibility, it's a good idea to build and install both the Debug and Release versions of the library (in that order). The installation directories will then contain the release versions of the tools and both versions (debug and release) of the libraries. If you use cmake to configure and build your programs, then the right version of the library (debug vs. release) will automatically be used. - The headers, library, and utilities are installed in the include/GeographicLib, lib, and bin directories under CMAKE_INSTALL_PREFIX. (dll dynamic libraries are installed in bin.) For documentation, open in a web browser PREFIX/share/doc/GeographicLib/html/index.html, if COMMON_INSTALL_PATH is ON, or PREFIX/doc/index.html, otherwise. \section autoconf Installation using the autoconfigure tools The method works on most Unix-like systems including Linux and Mac OS X. Here are the steps to compile and install GeographicLib: - Unpack the source, running \verbatim tar xfpz GeographicLib-@PROJECT_VERSION@.tar.gz \endverbatim then enter the directory created \verbatim cd GeographicLib-@PROJECT_VERSION@ \endverbatim - Create a separate build directory and enter it, for example, \verbatim mkdir BUILD cd BUILD \endverbatim - Configure the software, specifying the path of the source directory, with \verbatim ../configure \endverbatim - By default GeographicLib will be installed under /usr/local. You can change this with, for example \verbatim ../configure --prefix=/tmp/geographic \endverbatim - Compile and install the software with \verbatim make make install \endverbatim - The headers, library, and utilities are installed in the include/GeographicLib, lib, and bin directories under prefix. For documentation, open share/doc/GeographicLib/html/index.html in a web browser. \section gnu Installation with GNU compiler and Make This method requires the standard GNU suite of tools, in particular make and g++. This builds a static library and the examples. Here are the steps to compile and install GeographicLib: - Unpack the source, running \verbatim tar xfpz GeographicLib-@PROJECT_VERSION@.tar.gz \endverbatim then enter the directory created \verbatim cd GeographicLib-@PROJECT_VERSION@ \endverbatim - Edit \verbatim include/GeographicLib/Config.h \endverbatim If your C++ compiler does not recognize the long double type (unlikely), insert \code #undef GEOGRAPHICLIB_HAVE_LONG_DOUBLE \endcode If your machine using big endian ordering, then insert \code #define GEOGRAPHICLIB_WORDS_BIGENDIAN 1 \endcode - Build and install the software: \verbatim make # compile the library and the examples make install # as root \endverbatim The installation is in directories under /usr/local. You can specify a different installation directory with, for example, \verbatim make PREFIX=/tmp/geographic install \endverbatim - The headers, library, and utilities are installed in the include/GeographicLib, lib, and bin directories under PREFIX. For documentation, open share/doc/GeographicLib/html/index.html in a web browser. \section windows Installation on Windows This method requires Visual Studio 2010. This builds a static library and the utilities. If you have some other version of Visual Studio, use cmake to create the necessary solution file, see \ref cmake. (cmake is needed to run the tests.) - Unpack the source, running \verbatim unzip -q GeographicLib-@PROJECT_VERSION@.zip \endverbatim - Open GeographicLib-@PROJECT_VERSION@/windows/GeographicLib-vc10.sln in Visual Studio 2010 (for Visual Studio Express 2010, replace -vc10 by -vc10x). - Pick the build type (e.g., Release), and select "Build Solution". - The library and the compiled examples are in the windows/Release. - Copy the library windows/Release/GeographicLib.lib and the headers in include/GeographicLib somewhere convenient. The headers should remain in a directory named GeographicLib. For documentation, open doc/html/index.html in a web browser. The Visual Studio 10 solution also contains projects to build NETGeographicLib and the C# example project. \section binaryinst Using a binary installer Binary installers are available for some platforms \subsection binaryinstwin Windows Use this method if you only need to use the GeographicLib utilities. The header files and static and shared versions of library are also provided; these can only be used by Visual Studio 14 2015 or later (2017 or 2019) (in either release or debug mode). However, if you plan to use the library, it may be advisable to build it with the compiler you are using for your own code using either \ref cmake or \ref windows. Download and run GeographicLib-@PROJECT_VERSION@-win32.exe or GeographicLib-@PROJECT_VERSION@-win64.exe: - read the MIT/X11 License agreement, - select whether you want your PATH modified, - select the installation folder, by default C:\\Program Files\\GeographicLib-@PROJECT_VERSION@ or C:\\Program Files (x86)\\GeographicLib-@PROJECT_VERSION@, - select the start menu folder, - and install. . (Note that the default installation folder adheres the the convention given in \ref cmake.) The start menu will now include links to the documentation for the library and for the utilities (and a link for uninstalling the library). If you ask for your PATH to be modified, it will include C:/Program Files{, (x86)}/GeographicLib-@PROJECT_VERSION@/bin where the utilities are installed. The headers and library are installed in the include/GeographicLib and lib folders. The libraries were built using using Visual Studio 14 2015 in release and debug modes. The utilities were linked against the release-mode shared library. NETGeographicLib library dlls (release and debug) are included with the binary installers; these are linked against the shared library for GeographicLib. Also included are the Python, JavaScript, and MATLAB interfaces. \subsection binaryinstosx MacOSX You can install using Homebrew. Follow the directions on https://brew.sh/ for installing this package manager. Then type \verbatim brew install geographiclib \endverbatim Now links to GeographicLib are installed under /usr/local. \subsection binaryinstlin Linux Some Linux distributions, Fedora, Debian, and Ubuntu, offer GeographicLib as a standard package. Typically these will be one or two versions behind the latest. \section qt Building the library for use with Qt If Qt is using a standard compiler, then build GeographicLib with that same compiler (and optimization flags) as Qt. If you are using the mingw compiler on Windows for Qt, then you need to build GeographicLib with mingw. You can accomplish this with cmake under cygwin with, for example, \verbatim export PATH="`cygpath -m c:/QtSDK/mingw/bin`:$PATH" mkdir BUILD cd BUILD cmake -G "MinGW Makefiles" -D CMAKE_INSTALL_PREFIX="C:/Program Files/GeographicLib" .. mingw32-make mingw32-make install \endverbatim If cmake complains that sh mustn't be in your path, invoke cmake with \verbatim env PATH="$( echo $PATH | tr : '\n' | while read d; do test -f "$d/sh.exe" || echo -n "$d:"; done | sed 's/:$//' )" \ cmake -G "MinGW Makefiles" -D CMAKE_INSTALL_PREFIX="C:/Program Files/GeographicLib" .. \endverbatim \section maintainer Maintainer tasks Check the code out of git with \verbatim git clone -b master git://git.code.sourceforge.net/p/geographiclib/code geographiclib \endverbatim Here the "master" branch is checked out. There are three branches in the git repository: - master: the main branch for code maintenance. Releases are tagged on this branch as, e.g., v@PROJECT_VERSION@. - devel: the development branch; changes made here are merged into master. - release: the release branch created by unpacking the source releases (git is \e not used to merge changes from the other branches into this branch). This is the \e default branch of the repository (the branch you get if cloning the repository without specifying a branch). This differs from the master branch in that some administrative files are excluded while some intermediate files are included (in order to aid building on as many platforms as possible). Releases are tagged on this branch as, e.g., r@PROJECT_VERSION@. . The autoconf configuration script and the formatted man pages are not checked into master branch of the repository. In order to create the autoconf configuration script, run \verbatim sh autogen.sh \endverbatim in the top level directory. Provided you are running on a system with doxygen, pod2man, and pod2html installed, then you can create the documentation and the man pages by building the system using cmake or configure. In the case of cmake, you then run \verbatim make dist \endverbatim which will copy the man pages from the build directory back into the source tree and package the resulting source tree for distribution as \verbatim GeographicLib-@PROJECT_VERSION@.tar.gz GeographicLib-@PROJECT_VERSION@.zip \endverbatim Finally, \verbatim make package \endverbatim or building PACKAGE in Visual Studio will create a binary installer for GeographicLib. For Windows, this requires in the installation of NSIS. On Windows, you should configure GeographicLib with PACKAGE_DEBUG_LIBS=ON, build both Release and Debug versions of the library and finally build PACKAGE in Release mode. This will get the release and debug versions of the library included in the package. For example, the 64-bit binary installer is created with \verbatim cmake -G "Visual Studio 14" -A x64 \ -D GEOGRAPHICLIB_LIB_TYPE=BOTH \ -D PACKAGE_DEBUG_LIBS=ON \ -D BUILD_NETGEOGRAPHICLIB=ON \ .. cmake --build . --config Debug --target ALL_BUILD cmake --build . --config Release --target ALL_BUILD cmake --build . --config Release --target matlabinterface cmake --build . --config Release --target PACKAGE \endverbatim With configure, run \verbatim make dist-gzip \endverbatim which will create the additional files and packages the results ready for distribution as \verbatim geographiclib-@PROJECT_VERSION@.tar.gz \endverbatim Prior to making a release, the script tests/test-distribution.sh is run on a Fedora system. This checked that the library compiles correctly is multiple configurations. In addition it creates a directory and scripts for checking the compilation on Windows. The following Fedora packages are required by tests/test-distribution.sh - cmake - automake - autoconf-archive - libtool - gcc-c++ - gcc-gfortran - ccache - doxygen - boost-devel - mpfr-devel - octave - python2-sphinx - nodejs - maven . The following npm packages need to be installed (jshint is just for syntax checking) \verbatim npm install -g mocha jsdoc jshint \endverbatim The following Fedora package is also useful for syntax checking python - pychecker . Installing the python package requires the following \verbatim python3 -m pip install --user --upgrade setuptools wheel twine \endverbatim A recent version of mpreal.h needs to be downloaded from https://bitbucket.org/advanpix/mpreal and installed in the include/ directory. For all the tests to be run, the following datasets need to be installed - geoid models: egm96-5 - magnetic models: wmm2010 emm2015 - gravity models: egm2008 grs80
Back to \ref intro. Forward to \ref start. Up to \ref contents.
**********************************************************************/ /** \page start Getting started
Back to \ref install. Forward to \ref utilities. Up to \ref contents.
Much (but not all!) of the useful functionality of GeographicLib is available via simple command line utilities. Interfaces to some of them are available via the web. See \ref utilities for documentation on these. In order to use GeographicLib from C++ code, you will need to - Include the header files for the GeographicLib classes in your code. E.g., \code #include \endcode - Include the GeographicLib:: namespace prefix to the GeographicLib classes, or include \code using namespace GeographicLib; \endcode in your code. - Finally compile and link your code. You have two options here. - Use cmake to build your package. If you are familiar with cmake this typically will be far the simplest option. - Set the include paths and linking options "manually". - Building your code with cmake. In brief, the necessary steps are: - include in your CMakeLists.txt files \verbatim find_package (GeographicLib REQUIRED) add_executable (program source1.cpp source2.cpp) target_link_libraries (program ${GeographicLib_LIBRARIES}) \endverbatim - configure your package, e.g., with \verbatim mkdir BUILD cd BUILD cmake -G "Visual Studio 14" -A x64 \ -D CMAKE_PREFIX_PATH="C:/Program Files" \ -D CMAKE_INSTALL_PREFIX="C:/Program Files/testgeographic" \ .. \endverbatim Note that you almost always want to configure and build your code somewhere other than the source directory (in this case, we use the BUILD subdirectory). Also, on Windows, make sure that the version of Visual Studio (14 in the example above) architecture (x64 in the example above) is compatible with that used to build GeographicLib. In this example, it's not necessary to specify CMAKE_PREFIX_PATH, because C:/Program Files is one of the system paths which is searched automatically. - build your package. On Linux and MacOS this usually involves just running make. On Windows, you can load the solution file created by cmake into Visual Studio; alternatively, you can get cmake to run build your code with \verbatim cmake --build . --config Release --target ALL_BUILD \endverbatim You might also want to install your package (using "make install" or build the "INSTALL" target with the command above). . The most import step is the find_package command. The cmake documentation describes the locations searched by find_package (the appropriate rule for GeographicLib are those for "Config" mode lookups). In brief, the locations that are searched are (from least specific to most specific, i.e., in reverse order) are - under the system paths, i.e., locations such as C:/Program Files and /usr/local); - frequently, it's necessary to search within a "package directory" (or set of directories) for external dependencies; this is given by a (semicolon separated) list of directories specified by the cmake variable CMAKE_PREFIX_PATH (illustrated above); - the package directory for GeographicLib can be overridden with the environment variable GeographicLib_DIR (which is the directory under which GeographicLib is installed); - finally, if you need to point to a particular build of GeographicLib, define the cmake variable GeographicLib_DIR, which specifies the absolute path of the directory containing the configuration file geographiclib-config.cmake (for debugging this may be the top-level build directory, as opposed to installation directory, for GeographicLib). . Typically, specifying nothing or CMAKE_PREFIX_PATH suffices. However the two GeographicLib_DIR variables allow for a specific version to be chosen. On Windows systems (with Visual Studio), find_package will only find versions of GeographicLib built with the right version of the compiler. (If you used a non-cmake method of installing GeographicLib, you can try copying cmake/FindGeographicLib.cmake to somewhere in your CMAKE_MODULE_PATH in order for find_package to work. However, this method has not been thoroughly tested.) If GeographicLib is not found, check the values of GeographicLib_CONSIDERED_CONFIGS and GeographicLib_CONSIDERED_VERSIONS; these list the configuration files and corresponding versions which were considered by find_package. If GeographicLib is found, then the following cmake variables are set: - GeographicLib_FOUND = 1 - GeographicLib_VERSION = @PROJECT_VERSION@ - GeographicLib_INCLUDE_DIRS - GeographicLib_LIBRARIES = one of the following two: - GeographicLib_SHARED_LIBRARIES = GeographicLib_SHARED - GeographicLib_STATIC_LIBRARIES = GeographicLib_STATIC - GeographicLib_LIBRARY_DIRS - GeographicLib_BINARY_DIRS - GEOGRAPHICLIB_DATA = value of this compile-time parameter . Either of GeographicLib_SHARED_LIBRARIES or GeographicLib_STATIC_LIBRARIES may be empty, if that version of the library is unavailable. If you require a specific version, SHARED or STATIC, of the library, add a COMPONENTS clause to find_package, e.g., \verbatim find_package (GeographicLib 1.34 REQUIRED COMPONENTS SHARED) \endverbatim causes only packages which include the shared library to be found. If the package includes both versions of the library, then GeographicLib_LIBRARIES is set to the shared version, unless you include \verbatim set (GeographicLib_USE_STATIC_LIBS ON) \endverbatim before the find_package command. You can check whether GeographicLib_LIBRARIES refers to the shared or static library with \verbatim get_target_property(_LIBTYPE ${GeographicLib_LIBRARIES} TYPE) \endverbatim which results in _LIBTYPE being set to SHARED_LIBRARY or STATIC_LIBRARY. On Windows, cmake takes care of linking to the release or debug version of the library as appropriate. (This assumes that the Release and Debug versions of the libraries were built and installed. This is true for the Windows binary installer for GeographicLib version 1.34 and later.) - Here are the steps to compile and link your code using GeographicLib "manually". - Tell the compiler where to find the header files. With g++ and with /usr/local specified as the installation directory, this is accomplished with \verbatim g++ -c -g -O3 -I/usr/local/include testprogram.cpp \endverbatim With Visual Studio, specify the include directory in the IDE via, e.g., \verbatim C/C++ -> General -> Additional Include Directories = C:\pkg-vc14-x64\GeographicLib\include \endverbatim - If using the shared (or static) library with Visual Studio, define the macro GEOGRAPHICLIB_SHARED_LIB=1 (or 0), e.g., \verbatim C/C++ -> Preprocessor -> Preprocessor Definitions = GEOGRAPHICLIB_SHARED_LIB=1 \endverbatim This is only needed for Windows systems when both shared and static libraries have been installed. (If you configure your package with cmake, this definition is added automatically.) - Tell the linker the name, Geographic, and location of the library. Using g++ as the linker, you would use \verbatim g++ -g -o testprogram testprogram.o -L/usr/local/lib -lGeographic \endverbatim With Visual Studio, you supply this information in the IDE via, e.g., \verbatim Linker -> Input -> Additional Dependencies = Geographic-i.lib (for shared library) Linker -> Input -> Additional Dependencies = Geographic.lib (for static library) Linker -> General -> Additional Library Directories = C:\pkg-vc14-x64\Geographic\lib \endverbatim Note that the library name is Geographic and not GeographicLib. For the Debug version of your program on Windows add "_d" to the library, e.g., Geographic_d-i.lib or Geographic_d.lib. - Tell the runtime environment where to find the shared library (assuming you compiled %Geographic as a shared library). With g++, this is accomplished by modifying the link line above to read \verbatim g++ -g -o testprogram testprogram.o -Wl,-rpath=/usr/local/lib \ -L/usr/local/lib -lGeographic \endverbatim (There are two other ways to specify the location of shared libraries at runtime: (1) define the environment variable LD_LIBRARY_PATH to be a colon-separated list of directories to search; (2) as root, specify /usr/local/lib as a directory searched by ldconfig(8).) On Windows, you need to ensure that Geographic.dll or Geographic_d.dll is in the same directory as your executable or else include the directory containing the dll in your PATH. - You can also use the pkg-config utility to specify compile and link flags. This requires that pkg-config be installed and that it's configured to search, e.g., /usr/local/lib/pgkconfig; if not, define the environment variable PKG_CONFIG_PATH to include this directory. The compile and link steps under Linux would typically be \verbatim g++ -c -g -O3 `pkg-config --cflags geographiclib` testprogram.cpp g++ -g -o testprogram testprogram.o `pkg-config --libs geographiclib` \endverbatim Here is a very simple test code, which uses the Geodesic class: \include example-Geodesic-small.cpp This example is examples/example-Geodesic-small.cpp. If you compile, link, and run it according to the instructions above, it should print out \verbatim 5551.76 km \endverbatim Here is a complete CMakeList.txt files you can use to build this test code using the installed library: \verbatim project (geodesictest) cmake_minimum_required (VERSION 3.1.0) find_package (GeographicLib REQUIRED) if (NOT MSVC) set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif () add_executable (${PROJECT_NAME} example-Geodesic-small.cpp) target_link_libraries (${PROJECT_NAME} ${GeographicLib_LIBRARIES}) if (MSVC) get_target_property (_LIBTYPE ${GeographicLib_LIBRARIES} TYPE) if (_LIBTYPE STREQUAL "SHARED_LIBRARY") # On Windows systems, copy the shared library to build directory add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CFG_INTDIR} COMMENT "Copying shared library for GeographicLib") endif () endif () \endverbatim The next steps are: - Learn about and run the \ref utilities. - Read the section, \ref organization, for an overview of the library. - Browse the Class List for full documentation on the classes in the library. - Look at the example code in the examples directory. Each file provides a very simple standalone example of using one GeographicLib class. These are included in the descriptions of the classes. - Look at the source code for the utilities in the tools directory for more examples of using GeographicLib from C++ code, e.g., GeodesicProj.cpp is a program to performing various geodesic projections. Here's a list of some of the abbreviations used here with links to the corresponding Wikipedia articles: - WGS84, World Geodetic System 1984. - UTM, Universal Transverse Mercator coordinate system. - UPS, Universal Polar Stereographic coordinate system. - MGRS, Military Grid Reference System. - EGM, Earth Gravity Model. - WMM, World Magnetic Model. - IGRF, International Geomagnetic Reference Field.
Back to \ref install. Forward to \ref utilities. Up to \ref contents.
**********************************************************************/ /** \page utilities Utility programs
Back to \ref start. Forward to \ref organization. Up to \ref contents.
Various utility programs are provided with GeographicLib. These should be installed in a directory included in your PATH (e.g., /usr/local/bin). These programs are wrapper programs that invoke the underlying functionality provided by the library. The utilities are - GeoConvert: convert geographic coordinates using GeoCoords. See \ref GeoConvert.cpp. - GeodSolve: perform geodesic calculations using Geodesic and GeodesicLine. See \ref GeodSolve.cpp. - Planimeter: compute the area of geodesic polygons using PolygonAreaT. See \ref Planimeter.cpp. - TransverseMercatorProj: convert between geographic and transverse Mercator. This is for testing TransverseMercatorExact and TransverseMercator. See \ref TransverseMercatorProj.cpp. - CartConvert: convert geodetic coordinates to geocentric or local cartesian using Geocentric and LocalCartesian. See \ref CartConvert.cpp. - GeodesicProj: perform projections based on geodesics using AzimuthalEquidistant, Gnomonic, and CassiniSoldner. See \ref GeodesicProj.cpp. - ConicProj: perform conic projections using LambertConformalConic and AlbersEqualArea. See \ref ConicProj.cpp. - GeoidEval: look up geoid heights using Geoid. See \ref GeoidEval.cpp. - Gravity: compute the earth's gravitational field using GravityModel and GravityCircle. See \ref Gravity.cpp. - MagneticField: compute the earth's magnetic field using MagneticModel and MagneticCircle. See \ref MagneticField.cpp. - RhumbSolve: perform rhumb line calculations using Rhumb and RhumbLine. See \ref RhumbSolve.cpp. . The documentation for these utilities is in the form of man pages. This documentation can be accessed by clicking on the utility name in the list above, running the man command on Unix-like systems, or by invoking the utility with the \--help option. A brief summary of usage is given by invoking the utility with the -h option. The version of the utility is given by the \--version option. The utilities all accept data on standard input, transform it in some way, and print the results on standard output. This makes the utilities easy to use within scripts to transform tabular data; however they can also be used interactively, often with the input supplied via a pipe, e.g., - echo 38SMB4488 | GeoConvert -d Online versions of four of these utilities are provided: - GeoConvert - GeodSolve - Planimeter - GeoidEval - RhumbSolve
Back to \ref start. Forward to \ref organization. Up to \ref contents.
**********************************************************************/ /** \page organization Code organization
Back to \ref utilities. Forward to \ref other. Up to \ref contents.
Here is a brief description of the relationship between the various components of GeographicLib. All of these are defined in the GeographicLib namespace. TransverseMercator, PolarStereographic, LambertConformalConic, and AlbersEqualArea provide the basic projections. The constructors for these classes specify the ellipsoid and the forward and reverse projections are implemented as const member functions. TransverseMercator uses Krüger's series which have been extended to sixth order in the square of the eccentricity. PolarStereographic, LambertConformalConic, and AlbersEqualArea use the exact formulas for the projections (e.g., from Snyder). TransverseMercator::UTM and PolarStereographic::UPS are const static instantiations specific for the WGS84 ellipsoid with the UTM and UPS scale factors. (These do \e not add the standard false eastings or false northings for UTM and UPS.) Similarly LambertConformalConic::Mercator is a const static instantiation of this projection for a WGS84 ellipsoid and a standard parallel of 0 (which gives the Mercator projection). AlbersEqualArea::CylindricalEqualArea, AzimuthalEqualAreaNorth, and AzimuthalEqualAreaSouth, likewise provide special cases of the equal area projection. UTMUPS uses TransverseMercator::UTM and PolarStereographic::UPS to perform the UTM and UPS projections. The class offers a uniform interface to UTM and UPS by treating UPS as UTM zone 0. This class stores no internal state and the forward and reverse projections are provided via static member functions. The forward projection offers the ability to override the standard UTM/UPS choice and the UTM zone. MGRS transforms between UTM/UPS coordinates and MGRS. UPS coordinates are handled as UTM zone 0. This class stores no internal state and the forward (UTM/UPS to MGRS) and reverse (MGRS to UTM/UPS) conversions are provided via static member functions. GeoCoords holds a single geographic location which may be specified as latitude and longitude, UTM or UPS, or MGRS. Member functions are provided to convert between coordinate systems and to provide formatted representations of them. GeoConvert is a simple command line utility to provide access to the GeoCoords class. TransverseMercatorExact is a drop in replacement for TransverseMercator which uses the exact formulas, based on elliptic functions, for the projection as given by Lee. TransverseMercatorProj is a simple command line utility to test to the TransverseMercator and TransverseMercatorExact. Geodesic and GeodesicLine perform geodesic calculations. The constructor for Geodesic specifies the ellipsoid and the direct and inverse calculations are implemented as const member functions. Geocentric::WGS84 is a const static instantiation of Geodesic specific for the WGS84 ellipsoid. In order to perform a series of direct geodesic calculations on a single line, the GeodesicLine class can be used. This packages all the information needed to specify a geodesic. A const member function returns the coordinates a specified distance from the starting point. GeodSolve is a simple command line utility to perform geodesic calculations. PolygonAreaT is a class which compute the area of geodesic polygons using the Geodesic class and Planimeter is a command line utility for the same purpose. AzimuthalEquidistant, CassiniSoldner, and Gnomonic are projections based on the Geodesic class. GeodesicProj is a command line utility to exercise these projections. GeodesicExact and GeodesicLineExact are drop in replacements for Geodesic and GeodesicLine in which the solution is given in terms of elliptic integrals (computed by EllipticFunction). These classes should be used if the absolute value of the flattening exceeds 0.02. The -E option to GeodSolve uses these classes. NearestNeighbor is a header-only class for efficiently \ref nearest of a collection of points where the distance function obeys the triangle inequality. The geodesic distance obeys this condition. Geocentric and LocalCartesian convert between geodetic and geocentric or a local cartesian system. The constructor for specifies the ellipsoid and the forward and reverse projections are implemented as const member functions. Geocentric::WGS84 is a const static instantiation of Geocentric specific for the WGS84 ellipsoid. CartConvert is a simple command line utility to provide access to these classes. Geoid evaluates geoid heights by interpolation. This is provided by the operator() member function. GeoidEval is a simple command line utility to provide access to this class. This class requires installation of data files for the various geoid models; see \ref geoidinst for details. Ellipsoid is a class which performs latitude conversions and returns various properties of the ellipsoid. GravityModel evaluates the earth's gravitational field using a particular gravity model. Various member functions return the gravitational field, the gravity disturbance, the gravity anomaly, and the geoid height Gravity is a simple command line utility to provide access to this class. If the field several points on a circle of latitude are sought then use GravityModel::Circle to return a GravityCircle object whose member functions performs the calculations efficiently. (This is particularly important for high degree models such as EGM2008.) These classes requires installation of data files for the various gravity models; see \ref gravityinst for details. NormalGravity computes the gravity of the so-called level ellipsoid. MagneticModel evaluates the earth's magnetic field using a particular magnetic model. The field is provided by the operator() member function. MagneticField is a simple command line utility to provide access to this class. If the field several points on a circle of latitude are sought then use MagneticModel::Circle to return a MagneticCircle object whose operator() member function performs the calculation efficiently. (This is particularly important for high degree models such as emm2010.) These classes requires installation of data files for the various magnetic models; see \ref magneticinst for details. Constants, Math, Utility, DMS, are general utility class which are used internally by the library; in addition EllipticFunction is used by TransverseMercatorExact, Ellipsoid, and GeodesicExact, and GeodesicLineExact; Accumulator is used by PolygonAreaT, and SphericalEngine, CircularEngine, SphericalHarmonic, SphericalHarmonic1, and SphericalHarmonic2 facilitate the summation of spherical harmonic series which is needed by and MagneticModel and MagneticCircle. One important definition is Math::real which is the type used for real numbers. This allows the library to be easily switched to using floats, doubles, or long doubles. However all the testing has been with real set to double and the library should be installed in this way. GeographicLib uniformly represents all angle-like variables (latitude, longitude, azimuth) in terms of degrees. To convert from degrees to radians, multiple the quantity by Math::degree(). To convert from radians to degrees , divide the quantity by Math::degree(). In general, the constructors for the classes in GeographicLib check their arguments and throw GeographicErr exceptions with a explanatory message if these are illegal. The member functions, e.g., the projections implemented by TransverseMercator and PolarStereographic, the solutions to the geodesic problem, etc., typically do not check their arguments; the calling program should ensure that the arguments are legitimate. However, the functions implemented by UTMUPS, MGRS, and GeoCoords do check their arguments and may throw GeographicErr exceptions. Similarly Geoid may throw exceptions on file errors. If a function does throw an exception, then the function arguments used for return values will not have been altered. GeographicLib attempts to act sensibly with NaNs. NaNs in constructors typically throw errors (an exception is GeodesicLine). However, calling the class functions with NaNs as arguments is not an error; NaNs are returned as appropriate. "INV" is treated as an invalid zone designation by UTMUPS. "INVALID" is the corresponding invalid MGRS string (and similarly for GARS, Geohash, and Georef strings). NaNs allow the projection of polylines which are separated by NaNs; in this format they can be easily plotted in MATLAB. A note about portability. For the most part, the code uses standard C++ and should be able to be deployed on any system with a modern C++ compiler. System dependencies come into - Math -- GeographicLib needs to define functions such as atanh for systems that lack them. The system dependence will disappear with the adoption of C++11 because the needed functions are part of that standard. - use of long double -- the type is used only for testing. On systems which lack this data type the cmake and autoconf configuration methods should detect its absence and omit the code that depends on it. - Geoid, GravityModel, and MagneticModel -- these class uses system-dependent default paths for looking up the respective datasets. It also relies on getenv to find the value of the environment variables. - Utility::readarray reads numerical data from binary files. This assumes that floating point numbers are in IEEE format. It attempts to handled the "endianness" of the target platform using the GEOGRAPHICLIB_WORDS_BIGENDIAN macro (which sets the compile-time constant Math::bigendian). An attempt is made to maintain backward compatibility with GeographicLib (especially at the level of your source code). Sometimes it's necessary to take actions that depend on what version of GeographicLib is being used; for example, you may want to use a new feature of GeographicLib, but want your code still to work with older versions. In that case, you can test the values of the macros GEOGRAPHICLIB_VERSION_MAJOR, GEOGRAPHICLIB_VERSION_MINOR, and GEOGRAPHICLIB_VERSION_PATCH; these expand to numbers (and the last one is usually 0); these macros appeared starting in version 1.31. There's also a macro GEOGRAPHICLIB_VERSION_STRING which expands to, e.g., "@PROJECT_VERSION@"; this macro has been defined since version 1.9. Since version 1.37, there's also been a macro GEOGRAPHICLIB_VERSION which encodes the version as a single number, e.g, 1003900. Do not rely on this particular packing; instead use the macro GEOGRAPHICLIB_VERSION_NUM(a,b,c) which allows you to compare versions with, e.g., \code #if GEOGRAPHICLIB_VERSION >= GEOGRAPHICLIB_VERSION_NUM(1,37,0) ... #endif \endcode
Back to \ref utilities. Forward to \ref other. Up to \ref contents.
**********************************************************************/ /** \page other Implementations in other languages
Back to \ref organization. Forward to \ref geoid. Up to \ref contents.
Various subsets of GeographicLib have been implemented in other languages. In some cases, these are available as independent packages. Here is a summary: - C (geodesic routines): documentation, also included with recent versions of PROJ; - Fortran (geodesic routines): documentation; - Java (geodesic routines): Maven Central package, documentation; - JavaScript (geodesic routines): npm package, documentation; - Python (geodesic routines): PyPI package, documentation; - MATLAB/Octave (geodesic and some other routines): MATLAB Central package, documentation; - C# (.NET wrapper for C++ library): documentation. Some more details are available in the following sections - \ref c-fortran - \ref java. - \ref javascript. - \ref python. - \ref matlab. - \ref dotnet. - \ref maxima. \section c-fortran C and Fortran implementation This includes the geodesic capabilities of GeographicLib. The source code is in the directories legacy/C and legacy/Fortran. These are intended for use in old codes written in these languages and should work any reasonably modern compiler. These implementations are entirely self-contained and do not depend on the rest of GeographicLib. Sample main programs to solve the direct and inverse geodesic problems and to compute polygonal areas are provided. The C library is also included as part of PROJ starting with version 4.9.0, where it is used as the computational backend for geod(1). For documentation, see - C library for geodesics, - Fortran library for geodesics. It is also possible to call the C++ version of GeographicLib directly from C and the directory wrapper/C contains a small example, which converts heights above the geoid to heights above the ellipsoid. \section java Java implementation This includes the geodesic capabilities of GeographicLib. The source code is in the directory java. This implementation is entirely self-contained and does not depend on the rest of GeographicLib. Sample main programs to solve the direct and inverse geodesic problems and to compute polygonal areas are provided. This package is available on Maven Central; so if you're using Apache Maven as your build system, you can use this package by including the dependency \verbatim net.sf.geographiclib GeographicLib-Java @PROJECT_VERSION@ \endverbatim in your pom.xml. For documentation, see - Java library for geodesics. \section javascript JavaScript implementation This includes the geodesic capabilities of GeographicLib. The source code is in the directory js. This implementation is entirely self-contained and does not depend on the rest of GeographicLib. The library is available as an npm package. To install this package, use \verbatim npm install geographiclib \endverbatim For documentation, see - JavaScript library for geodesics. Examples of using this interface are - a geodesic calculator showing the solution of direct and inverse geodesic problem, finding intermediate points on a geodesic line, and computing the area of a geodesic polygon; - displaying geodesics in Google Maps which shows the geodesic, the geodesic circle, and various geodesic envelopes. \section python Python implementation This includes the geodesic capabilities of GeographicLib. The source code is in the directory python. This implementation is entirely self-contained and does not depend on the rest of GeographicLib. The library is available as an PyPI package. To install this package, use \verbatim pip install geographiclib \endverbatim For documentation, see - Python library for geodesics. It is also possible to call the C++ version of GeographicLib directly from Python and the directory wrapper/python contains a small example, which converts heights above the geoid to heights above the ellipsoid. \section matlab MATLAB and Octave implementations The includes the geodesic capabilities of GeographicLib and implementations of the TransverseMercator, PolarStereographic, AzimuthalEquidistant, CassiniSoldner, Gnomonic, UTMUPS, MGRS, Geocentric, and LocalCartesian classes. In addition, it includes solutions of the direct, inverse, and area problems for \ref greatellipse. Because these functions are all vectorized, their performance is comparable to the C++ routines. The minimum version numbers required are - MATLAB, version 7.9, 2009b, - Octave, version 3.4, Feb. 2011. . In addition, in order to use the geoid routines, Octave needs to have been built with a version of GraphicsMagick which supports 16-bit images. The source code is in the directory matlab/geographiclib. This implementation is entirely self-contained and does not depend on the rest of GeographicLib. The library is available as an MATLAB Central package, GeographicLib toolbox, documentation. A summary of the routines is obtained by \verbatim help geographiclib \endverbatim Prior to version 1.42, GeographicLib was distributed with some MATLAB functionality offered via compiled interface code. This has now been replaced by native MATLAB wrapper functions in matlab/geographiclib-legacy; these depend on the GeographicLib toolbox. A summary of the routines is obtained by \verbatim help geographiclib-legacy \endverbatim It is also possible to call the C++ version of GeographicLib directly from MATLAB or Octave and the directory wrapper/matlab contains a small example, which solves the inverse geodesic problem for ellipsoids with arbitrary flattening. (This example is taken from the MATLAB interface code which was provided prior to version 1.42.) \section dotnet .NET wrapper This is a comprehensive wrapper library, written and maintained by Scott Heiman, which exposes all of the functionality of GeographicLib to the .NET family of languages. For documentation, see - NETGeographicLib .NET wrapper library. \section maxima Maxima routines Maxima is a free computer algebra system which can be downloaded from http://maxima.sourceforge.net. Maxima was used to generate the series used by TransverseMercator ( tmseries.mac), Geodesic ( geod.mac), Rhumb ( rhumbarea.mac), \ref gearea ( gearea.mac), the relation between \ref auxlat ( auxlat.mac), and to generate accurate data for testing ( tm.mac and geodesic.mac). The latter uses Maxima's bigfloat arithmetic together with series extended to high order or solutions in terms of elliptic integrals ( ellint.mac). These files contain brief instructions on how to use them.
Back to \ref organization. Forward to \ref geoid. Up to \ref contents.
**********************************************************************/ /** \page geoid Geoid height
Back to \ref other. Forward to \ref gravity. Up to \ref contents.
The gravitational equipotential surface approximately coinciding with mean sea level is called the geoid. The Geoid class and the GeoidEval utility evaluate the height of the geoid above the WGS84 ellipsoid. This can be used to convert heights above mean sea level to heights above the WGS84 ellipsoid. Because the normal to the ellipsoid differs from the normal to the geoid (the direction of a plumb line) there is a slight ambiguity in the measurement of heights; however for heights up to 10 km this ambiguity is only 1 mm. The geoid is usually approximated by an "earth gravity model" (EGM). The models published by the NGA are: - EGM84: http://earth-info.nga.mil/GandG/wgs84/gravitymod/wgs84_180/wgs84_180.html - EGM96: http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/egm96.html - EGM2008: http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008 . Geoid offers a uniform way to handle all 3 geoids at a variety of grid resolutions. (In contrast, the software tools that NGA offers are different for each geoid, and the interpolation programs are different for each grid resolution. In addition these tools are written in Fortran with is nowadays difficult to integrate with other software.) The height of the geoid above the ellipsoid, \e N, is sometimes called the geoid undulation. It can be used to convert a height above the ellipsoid, \e h, to the corresponding height above the geoid (the orthometric height, roughly the height above mean sea level), \e H, using the relations    \e h = \e N + \e H;   \e H = −\e N + \e h. Unlike other components of GeographicLib, there is a appreciable error in the results obtained (at best, the RMS error is 1 mm). However the class provides methods to report the maximum and RMS errors in the results. The class also returns the gradient of the geoid. This can be used to estimate the direction of a plumb line relative to the WGS84 ellipsoid. The GravityModel class calculates geoid heights using the underlying gravity model. This is slower then Geoid but considerably more accurate. This class also can accurately compute all the components of the acceleration due to gravity (and hence the direction of plumb line). Go to - \ref geoidinst - \ref geoidformat - \ref geoidinterp - \ref geoidcache - \ref testgeoid \section geoidinst Installing the geoid datasets The geoid heights are computed using interpolation into a rectangular grid. The grids are read from data files which have been are computed using the NGA synthesis programs in the case of the EGM84 and EGM96 models and using the NGA binary gridded data files in the case of EGM2008. These data files are available for download:
Available geoid data files
name geoid grid size\n(MB)
Download Links (size, MB)
tar file Windows\n installer zip file
egm84-30 EGM84
30'
0.6
link (0.5)
link (0.8)
link (0.5)
egm84-15 EGM84
15'
2.1
link (1.5)
link (1.9)
link (2.0)
egm96-15 EGM96
15'
2.1
link (1.5)
link (1.9)
link (2.0)
egm96-5 EGM96
5'
19
link (11)
link (11)
link (17)
egm2008-5 EGM2008
5'
19
link (11)
link (11)
link (17)
egm2008-2_5 EGM2008
2.5'
75
link (35)
link (33)
link (65)
egm2008-1 EGM2008
1'
470
link (170)
link (130)
link (390)
The "size" column is the size of the uncompressed data and it also gives the memory requirements for caching the entire dataset using the Geoid::CacheAll method. At a minimum you should install egm96-5 and either egm2008-1 or egm2008-2_5. Many applications use the EGM96 geoid, however the use of EGM2008 is growing. (EGM84 is rarely used now.) For Linux and Unix systems, GeographicLib provides a shell script geographiclib-get-geoids (typically installed in /usr/local/sbin) which automates the process of downloading and installing the geoid data. For example \verbatim geographiclib-get-geoids best # to install egm84-15, egm96-5, egm2008-1 geographiclib-get-geoids -h # for help \endverbatim This script should be run as a user with write access to the installation directory, which is typically /usr/local/share/GeographicLib (this can be overridden with the -p flag), and the data will then be placed in the "geoids" subdirectory. Windows users should download and run the Windows installers. These will prompt for an installation directory with the default being \verbatim C:/ProgramData/GeographicLib \endverbatim (which you probably should not change) and the data is installed in the "geoids" sub-directory. (The second directory name is an alternate name that Windows 7 uses for the "Application Data" directory.) Otherwise download \e either the tar.bz2 file \e or the zip file (they have the same contents). If possible use the tar.bz2 files, since these are compressed about 2 times better than the zip file. To unpack these, run, for example \verbatim mkdir -p /usr/local/share/GeographicLib tar xofjC egm96-5.tar.bz2 /usr/local/share/GeographicLib tar xofjC egm2008-2_5.tar.bz2 /usr/local/share/GeographicLib etc. \endverbatim and, again, the data will be placed in the "geoids" subdirectory. However you install the geoid data, all the datasets should be installed in the same directory. Geoid and GeoidEval uses a compile time default to locate the datasets. This is - /usr/local/share/GeographicLib/geoids, for non-Windows systems - C:/ProgramData/GeographicLib/geoids, for Windows systems . consistent with the examples above. This may be overridden at run-time by defining the GEOGRAPHICLIB_GEOID_PATH or the GEOGRAPHICLIB_DATA environment variables; see Geoid::DefaultGeoidPath() for details. Finally, the path may be set using the optional second argument to the Geoid constructor or with the "-d" flag to GeoidEval. Supplying the "-h" flag to GeoidEval reports the default geoid path for that utility. The "-v" flag causes GeoidEval to report the full path name of the data file it uses. \section geoidformat The format of the geoid data files The gridded data used by the Geoid class is stored in 16-bit PGM files. Thus the data for egm96-5 might be stored in the file - /usr/local/share/GeographicLib/geoids/egm96-5.pgm . PGM simple graphic format with the following properties - it is well documented here; - there are no separate "little-endian" and "big-endian" versions; - it uses 1 or 2 bytes per pixel; - pixels can be randomly accessed; - comments can be added to the file header; - it is sufficiently simple that it can be easily read without using the libnetpbm library (and thus we avoid adding a software dependency to GeographicLib). . The major drawback of this format is that since there are only 65535 possible pixel values, the height must be quantized to 3 mm. However, the resulting quantization error (up to 1.5 mm) is typically smaller than the linear interpolation errors. The comments in the header for egm96-5 are \verbatim # Geoid file in PGM format for the GeographicLib::Geoid class # Description WGS84 EGM96, 5-minute grid # URL http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/egm96.html # DateTime 2009-08-29 18:45:03 # MaxBilinearError 0.140 # RMSBilinearError 0.005 # MaxCubicError 0.003 # RMSCubicError 0.001 # Offset -108 # Scale 0.003 # Origin 90N 0E # AREA_OR_POINT Point # Vertical_Datum WGS84 \endverbatim Of these lines, the Scale and Offset lines are required and define the conversion from pixel value to height (in meters) using \e height = \e offset + \e scale \e pixel. The Geoid constructor also reads the Description, DateTime, and error lines (if present) and stores the resulting data so that it can be returned by Geoid::Description, Geoid::DateTime, Geoid::MaxError, and Geoid::RMSError methods. The other lines serve as additional documentation but are not used by this class. Accompanying egm96-5.pgm (and similarly with the other geoid data files) are two files egm96-5.wld and egm96-5.pgm.aux.xml. The first is an ESRI "world" file and the second supplies complete projection metadata for use by GDAL. Neither of these files is read by Geoid. You can use gdal_translate to convert the data files to a standard GeoTiff, e.g., with \verbatim gdal_translate -ot Float32 -scale 0 65000 -108 87 egm96-5.pgm egm96-5.tif \endverbatim The arguments to -scale here are specific to the Offset and Scale parameters used in the pgm file (note 65000 * 0.003 − 108 = 87). You can check these by running GeoidEval with the "-v" option. Here is a sample script which uses GDAL to create a 1-degree squared grid of geoid heights at 3" resolution (matching DTED1) by bilinear interpolation. \verbatim #! /bin/sh lat=37 lon=067 res=3 # resolution in seconds TEMP=`mktemp junkXXXXXXXXXX` # temporary file for GDAL gdalwarp -q -te `echo $lon $lat $res | awk '{ lon = $1; lat = $2; res = $3; printf "%.14f %.14f %.14f %.14f", lon -0.5*res/3600, lat -0.5*res/3600, lon+1+0.5*res/3600, lat+1+0.5*res/3600; }'` -ts $((3600/res+1)) $((3600/res+1)) -r bilinear egm96-5.tif $TEMP gdal_translate -quiet \ -mo AREA_OR_POINT=Point \ -mo Description="WGS84 EGM96, $res-second grid" \ -mo Vertical_Datum=WGS84 \ -mo Tie_Point_Location=pixel_corner \ $TEMP e$lon-n$lat.tif rm -f $TEMP \endverbatim Because the pgm files are uncompressed, they can take up a lot of disk space. Some compressed formats compress in tiles and so might be compatible with the requirement that the data can be randomly accessed. In particular gdal_translate can be used to convert the pgm files to compressed tiff files with \verbatim gdal_translate -co COMPRESS=LZW -co PREDICTOR=2 \ -co TILED=YES -co BLOCKXSIZE=256 -co BLOCKYSIZE=256 \ egmyy-g.pgm egmyy-g.tif \endverbatim The resulting files sizes are \verbatim pgm tif egm84-30 0.6 MB 0.5 MB egm84-15 2.1 MB 1.4 MB egm96-15 2.1 MB 1.5 MB egm96-5 19 MB 8.5 MB egm2008-5 19 MB 9.8 MB egm2008-2_5 75 MB 28 MB egm2008-1 470 MB 97 MB \endverbatim Currently, there are no plans for GeographicLib to support this compressed format. The Geoid class only handles world-wide geoid models. The pgm provides geoid height postings on grid of points with uniform spacing in latitude (row) and longitude (column). If the dimensions of the pgm file are \e h × \e w, then latitude (resp. longitude) spacing is −180°/(\e h − 1) (resp. 360°/\e w), with the (0,0) pixel given the value at φ = 90°, λ = 0°. Models covering a limited area will need to be "inserted" into a world-wide grid before being accessible to the Geoid class. \section geoidinterp Interpolating the geoid data Geoid evaluates the geoid height using bilinear or cubic interpolation. The bilinear interpolation is based on the values at the 4 corners of the enclosing cell. The interpolated height is a continuous function of position; however the gradient has discontinuities are cell boundaries. The quantization of the data files exacerbates the errors in the gradients. The cubic interpolation is a least-squares fit to the values on a 12-point stencil with weights as follows: \verbatim . 1 1 . 1 2 2 1 1 2 2 1 . 1 1 . \endverbatim The cubic is constrained to be independent of longitude when evaluating the height at one of the poles. Cubic interpolation is considerably more accurate than bilinear interpolation; however, in this implementation there are small discontinuities in the heights are cell boundaries. The over-constrained cubic fit slightly reduces the quantization errors on average. The algorithm for the least squares fit is taken from, F. H. Lesh, Multi-dimensional least-squares polynomial curve fitting, CACM 2, 29--30 (1959). This algorithm is not part of Geoid; instead it is implemented as Maxima code which is used to precompute the matrices to convert the function values on the stencil into the coefficients from the cubic polynomial. This code is included as a comment in Geoid.cpp. The interpolation methods are quick and give good accuracy. Here is a summary of the combined quantization and interpolation errors for the heights.
Interpolation and quantization errors for geoid heights
name geoid grid
bilinear error
cubic error
max
rms
max
rms
egm84-30 EGM84
30'
1.546 m
70 mm
0.274 m
14 mm
egm84-15 EGM84
15'
0.413 m
18 mm
0.021 m
1.2 mm
egm96-15 EGM96
15'
1.152 m
40 mm
0.169 m
7.0 mm
egm96-5 EGM96
5'
0.140 m
4.6 mm
0.0032 m
0.7 mm
egm2008-5 EGM2008
5'
0.478 m
12 mm
0.294 m
4.5 mm
egm2008-2_5EGM2008
2.5'
0.135 m
3.2 mm
0.031 m
0.8 mm
egm2008-1 EGM2008
1'
0.025 m
0.8 mm
0.0022 m
0.7 mm
The errors are with respect to the specific NGA earth gravity model (not to any "real" geoid). The RMS values are obtained using 5 million uniformly distributed random points. The maximum values are obtained by evaluating the errors using a different grid with points at the centers of the original grid. (The RMS difference between EGM96 and EGM2008 is about 0.5 m. The RMS difference between EGM84 and EGM96 is about 1.5 m.) The errors in the table above include the quantization errors that arise because the height data that Geoid uses are quantized to 3 mm. If, instead, Geoid were to use data files without such quantization artifacts, the overall error would be reduced but only modestly as shown in the following table, where only the changed rows are included and where the changed entries are given in bold:
Interpolation (only!) errors for geoid heights
name geoid grid
bilinear error
cubic error
max
rms
max
rms
egm96-5 EGM96
5'
0.140 m
4.6 mm
0.0026 m
0.1 mm
egm2008-2_5EGM2008
2.5'
0.135 m
3.2 mm
0.031 m
0.4 mm
egm2008-1 EGM2008
1'
0.025 m
0.6 mm
0.0010 m
0.011 mm
\section geoidcache Caching the geoid data A simple way of calling Geoid is as follows \code #include #include ... GeographicLib::Geoid g("egm96-5"); double lat, lon; while (std::cin >> lat >> lon) std::cout << g(lat, lon) << "\n"; ... \endcode The first call to g(lat, lon) causes the data for the stencil points (4 points for bilinear interpolation and 12 for cubic interpolation) to be read and the interpolated value returned. A simple 0th-order caching scheme is provided by default, so that, if the second and subsequent points falls within the same grid cell, the data values are not reread from the file. This is adequate for most interactive use and also minimizes disk accesses for the case when a continuous track is being followed. If a large quantity of geoid calculations are needed, the calculation can be sped up by preloading the data for a rectangular block with Geoid::CacheArea or the entire dataset with Geoid::CacheAll. If the requested points lie within the cached area, the cached data values are used; otherwise the data is read from disk as before. Caching all the data is a reasonable choice for the 5' grids and coarser. Caching all the data for the 1' grid will require 0.5 GB of RAM and should only be used on systems with sufficient memory. The use of caching does not affect the values returned. Because of the caching and the random file access, this class is \e not normally thread safe; i.e., a single instantiation cannot be safely used by multiple threads. If multiple threads need to calculate geoid heights, there are two alternatives: - they should all construct thread-local instantiations. - Geoid should be constructed with \e threadsafe = true. This causes all the data to be read at the time of construction (and if this fails, an exception is thrown), the data file to be closed and the single-cell caching to be turned off. The resulting object may then be shared safely between threads. \section testgeoid Test data for geoids A test set for the geoid models is available at - GeoidHeights.dat.gz . This is about 11 MB (compressed). This test set consists of a set of 500000 geographic coordinates together with the corresponding geoid heights according to various earth gravity models. Each line of the test set gives 6 space delimited numbers - latitude (degrees, exact) - longitude (degrees, exact) - EGM84 height (meters, accurate to 1 μm) - EGM96 height (meters, accurate to 1 μm) - EGM2008 height (meters, accurate to 1 μm) . The latitude and longitude are all multiples of 10−6 deg and should be regarded as exact. The geoid heights are computed using the harmonic NGA synthesis programs, where the programs were compiled (with gfortran) and run under Linux. In the case of the EGM2008 program, a SAVE statement needed to be added to subroutine latf, in order for the program to compile correctly with a stack-based compiler. Similarly the EGM96 code requires a SAVE statement in subroutine legfdn.
Back to \ref other. Forward to \ref gravity. Up to \ref contents.
**********************************************************************/ /** \page gravity Gravity models
Back to \ref geoid. Forward to \ref normalgravity. Up to \ref contents.
GeographicLib can compute the earth's gravitational field with an earth gravity model using the GravityModel and GravityCircle classes and with the Gravity utility. These models expand the gravitational potential of the earth as sum of spherical harmonics. The models also specify a reference ellipsoid, relative to which geoid heights and gravity disturbances are measured. Underlying all these models is normal gravity which is the exact solution for an idealized rotating ellipsoidal body. This is implemented with the NormalGravity class and some notes on are provided in section \ref normalgravity Go to - \ref gravityinst - \ref gravityformat - \ref gravitynga - \ref gravitygeoid - \ref gravityatmos - \ref gravityparallel - \ref normalgravity (now on its own page) The supported models are - egm84, the Earth Gravity Model 1984, which includes terms up to degree 180. - egm96, the Earth Gravity Model 1996, which includes terms up to degree 360. - egm2008, the Earth Gravity Model 2008, which includes terms up to degree 2190. - wgs84, the WGS84 Reference Ellipsoid. This is just reproduces the normal gravitational field for the reference ellipsoid. This includes the zonal coefficients up to order 20. Usually NormalGravity::WGS84() should be used instead. - grs80, the GRS80 Reference Ellipsoid. This is just reproduces the normal gravitational field for the GRS80 ellipsoid. This includes the zonal coefficients up to order 20. Usually NormalGravity::GRS80() should be used instead. See - W. A. Heiskanen and H. Moritz, Physical Geodesy (Freeman, San Francisco, 1967). . for more information. Acknowledgment: I would like to thank Mathieu Peyréga for sharing EGM_Geoid_CalculatorClass from his Geo library with me. His implementation was the first I could easily understand and he and I together worked through some of the issues with overflow and underflow the occur while performing high-degree spherical harmonic sums. \section gravityinst Installing the gravity models These gravity models are available for download:
Available gravity models
name max\n degree size\n(kB)
Download Links (size, kB)
tar file Windows\n installer zip file
egm84
180
27
link (26)
link (55)
link (26)
egm96
360
2100
link (2100)
link (2300)
link (2100)
egm2008
2190
76000
link (75000)
link (72000)
link (73000)
wgs84
20
1
link (1)
link (30)
link (1)
The "size" column is the size of the uncompressed data. For Linux and Unix systems, GeographicLib provides a shell script geographiclib-get-gravity (typically installed in /usr/local/sbin) which automates the process of downloading and installing the gravity models. For example \verbatim geographiclib-get-gravity all # to install egm84, egm96, egm2008, wgs84 geographiclib-get-gravity -h # for help \endverbatim This script should be run as a user with write access to the installation directory, which is typically /usr/local/share/GeographicLib (this can be overridden with the -p flag), and the data will then be placed in the "gravity" subdirectory. Windows users should download and run the Windows installers. These will prompt for an installation directory with the default being \verbatim C:/ProgramData/GeographicLib \endverbatim (which you probably should not change) and the data is installed in the "gravity" sub-directory. (The second directory name is an alternate name that Windows 7 uses for the "Application Data" directory.) Otherwise download \e either the tar.bz2 file \e or the zip file (they have the same contents). To unpack these, run, for example \verbatim mkdir -p /usr/local/share/GeographicLib tar xofjC egm96.tar.bz2 /usr/local/share/GeographicLib tar xofjC egm2008.tar.bz2 /usr/local/share/GeographicLib etc. \endverbatim and, again, the data will be placed in the "gravity" subdirectory. However you install the gravity models, all the datasets should be installed in the same directory. GravityModel and Gravity uses a compile time default to locate the datasets. This is - /usr/local/share/GeographicLib/gravity, for non-Windows systems - C:/ProgramData/GeographicLib/gravity, for Windows systems . consistent with the examples above. This may be overridden at run-time by defining the GEOGRAPHICLIB_GRAVITY_PATH or the GEOGRAPHICLIB_DATA environment variables; see GravityModel::DefaultGravityPath() for details. Finally, the path may be set using the optional second argument to the GravityModel constructor or with the "-d" flag to Gravity. Supplying the "-h" flag to Gravity reports the default path for gravity models for that utility. The "-v" flag causes Gravity to report the full path name of the data file it uses. \section gravityformat The format of the gravity model files The constructor for GravityModel reads a file called NAME.egm which specifies various properties for the gravity model. It then opens a binary file NAME.egm.cof to obtain the coefficients of the spherical harmonic sum. The first line of the .egm file must consist of "EGMF-v" where EGMF stands for "Earth Gravity Model Format" and v is the version number of the format (currently "1"). The rest of the File is read a line at a time. A # character and everything after it are discarded. If the result is just white space it is discarded. The remaining lines are of the form "KEY WHITESPACE VALUE". In general, the KEY and the VALUE are case-sensitive. GravityModel only pays attention to the following keywords - keywords that affect the field calculation, namely: - ModelRadius (required), the normalizing radius for the model in meters. - ReferenceRadius (required), the equatorial radius \e a for the reference ellipsoid meters. - ModelMass (required), the mass constant \e GM for the model in meters3/seconds2. - ReferenceMass (required), the mass constant \e GM for the reference ellipsoid in meters3/seconds2. - AngularVelocity (required), the angular velocity ω for the model \e and the reference ellipsoid in rad seconds−1. - Flattening, the flattening of the reference ellipsoid; this can be given a fraction, e.g., 1/298.257223563. One of Flattening and DynamicalFormFactor is required. - DynamicalFormFactor, the dynamical form factor J2 for the reference ellipsoid. One of Flattening and DynamicalFormFactor is required. - HeightOffset (default 0), the constant height offset (meters) added to obtain the geoid height. - CorrectionMultiplier (default 1), the multiplier for the "zeta-to-N" correction terms for the geoid height to convert them to meters. - Normalization (default full), the normalization used for the associated Legendre functions (full or schmidt). - ID (required), 8 printable characters which serve as a signature for the .egm.cof file (they must appear as the first 8 bytes of this file). . The parameters ModelRadius, ModelMass, and AngularVelocity apply to the gravity model, while ReferenceRadius, ReferenceMass, AngularVelocity, and either Flattening or DynamicalFormFactor characterize the reference ellipsoid. AngularVelocity (because it can be measured precisely) is the same for the gravity model and the reference ellipsoid. ModelRadius is merely a scaling parameter for the gravity model and there's no requirement that it be close to the equatorial radius of the earth (although that's typically how it is chosen). ModelMass and ReferenceMass need not be the same and, indeed, they are slightly difference for egm2008. As a result the disturbing potential \e T has a 1/\e r dependence at large distances. - keywords that store data that the user can query: - Name, the name of the model. - Description, a more descriptive name of the model. - ReleaseDate, when the model was created. - keywords that are examined to verify that their values are valid: - ByteOrder (default little), the order of bytes in the .egm.cof file. Only little endian is supported at present. . Other keywords are ignored. The coefficient file NAME.egm.cof is a binary file in little endian order. The first 8 bytes of this file must match the ID given in NAME.egm. This is followed by 2 sets of spherical harmonic coefficients. The first of these gives the gravity potential and the second gives the zeta-to-N corrections to the geoid height. The format for each set of coefficients is: - \e N, the maximum degree of the sum stored as a 4-byte signed integer. This must satisfy \e N ≥ −1. - \e M, the maximum order of the sum stored as a 4-byte signed integer. This must satisfy \e N ≥ \e M ≥ −1. - Cnm, the coefficients of the cosine coefficients of the sum in column (i.e., \e m) major order. There are (\e M + 1) (2\e N - \e M + 2) / 2 elements which are stored as IEEE doubles (8 bytes). For example for \e N = \e M = 3, there are 10 coefficients arranged as C00, C10, C20, C30, C11, C21, C31, C22, C32, C33. - Snm, the coefficients of the sine coefficients of the sum in column (i.e., \e m) major order starting at \e m = 1. There are \e M (2\e N - \e M + 1) / 2 elements which are stored as IEEE doubles (8 bytes). For example for \e N = \e M = 3, there are 6 coefficients arranged as S11, S21, S31, S22, S32, S33. . Although the coefficient file is in little endian order, GeographicLib can read it on big endian machines. It can only be read on machines which store doubles in IEEE format. As an illustration, here is egm2008.egm: \verbatim EGMF-1 # An Earth Gravity Model (Format 1) file. For documentation on the # format of this file see # https://geographiclib.sourceforge.io/html/gravity.html#gravityformat Name egm2008 Publisher National Geospatial Intelligence Agency Description Earth Gravity Model 2008 URL http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008 ReleaseDate 2008-06-01 ConversionDate 2011-11-19 DataVersion 1 ModelRadius 6378136.3 ModelMass 3986004.415e8 AngularVelocity 7292115e-11 ReferenceRadius 6378137 ReferenceMass 3986004.418e8 Flattening 1/298.257223563 HeightOffset -0.41 # Gravitational and correction coefficients taken from # EGM2008_to2190_TideFree and Zeta-to-N_to2160_egm2008 from # the egm2008 distribution. ID EGM2008A \endverbatim The code to produce the coefficient files for the wgs84 and grs80 models is \include make-egmcof.cpp \section gravitynga Comments on the NGA harmonic synthesis code GravityModel attempts to reproduce the results of NGA's harmonic synthesis code for EGM2008, hsynth_WGS84.f. Listed here are issues that I encountered using the NGA code: -# A compiler which allocates local variables on the stack produces an executable with just returns NaNs. The problem here is a missing SAVE statement in subroutine latf. -# Because the model and references masses for egm2008 differ (by about 1 part in 109), there should be a 1/\e r contribution to the disturbing potential \e T. However, this term is set to zero in hsynth_WGS84 (effectively altering the normal potential). This shifts the surface \e W = U0 outward by about 5 mm. Note too that the reference ellipsoid is no longer a level surface of the effective normal potential. -# Subroutine radgrav computes the ellipsoidal coordinate β incorrectly. This leads to small errors in the deflection of the vertical, ξ and η, when the height above the ellipsoid, \e h, is non-zero (about 10−7 arcsec at \e h = 400 km). -# There are several expressions which will return inaccurate results due to cancellation. For example, subroutine grs computes the flattening using \e f = 1 − sqrt(1 − e2). Much better is to use \e f = e2/(1 + sqrt(1 − e2)). The expressions for \e q and \e q' in grs and radgrav suffer from similar problems. The resulting errors are tiny (about 50 pm in the geoid height); however, given that's there's essentially no cost to using more accurate expressions, it's preferable to do so. -# hsynth_WGS84 returns an "undefined" value for \e xi and \e eta at the poles. Better would be to return the value obtained by taking the limit \e lat → ± 90°. . Issues 1--4 have been reported to the authors of hsynth_WGS84. Issue 1 is peculiar to Fortran and is not encountered in C++ code and GravityModel corrects issues 3--5. On issue 2, GravityModel neglects the 1/\e r term in \e T in GravityModel::GeoidHeight and GravityModel::SphericalAnomaly in order to produce results which match NGA's for these quantities. On the other hand, GravityModel::Disturbance and GravityModel::T do include this term. \section gravitygeoid Details of the geoid height and anomaly calculations Ideally, the geoid represents a surface of constant gravitational potential which approximates mean sea level. In reality some approximations are taken in determining this surface. The steps taking by GravityModel in computing the geoid height are described here (in the context of EGM2008). This mimics NGA's code hsynth_WGS84 closely because most users of EGM2008 use the gridded data generated by this code (e.g., Geoid) and it is desirable to use a consistent definition of the geoid height. - The model potential is band limited; the minimum wavelength that is represented is 360°/2160 = 10' (i.e., about 10NM or 18.5km). The maximum degree for the spherical harmonic sum is 2190; however the model was derived using ellipsoidal harmonics of degree and order 2160 and the degree was increased to 2190 in order to capture the ellipsoidal harmonics faithfully with spherical harmonics. - The 1/\e r term is omitted from the \e T (this is issue 2 in \ref gravitynga). This moves the equipotential surface by about 5mm. - The surface \e W = U0 is determined by Bruns' formula, which is roughly equivalent to a single iteration of Newton's method. The RMS error in this approximation is about 1.5mm with a maximum error of about 10 mm. - The model potential is only valid above the earth's surface. A correction therefore needs to be included where the geoid lies beneath the terrain. This is NGA's "zeta-to-N" correction, which is represented by a spherical harmonic sum of degree and order 2160 (and so it misses short wavelength terrain variations). In addition, it entails estimating the isostatic equilibrium of the earth's crust. The correction lies in the range [−5.05 m, 0.05 m], however for 99.9% of the earth's surface the correction is less than 10 mm in magnitude. - The resulting surface lies above the observed mean sea level, so −0.41m is added to the geoid height. (Better would be to change the potential used to define the geoid; but this would only change the result by about 2mm.) . A useful discussion of the problems with defining a geoid is given by Dru A. Smith in There is no such thing as "The" EGM96 geoid: Subtle points on the use of a global geopotential model, IGeS Bulletin No. 8, International Geoid Service, Milan, Italy, pp. 17--28 (1998). GravityModel::GeoidHeight reproduces the results of the several NGA codes for harmonic synthesis with the following maximum discrepancies: - egm84 = 1.1mm. This is probably due to inconsistent parameters for the reference ellipsoid in the NGA code. (In particular, the value of mass constant excludes the atmosphere; however, it's not clear whether the other parameters have been correspondingly adjusted.) Note that geoid heights predicted by egm84 differ from those of more recent gravity models by about 1 meter. - egm96 = 23nm. - egm2008 = 78pm. After addressing some of the issues alluded to in issue 4 in \ref gravitynga, the maximum discrepancy becomes 23pm. The formula for the gravity anomaly vector involves computing gravity and normal gravity at two different points (with the displacement between the points unknown ab initio). Since the gravity anomaly is already a small quantity it is sometimes acceptable to employ approximations that change the quantities by \e O(\e f). The NGA code uses the spherical approximation described by Heiskanen and Moritz, Sec. 2-14 and GravityModel::SphericalAnomaly uses the same approximation for compatibility. In this approximation, the gravity disturbance delta = grad \e T is calculated. Here, \e T once again excludes the 1/\e r term (this is issue 2 in \ref gravitynga and is consistent with the computation of the geoid height). Note that delta compares the gravity and the normal gravity at the \e same point; the gravity anomaly vector is then found by estimating the gradient of the normal gravity in the limit that the earth is spherically symmetric. delta is expressed in \e spherical coordinates as \e deltax, \e deltay, \e deltaz where, for example, \e deltaz is the \e radial component of delta (not the component perpendicular to the ellipsoid) and \e deltay is similarly slightly different from the usual northerly component. The components of the anomaly are then given by - gravity anomaly, \e Dg01 = \e deltaz − 2T/\e R, where \e R distance to the center of the earth; - northerly component of the deflection of the vertical, \e xi = − deltay/\e gamma, where \e gamma is the magnitude of the normal gravity; - easterly component of the deflection of the vertical, \e eta = − deltax/\e gamma. . NormalGravity computes the normal gravity accurately and avoids issue 3 of \ref gravitynga. Thus while GravityModel::SphericalAnomaly reproduces the results for \e xi and \e eta at \e h = 0, there is a slight discrepancy if \e h is non-zero. \section gravityatmos The effect of the mass of the atmosphere All of the supported models use WGS84 for the reference ellipsoid. This has (see TR8350.2, table 3.1) - \e a = 6378137 m - \e f = 1/298.257223563 - ω = 7292115 × 10−11 rad s−1 - \e GM = 3986004.418 × 108 m3 s−2. . The value of \e GM includes the mass of the atmosphere and so strictly only applies above the earth's atmosphere. Near the surface of the earth, the value of \e g will be less (in absolute value) than the value predicted by these models by about δ\e g = (4πG/\e g) \e A = 8.552 × 10−11 \e A m2/kg, where \e G is the gravitational constant, \e g is the earth's gravity, and \e A is the pressure of the atmosphere. At sea level we have \e A = 101.3 kPa, and δ\e g = 8.7 × 10−6 m s−2, approximately. (In other words the effect is about 1 part in a million; by way of comparison, buoyancy effects are about 100 times larger.) \section gravityparallel Geoid heights on a multi-processor system The egm2008 model includes many terms (over 2 million spherical harmonics). For that reason computations using this model may be slow; for example it takes about 78 ms to compute the geoid height at a single point. There are two ways to speed up this computation: - Use a GravityCircle to compute the geoid height at several points on a circle of latitude. This reduces the cost per point to about 92 μs (a reduction by a factor of over 800). - Compute the values on several circles of latitude in parallel. One of the simplest ways of doing this is with OpenMP; on an 8-processor system, this can speed up the computation by another factor of 8. . Both of these techniques are illustrated by the following code, which computes a table of geoid heights on a regular grid and writes on the result in a .gtx file. On an 8-processor Intel 2.66 GHz machine using OpenMP (-DHAVE_OPENMP=1), it takes about 40 minutes of elapsed time to compute the geoid height for EGM2008 on a 1' grid. (Without these optimizations, the computation would have taken about 200 days!) \include GeoidToGTX.cpp cmake will add in support for OpenMP for examples/GeoidToGTX.cpp, if it is available.
Back to \ref geoid. Forward to \ref normalgravity. Up to \ref contents.
**********************************************************************/ /** \page normalgravity Normal gravity
Back to \ref gravity. Forward to \ref magnetic. Up to \ref contents.
The NormalGravity class computes "normal gravity" which refers to the exact (classical) solution of an idealised system consisting of an ellipsoid of revolution with the following properties: - \e M the mass interior to the ellipsoid, - \e a the equatorial radius, - \e b the polar semi-axis, - ω the rotation rate about the polar axis. . (N.B. The mass always appears in the combination \e GM, with units m3/s2, where \e G is the gravtitational constant.) The distribution of the mass \e M within the ellipsoid is such that the surface of the ellipsoid is at a constant normal potential where the normal potential is the sum of the gravitational potential (due to the gravitational attraction) and the centrifugal potential (due to the rotation). The resulting field exterior to the ellipsoid is called normal gravity and was found by Somigliana (1929). Because the potential is constant on the ellipsoid it is sometimes referred to as the level ellipsoid. Go to - \ref normalgravcoords - \ref normalgravpot - \ref normalgravmass - \ref normalgravsurf - \ref normalgravmean - \ref normalgravj2 References: - C. Somigliana, Teoria generale del campo gravitazionale dell'ellissoide di rotazione, Mem. Soc. Astron. Ital, 4, 541--599 (1929). - W. A. Heiskanen and H. Moritz, Physical Geodesy (Freeman, San Francisco, 1967), Secs. 1-19, 2-7, 2-8 (2-9, 2-10), 6-2 (6-3). - B. Hofmann-Wellenhof, H. Moritz, Physical Geodesy (Second edition, Springer, 2006). https://doi.org/10.1007/978-3-211-33545-1 - H. Moritz, Geodetic Reference System 1980, J. Geodesy 54(3), 395--405 (1980). https://doi.org/10.1007/BF02521480 - H. Moritz, The Figure of the Earth (Wichmann, 1990). - M. Chasles, Solution nouvelle du problème de l’attraction d’un ellipsoïde hétérogène sur un point exterieur, Jour. Liouville 5, 465--488 (1840), Note 2. http://sites.mathdoc.fr/JMPA/PDF/JMPA_1840_1_5_A41_0.pdf \section normalgravcoords Ellipsoidal coordinates Two set of formulas are presented: those of Heiskanen and Moritz (1967) which are applicable to an oblate ellipsoid and a second set where the variables are distinguished with primes which apply to a prolate ellipsoid. The primes are omitted from those variables which are the same in the two cases. In the text, the parenthetical "alt." clauses apply to prolate ellipsoids. Cylindrical coordinates \f$ R,Z \f$ are expressed in terms of ellipsoidal coordinates \f[ \begin{align} R &= \sqrt{u^2 + E^2} \cos\beta = u' \cos\beta,\\ Z &= u \sin\beta = \sqrt{u'^2 + E'^2} \sin\beta, \end{align} \f] where \f[ \begin{align} E^2 = a^2 - b^2,&{} \qquad u^2 = u'^2 + E'^2,\\ E'^2 = b^2 - a^2,&{} \qquad u'^2 = u^2 + E^2. \end{align} \f] Surfaces of constant \f$ u \f$ (or \f$ u' \f$) are confocal ellipsoids. The surface \f$ u = 0 \f$ (alt. \f$ u' = 0 \f$) corresponds to the focal disc of diameter \f$ 2E \f$ (alt. focal rod of length \f$ 2E' \f$). The level ellipsoid is given by \f$ u = b \f$ (alt. \f$ u' = a \f$). On the level ellipsoid, \f$ \beta \f$ is the familiar parametric latitude. In writing the potential and the gravity, it is useful to introduce the functions \f[ \begin{align} Q(z) &= \frac1{2z^3} \biggl[\biggl(1 + \frac3{z^2}\biggr)\tan^{-1}z - \frac3z\biggr],\\ Q'(z') &= \frac{(1+z'^2)^{3/2}}{2z'^3} \biggl[\biggl(2 + \frac3{z'^2}\biggr)\sinh^{-1}z' - \frac{3\sqrt{1+z'^2}}{z'}\biggr],\\ H(z) &= \biggl(3Q(z)+z\frac{dQ(z)}{dz}\biggr)(1+z^2)\\ &= \frac1{z^4}\biggl[3(1+z^2) \biggl(1-\frac{\tan^{-1}z}z\biggr)-z^2\biggr],\\ H'(z') &= \frac{3Q'(z')}{1+z'^2}+z'\frac{dQ'(z')}{dz'}\\ &= \frac{1+z'^2}{z'^4} \biggl[3\biggl(1-\frac{\sqrt{1+z'^2}\sinh^{-1}z'}{z'}\biggr) +z'^2\biggr]. \end{align} \f] The function arguments are \f$ z = E/u \f$ (alt. \f$ z' = E'/u' \f$) and the unprimed and primed quantities are related by \f[ \begin{align} Q'(z') = Q(z),&{} \qquad H'(z') = H(z),\\ z'^2 = -\frac{z^2}{1 + z^2},&{} \qquad z^2 = -\frac{z'^2}{1 + z'^2}. \end{align} \f] The functions \f$ q(u) \f$ and \f$ q'(u) \f$ used by Heiskanen and Moritz are given by \f[ q(u) = \frac{E^3}{u^3}Q\biggl(\frac Eu\biggr),\qquad q'(u) = \frac{E^2}{u^2}H\biggl(\frac Eu\biggr). \f] The functions \f$ Q(z) \f$, \f$ Q'(z') \f$, \f$ H(z) \f$, and \f$ H'(z') \f$ are more convenient for use in numerical codes because they are finite in the spherical limit \f$ E \rightarrow 0 \f$, i.e., \f$ Q(0) = Q'(0) = \frac2{15} \f$, and \f$ H(0) = H'(0) = \frac25 \f$. \section normalgravpot The normal potential The normal potential is the sum of three components, a mass term, a quadrupole term and a centrifugal term, \f[ U = U_m + U_q + U_r. \f] The mass term is \f[ U_m = \frac {GM}E \tan^{-1}\frac Eu = \frac {GM}{E'} \sinh^{-1}\frac{E'}{u'}; \f] the quadrupole term is \f[ \begin{align} U_q &= \frac{\omega^2}2 \frac{a^2 b^3}{u^3} \frac{Q(E/u)}{Q(E/b)} \biggl(\sin^2\beta-\frac13\biggr)\\ &= \frac{\omega^2}2 \frac{a^2 b^3}{(u'^2+E'^2)^{3/2}} \frac{Q'(E'/u')}{Q'(E'/a)} \biggl(\sin^2\beta-\frac13\biggr); \end{align} \f] finally, the rotational term is \f[ U_r = \frac{\omega^2}2 R^2 = \frac{\omega^2}2 (u^2 + E^2) \cos^2\beta = \frac{\omega^2}2 u'^2 \cos^2\beta. \f] \f$ U_m \f$ and \f$ U_q \f$ are both gravitational potentials (due to mass within the ellipsoid). The total mass contributing to \f$ U_m \f$ is \f$ M \f$; the total mass contributing to \f$ U_q \f$ vanishes (far from the ellipsoid, the \f$ U_q \f$ decays inversely as the cube of the distance). \f$ U_m \f$ and \f$ U_q + U_r \f$ are separately both constant on the level ellipsoid. \f$ U_m \f$ is the normal potential for a massive non-rotating ellipsoid. \f$ U_q + U_r \f$ is the potential for a massless rotating ellipsoid. Combining all the terms, \f$ U \f$ is the normal potential for a massive rotating ellipsoid. The figure shows normal gravity for the case \f$ GM = 1 \f$, \f$ a = 1 \f$, \f$ b = 0.8 \f$, \f$ \omega = 0.3 \f$. The level ellipsoid is shown in red. Contours of constant gravity potential are shown in blue; the contour spacing is constant outside the ellipsoid and equal to 1/20 of the difference between the potentials on the ellipsoid and at the geostationary point (\f$ R = 2.2536 \f$, \f$ Z = 0 \f$); inside the ellipsoid the contour spacing is 5 times greater. The green lines are stream lines for the gravity; these are spaced at intervals of 10° in parametric latitude on the surface of the ellipsoid. The normal gravity is continued into the level ellipsoid under the assumption that the mass is concentrated on the focal disc, shown in black. \image html normal-gravity-potential-1.svg "Normal gravity" \section normalgravmass The mass distribution Typically, the normal potential, \f$ U \f$, is only of interest for outside the ellipsoid \f$ u \ge b \f$ (alt. \f$ u' \ge a \f$). In planetary applications, an open problem is finding a mass distribution which is in hydrostatic equilibrium (the mass density is non-negative and a non-decreasing function of the potential interior to the ellipsoid). However it is possible to give singular mass distributions consistent with the normal potential. For a non-rotating body, the potential \f$ U = U_m \f$ is generated by a sandwiching the mass \f$ M \f$ uniformly between the level ellipsoid with semi-axes \f$ a \f$ and \f$ b \f$ and a close similar ellipsoid with semi-axes \f$ (1-\epsilon)a \f$ and \f$ (1-\epsilon)b \f$. Chasles (1840) extends a theorem of Newton to show that the field interior to such an ellipsoidal shell vanishes. Thus the potential on the ellipsoid is constant, i.e., it is indeed a level ellipsoid. This result also holds for a non-rotating triaxial ellipsoid. Observing that \f$ U_m \f$ and \f$ U_q \f$ as defined above obey \f$ \nabla^2 U_m = \nabla^2 U_q = 0 \f$ everywhere for \f$ u > 0 \f$ (alt. \f$ u' > 0 \f$), we see that these potentials correspond to masses concentrated at \f$ u = 0 \f$ (alt. \f$ u' = 0 \f$). In the oblate case, \f$ U_m \f$ is generated by a massive disc at \f$ Z = 0 \f$, \f$ R < E \f$, with mass density (mass per unit area) \f$ \rho_m \f$ and moments of inertia about the equatorial (resp. polar) axis of \f$ A_m \f$ (resp. \f$ C_m \f$) given by \f[ \begin{align} \rho_m &= \frac M{2\pi E\sqrt{E^2 - R^2}},\\ A_m &= \frac {ME^2}3, \\ C_m &= \frac {2ME^2}3, \\ C_m-A_m &= \frac {ME^2}3. \end{align} \f] This mass distribution is the same as that produced by projecting a uniform spheric shell of mass \f$ M \f$ and radius \f$ E \f$ onto the equatorial plane. In the prolate case, \f$ U_m \f$ is generated by a massive rod at \f$ R = 0 \f$, \f$ Z < E' \f$ and now the mass density \f$ \rho'_m \f$ has units mass per unit length, \f[ \begin{align} \rho'_m &= \frac M{2E'},\\ A_m &= \frac {ME'^2}3, \\ C_m &= 0, \\ C_m-A_m &= -\frac {ME'^2}3. \end{align} \f] This mass distribution is the same as that produced by projecting a uniform spheric shell of mass \f$ M \f$ and radius \f$ E' \f$ onto the polar axis. Similarly, \f$ U_q \f$ is generated in the oblate case by \f[ \begin{align} \rho_q &= \frac{a^2 b^3 \omega^2}G \frac{2E^2 - 3R^2}{6\pi E^5 \sqrt{E^2 - R^2} Q(E/b)}, \\ A_q &= -\frac{a^2 b^3 \omega^2}G \frac2{45\,Q(E/b)}, \\ C_q &= -\frac{a^2 b^3 \omega^2}G \frac4{45\,Q(E/b)}, \\ C_q-A_q &= -\frac{a^2 b^3 \omega^2}G \frac2{45\,Q(E/b)}. \end{align} \f] The corresponding results for a prolate ellipsoid are \f[ \begin{align} \rho_q' &= \frac{a^2 b^3 \omega^2}G \frac{3Z^2 - E'^2}{12\,E'^5 Q'(E'/a)}, \\ A_q &= \frac{a^2 b^3 \omega^2}G \frac2{45\,Q'(E'/a)}, \\ C_q &= 0, \\ C_q-A_q &= -\frac{a^2 b^3 \omega^2}G \frac2{45\,Q'(E'/a)}. \end{align} \f] Summing up the mass and quadrupole terms, we have \f[ \begin{align} A &= A_m + A_q, \\ C &= C_m + C_q, \\ J_2 & = \frac{C - A}{Ma^2}, \end{align} \f] where \f$ J_2 \f$ is the dynamical form factor. \section normalgravsurf The surface gravity Each term in the potential contributes to the gravity on the surface of the ellipsoid \f[ \gamma = \gamma_m + \gamma_q + \gamma_r; \f] These are the components of gravity normal to the ellipsoid and, by convention, \f$ \gamma \f$ is positive downwards. The tangential components of the total gravity and that due to \f$ U_m \f$ vanish. Those tangential components of the gravity due to \f$ U_q \f$ and \f$ U_r \f$ cancel one another. The gravity \f$ \gamma \f$ has the following dependence on latitude \f[ \begin{align} \gamma &= \frac{b\gamma_a\cos^2\beta + a\gamma_b\sin^2\beta} {\sqrt{b^2\cos^2\beta + a^2\sin^2\beta}}\\ &= \frac{a\gamma_a\cos^2\phi + b\gamma_b\sin^2\phi} {\sqrt{a^2\cos^2\phi + b^2\sin^2\phi}}, \end{align} \f] and the individual components, \f$ \gamma_m \f$, \f$ \gamma_q \f$, and \f$ \gamma_r \f$, have the same dependence on latitude. The equatorial and polar gravities are \f[ \begin{align} \gamma_a &= \gamma_{ma} + \gamma_{qa} + \gamma_{ra},\\ \gamma_b &= \gamma_{mb} + \gamma_{qb} + \gamma_{rb}, \end{align} \f] where \f[ \begin{align} \gamma_{ma} &= \frac{GM}{ab},\qquad \gamma_{mb} = \frac{GM}{a^2},\\ \gamma_{qa} &= -\frac{\omega^2 a}6 \frac{H(E/b)}{Q(E/b)} = -\frac{\omega^2 a}6 \frac{H'(E'/a)}{Q'(E'/a)},\\ \gamma_{qb} &= -\frac{\omega^2 b}3 \frac{H(E/b)}{Q(E/b)} = -\frac{\omega^2 b}3 \frac{H'(E'/a)}{Q'(E'/a)},\\ \gamma_{ra} &= -\omega^2 a,\qquad \gamma_{rb} = 0. \end{align} \f] \section normalgravmean The mean gravity Performing an average of the surface gravity over the area of the ellipsoid gives \f[ \langle \gamma \rangle = \frac {4\pi a^2 b}A \biggl(\frac{2\gamma_a}{3a} + \frac{\gamma_b}{3b}\biggr), \f] where \f$ A \f$ is the area of the ellipsoid \f[ \begin{align} A &= 2\pi\biggl( a^2 + ab\frac{\sinh^{-1}(E/b)}{E/b} \biggr)\\ &= 2\pi\biggl( a^2 + b^2\frac{\tan^{-1}(E'/a)}{E'/a} \biggr). \end{align} \f] The contributions to the mean gravity are \f[ \begin{align} \langle \gamma_m \rangle &= \frac{4\pi}A GM, \\ \langle \gamma_q \rangle &= 0 \quad \text{(as expected)}, \\ \langle \gamma_r \rangle &= -\frac{4\pi}A \frac{2\omega^2 a^2b}3,\\ \end{align} \f] resulting in \f[ \langle \gamma \rangle = \frac{4\pi}A \biggl(GM - \frac{2\omega^2 a^2b}3\biggr). \f] \section normalgravj2 Possible values of the dynamical form factor The solution for the normal gravity is well defined for arbitrary \f$ M \f$, \f$ \omega \f$, \f$ a > 0\f$, and \f$ f < 1 \f$. (Note that arbitrary oblate and prolate ellipsoids are possible, although hydrostatic equilibrium would not result in a prolate ellipsoid.) However, if is much easier to measure the dynamical form factor \f$ J_2 \f$ (from the motion of artificial satellites) than the flattening \f$ f \f$. (Note too that \f$ GM \f$ is also typically measured from from satellite or astronomical observations and so it includes the mass of the atmosphere.) So a question for the software developer is: given values of \f$ M > 0\f$, \f$ \omega \f$, and \f$ a > 0 \f$, what are the allowed values of \f$ J_2 \f$? We restrict the question to \f$ M > 0 \f$. The (unphysical) case \f$ M = 0 \f$ is problematic because \f$ M \f$ appears in the denominator in the definition of \f$ J_2 \f$. In the (also unphysical) case \f$ M < 0 \f$, a given \f$ J_2 \f$ can result from two distinct values of \f$ f \f$. Holding \f$ M > 0\f$, \f$ \omega \f$, and \f$ a > 0 \f$ fixed and varying \f$ f \f$ from \f$ -\infty \f$ to \f$ 1 \f$, we find that \f$ J_2 \f$ monotonically increases from \f$ -\infty \f$ to \f[ \frac13 - \frac8{45\pi} \frac{\omega^2 a^3}{GM}. \f] Thus any value of \f$ J_2 \f$ less that this value is permissible (but some of these values may be unphysical). In obtaining this limiting value, we used the result \f$ Q(z \rightarrow \infty) \rightarrow \pi/(4 z^3) \f$. The value \f[ J_2 = -\frac13 \frac{\omega^2 a^3}{GM} \f] results in a sphere (\f$ f = 0 \f$).
Back to \ref gravity. Forward to \ref magnetic. Up to \ref contents.
**********************************************************************/ /** \page magnetic Magnetic models
Back to \ref normalgravity. Forward to \ref geodesic. Up to \ref contents.
GeographicLib can compute the earth's magnetic field by a magnetic model using the MagneticModel and MagneticCircle classes and with the MagneticField utility. These models expand the internal magnetic potential of the earth as sum of spherical harmonics. They neglect magnetic fields due to the ionosphere, the magnetosphere, nearby magnetized materials, electric machinery, etc. Users of MagneticModel are advised to read the "Health Warning" this is provided with igrf11. Although the advice is specific to igrf11, many of the comments apply to all magnetic field models. The supported models are - wmm2010, the World Magnetic Model 2010, which approximates the main magnetic field for the period 2010--2015. - wmm2015v2, the World Magnetic Model 2015, which approximates the main magnetic field for the period 2015--2020. - wmm2015, a deprecated version of wmm2015v2. - wmm2020, the World Magnetic Model 2020, which approximates the main magnetic field for the period 2020--2025. - igrf11, the International Geomagnetic Reference Field (11th generation), which approximates the main magnetic field for the period 1900--2015. - igrf12, the International Geomagnetic Reference Field (12th generation), which approximates the main magnetic field for the period 1900--2020. - emm2010, the Enhanced Magnetic Model 2010, which approximates the main and crustal magnetic fields for the period 2010--2015. - emm2015, the Enhanced Magnetic Model 2015, which approximates the main and crustal magnetic fields for the period 2000--2020. - emm2017, the Enhanced Magnetic Model 2017, which approximates the main and crustal magnetic fields for the period 2000--2022. Go to - \ref magneticinst - \ref magneticformat \section magneticinst Installing the magnetic field models These magnetic models are available for download:
Available magnetic models
name max\n degree time\n interval size\n(kB)
Download Links (size, kB)
tar file Windows\n installer zip file
wmm2010
12
2010--2015
3
link (2)
link (300)
link (2)
wmm2015
12
2015--2020
3
link (2)
link (300)
link (2)
wmm2015v2
12
2015--2020
3
link (2)
link (300)
link (2)
wmm2020
12
2020--2025
3
link (2)
link (1390)
link (2)
igrf11
13
1900--2015
25
link (7)
link (310)
link (8)
igrf12
13
1900--2020
26
link (7)
link (310)
link (8)
emm2010
739
2010--2015
4400
link (3700)
link (3000)
link (4100)
emm2015
729
2000--2020
4300
link (660)
link (990)
link (1030)
emm2017
790
2000--2022
5050
link (1740)
link (1700)
link (2750)
The "size" column is the size of the uncompressed data. N.B., the wmm2015 model is deprecated; use wmm2015v2 instead. For Linux and Unix systems, GeographicLib provides a shell script geographiclib-get-magnetic (typically installed in /usr/local/sbin) which automates the process of downloading and installing the magnetic models. For example \verbatim geographiclib-get-magnetic all # install all available models geographiclib-get-magnetic -h # for help \endverbatim This script should be run as a user with write access to the installation directory, which is typically /usr/local/share/GeographicLib (this can be overridden with the -p flag), and the data will then be placed in the "magnetic" subdirectory. Windows users should download and run the Windows installers. These will prompt for an installation directory with the default being \verbatim C:/ProgramData/GeographicLib \endverbatim (which you probably should not change) and the data is installed in the "magnetic" sub-directory. (The second directory name is an alternate name that Windows 7 uses for the "Application Data" directory.) Otherwise download \e either the tar.bz2 file \e or the zip file (they have the same contents). To unpack these, run, for example \verbatim mkdir -p /usr/local/share/GeographicLib tar xofjC wmm2020.tar.bz2 /usr/local/share/GeographicLib tar xofjC emm2010.tar.bz2 /usr/local/share/GeographicLib etc. \endverbatim and, again, the data will be placed in the "magnetic" subdirectory. However you install the magnetic models, all the datasets should be installed in the same directory. MagneticModel and MagneticField uses a compile time default to locate the datasets. This is - /usr/local/share/GeographicLib/magnetic, for non-Windows systems - C:/ProgramData/GeographicLib/magnetic, for Windows systems . consistent with the examples above. This may be overridden at run-time by defining the GEOGRAPHICLIB_MAGNETIC_PATH or the GEOGRAPHIC_DATA environment variables; see MagneticModel::DefaultMagneticPath() for details. Finally, the path may be set using the optional second argument to the MagneticModel constructor or with the "-d" flag to MagneticField. Supplying the "-h" flag to MagneticField reports the default path for magnetic models for that utility. The "-v" flag causes MagneticField to report the full path name of the data file it uses. \section magneticformat The format of the magnetic model files The constructor for MagneticModel reads a file called NAME.wmm which specifies various properties for the magnetic model. It then opens a binary file NAME.wmm.cof to obtain the coefficients of the spherical harmonic sum. The first line of the .wmm file must consist of "WMMF-v" where WMMF stands for "World Magnetic Model Format" and v is the version number of the format (currently "2"). The rest of the File is read a line at a time. A # character and everything after it are discarded. If the result is just white space it is discarded. The remaining lines are of the form "KEY WHITESPACE VALUE". In general, the KEY and the VALUE are case-sensitive. MagneticModel only pays attention to the following keywords - keywords that affect the field calculation, namely: - Radius (required), the normalizing radius of the model in meters. - NumModels (default 1), the number of models. WMM2020 consists of a single model giving the magnetic field and its time variation at 2020. IGRF12 consists of 24 models for 1900 thru 2015 at 5 year intervals. The time variation is given only for the last model to allow extrapolation beyond 2015. For dates prior to 2015, linear interpolation is used. - NumConstants (default 0), the number of time-independent terms; this can be 0 or 1. This keyword was introduced in format version 2 (GeographicLib version 1.43) to support the EMM2015 and later models. This model includes long wavelength time-varying components of degree 15. This is supplemented by a short wavelength time-independent component with much higher degree. - Epoch (required), the time origin (in fractional years) for the first model. - DeltaEpoch (default 1), the interval between models in years (only relevant for NumModels > 1). - Normalization (default schmidt), the normalization used for the associated Legendre functions (schmidt or full). - ID (required), 8 printable characters which serve as a signature for the .wmm.cof file (they must appear as the first 8 bytes of this file). - keywords that store data that the user can query: - Name, the name of the model. - Description, a more descriptive name of the model. - ReleaseDate, when the model was created. - MinTime, the minimum date at which the model should be used. - MaxTime, the maximum date at which the model should be used. - MinHeight, the minimum height above the ellipsoid for which the model should be used. - MaxHeight, the maximum height above the ellipsoid for which the model should be used. . MagneticModel does not enforce the restrictions implied by last four quantities. However, MagneticField issues a warning if these limits are exceeded. - keywords that are examined to verify that their values are valid: - Type (default linear), the type of the model. "linear" means that the time variation is piece-wise linear (either using interpolation between the field at two dates or using the field and its first derivative with respect to time). This is the only type of model supported at present. - ByteOrder (default little), the order of bytes in the .wmm.cof file. Only little endian is supported at present. . Other keywords are ignored. The coefficient file NAME.wmm.cof is a binary file in little endian order. The first 8 bytes of this file must match the ID given in NAME.wmm. This is followed by NumModels + 1 sets of spherical harmonic coefficients. The first NumModels of these model the magnetic field at Epoch + \e i * DeltaEpoch for 0 ≤ \e i < NumModels. The last set of coefficients model the rate of change of the magnetic field at Epoch + (NumModels − 1) * DeltaEpoch. The format for each set of coefficients is: - \e N, the maximum degree of the sum stored as a 4-byte signed integer. This must satisfy \e N ≥ −1. - \e M, the maximum order of the sum stored as a 4-byte signed integer. This must satisfy \e N ≥ \e M ≥ −1. - Cnm, the coefficients of the cosine coefficients of the sum in column (i.e., \e m) major order. There are (\e M + 1) (2\e N − \e M + 2) / 2 elements which are stored as IEEE doubles (8 bytes). For example for \e N = \e M = 3, there are 10 coefficients arranged as C00, C10, C20, C30, C11, C21, C31, C22, C32, C33. - Snm, the coefficients of the sine coefficients of the sum in column (i.e., \e m) major order starting at \e m = 1. There are \e M (2\e N − \e M + 1) / 2 elements which are stored as IEEE doubles (8 bytes). For example for \e N = \e M = 3, there are 6 coefficients arranged as S11, S21, S31, S22, S32, S33. . Although the coefficient file is in little endian order, GeographicLib can read it on big endian machines. It can only be read on machines which store doubles in IEEE format. As an illustration, here is igrf11.wmm: \verbatim WMMF-1 # A World Magnetic Model (Format 1) file. For documentation on the # format of this file see # https://geographiclib.sourceforge.io/html/magnetic.html#magneticformat Name igrf11 Description International Geomagnetic Reference Field 11th Generation URL https://ngdc.noaa.gov/IAGA/vmod/igrf.html Publisher National Oceanic and Atmospheric Administration ReleaseDate 2009-12-15 DataCutOff 2009-10-01 ConversionDate 2011-11-04 DataVersion 1 Radius 6371200 NumModels 23 Epoch 1900 DeltaEpoch 5 MinTime 1900 MaxTime 2015 MinHeight -1000 MaxHeight 600000 # The coefficients are stored in a file obtained by appending ".cof" to # the name of this file. The coefficients were obtained from IGRF11.COF # in the geomag70 distribution. ID IGRF11-A \endverbatim
Back to \ref normalgravity. Forward to \ref geodesic. Up to \ref contents.
**********************************************************************/ /** \page geodesic Geodesics on an ellipsoid of revolution
Back to \ref magnetic. Forward to \ref nearest. Up to \ref contents.
Geodesic and GeodesicLine provide accurate solutions to the direct and inverse geodesic problems. The GeodSolve utility provides an interface to these classes. AzimuthalEquidistant implements the azimuthal equidistant projection in terms of geodesics. CassiniSoldner implements a transverse cylindrical equidistant projection in terms of geodesics. The GeodesicProj utility provides an interface to these projections. The algorithms used by Geodesic and GeodesicLine are based on a Taylor expansion of the geodesic integrals valid when the flattening \e f is small. GeodesicExact and GeodesicLineExact evaluate the integrals exactly (in terms of incomplete elliptic integrals). For the WGS84 ellipsoid, the series solutions are about 2--3 times faster and 2--3 times more accurate (because it's easier to control round-off errors with series solutions); thus Geodesic and GeodesicLine are recommended for most geodetic applications. However, in applications where the absolute value of \e f is greater than about 0.02, the exact classes should be used. Go to - \ref testgeod - \ref geodseries - \ref geodellip - \ref meridian - \ref geodshort . For some background information on geodesics on triaxial ellipsoids, see \ref triaxial. References: - F. W. Bessel, The calculation of longitude and latitude from geodesic measurements (1825), Astron. Nachr. 331(8), 852--861 (2010); translated by C. F. F. Karney and R. E. Deakin; preprint: arXiv:0908.1824. - F. R. Helmert, Mathematical and Physical Theories of Higher Geodesy, Part 1 (1880), Aeronautical Chart and Information Center (St. Louis, 1964), Chaps. 5--7. - J. Danielsen, The area under the geodesic, Survey Review 30(232), 61--66 (1989). DOI: 10.1179/003962689791474267 - C. F. F. Karney, Algorithms for geodesics, J. Geodesy 87(1), 43--55 (2013); DOI: 10.1007/s00190-012-0578-z; addenda: geod-addenda.html; resource page: geod.html. - A collection of some papers on geodesics is available at https://geographiclib.sourceforge.io/geodesic-papers/biblio.html - The wikipedia page, Geodesics on an ellipsoid. \section testgeod Test data for geodesics A test set a geodesics is available at - GeodTest.dat.gz - C. F. F. Karney, Test set for geodesics (2010),
DOI: 10.5281/zenodo.32156. . This is about 39 MB (compressed). This consists of a set of geodesics for the WGS84 ellipsoid. A subset of this (consisting of 1/50 of the members — about 690 kB, compressed) is available at - GeodTest-short.dat.gz Each line of the test set gives 10 space delimited numbers - latitude at point 1, \e lat1 (degrees, exact) - longitude at point 1, \e lon1 (degrees, always 0) - azimuth at point 1, \e azi1 (clockwise from north in degrees, exact) - latitude at point 2, \e lat2 (degrees, accurate to 10−18 deg) - longitude at point 2, \e lon2 (degrees, accurate to 10−18 deg) - azimuth at point 2, \e azi2 (degrees, accurate to 10−18 deg) - geodesic distance from point 1 to point 2, \e s12 (meters, exact) - arc distance on the auxiliary sphere, \e a12 (degrees, accurate to 10−18 deg) - reduced length of the geodesic, \e m12 (meters, accurate to 0.1 pm) - the area under the geodesic, \e S12 (m2, accurate to 1 mm2) . These are computed using as direct geodesic calculations with the given \e lat1, \e lon1, \e azi1, and \e s12. The distance \e s12 always corresponds to an arc length \e a12 ≤ 180°, so the given geodesics give the shortest paths from point 1 to point 2. For simplicity and without loss of generality, \e lat1 is chosen in [0°, 90°], \e lon1 is taken to be zero, \e azi1 is chosen in [0°, 180°]. Furthermore, \e lat1 and \e azi1 are taken to be multiples of 10−12 deg and \e s12 is a multiple of 0.1 μm in [0 m, 20003931.4586254 m]. This results in \e lon2 in [0°, 180°] and \e azi2 in [0°, 180°]. The direct calculation uses an expansion of the geodesic equations accurate to f30 (approximately 1 part in 1050) and is computed with with Maxima's bfloats and fpprec set to 100 (so the errors in the data are probably 1/2 of the values quoted above). The contents of the file are as follows: - 100000 entries randomly distributed - 50000 entries which are nearly antipodal - 50000 entries with short distances - 50000 entries with one end near a pole - 50000 entries with both ends near opposite poles - 50000 entries which are nearly meridional - 50000 entries which are nearly equatorial - 50000 entries running between vertices (\e azi1 = \e azi2 = 90°) - 50000 entries ending close to vertices . (a total of 500000 entries). The values for \e s12 for the geodesics running between vertices are truncated to a multiple of 0.1 pm and this is used to determine point 2. This data can be fed to the GeodSolve utility as follows - Direct from point 1: \verbatim gunzip -c GeodTest.dat.gz | cut -d' ' -f1,2,3,7 | ./GeodSolve \endverbatim This should yield columns 4, 5, 6, and 9 of the test set. - Direct from point 2: \verbatim gunzip -c GeodTest.dat.gz | cut -d' ' -f4,5,6,7 | sed "s/ \([^ ]*$\)/ -\1/" | ./GeodSolve \endverbatim (The sed command negates the distance.) This should yield columns 1, 2, and 3, and the negative of column 9 of the test set. - Inverse between points 1 and 2: \verbatim gunzip -c GeodTest.dat.gz | cut -d' ' -f1,2,4,5 | ./GeodSolve -i \endverbatim This should yield columns 3, 6, 7, and 9 of the test set. . Add, e.g., "-p 6", to the call to GeodSolve to change the precision of the output. Adding "-f" causes GeodSolve to print 12 fields specifying the geodesic; these include the 10 fields in the test set plus the geodesic scales \e M12 and \e M21 which are inserted between \e m12 and \e S12. Code for computing arbitrarily accurate geodesics in maxima is available in geodesic.mac (this depends on ellint.mac and uses the series computed by geod.mac). This solve both the direct and inverse geodesic problems and offers the ability to solve the problems either using series expansions (similar to Geodesic) or in terms of elliptic integrals (similar to GeodesicExact). \section geodseries Expansions for geodesics We give here the series expansions for the various geodesic integrals valid to order f10. In this release of the code, we use a 6th-order expansions. This is sufficient to maintain accuracy for doubles for the SRMmax ellipsoid (\e a = 6400 km, \e f = 1/150). However, the preprocessor macro GEOGRAPHICLIB_GEODESIC_ORDER can be used to select an order from 3 thru 8. (If using long doubles, with a 64-bit fraction, the default order is 7.) The series expanded to order f30 are given in geodseries30.html. In the formulas below ^ indicates exponentiation (f^3 = f3) and / indicates real division (3/5 = 0.6). The equations need to be converted to Horner form, but are here left in expanded form so that they can be easily truncated to lower order. These expansions were obtained using the Maxima code, geod.mac. In the expansions below, we have - \f$ \alpha \f$ is the azimuth - \f$ \alpha_0 \f$ is the azimuth at the equator crossing - \f$ \lambda \f$ is the longitude measured from the equator crossing - \f$ \sigma \f$ is the spherical arc length - \f$ \omega = \tan^{-1}(\sin\alpha_0\tan\sigma) \f$ is the spherical longitude - \f$ a \f$ is the equatorial radius - \f$ b \f$ is the polar semi-axis - \f$ f \f$ is the flattening - \f$ e^2 = f(2 - f) \f$ - \f$ e'^2 = e^2/(1-e^2) \f$ - \f$ k^2 = e'^2 \cos^2\alpha_0 = 4 \epsilon / (1 - \epsilon)^2 \f$ - \f$ n = f / (2 - f) \f$ - \f$ c^2 = a^2/2 + b^2/2 (\tanh^{-1}e)/e \f$ - \e ep2 = \f$ e'^2 \f$ - \e k2 = \f$ k^2 \f$ - \e eps = \f$ \epsilon = k^2 / (\sqrt{1 + k^2} + 1)^2\f$ The formula for distance is \f[ \frac sb = I_1(\sigma) \f] where \f[ \begin{align} I_1(\sigma) &= A_1\bigl(\sigma + B_1(\sigma)\bigr) \\ B_1(\sigma) &= \sum_{j=1} C_{1j} \sin 2j\sigma \end{align} \f] and \verbatim A1 = (1 + 1/4 * eps^2 + 1/64 * eps^4 + 1/256 * eps^6 + 25/16384 * eps^8 + 49/65536 * eps^10) / (1 - eps); \endverbatim \verbatim C1[1] = - 1/2 * eps + 3/16 * eps^3 - 1/32 * eps^5 + 19/2048 * eps^7 - 3/4096 * eps^9; C1[2] = - 1/16 * eps^2 + 1/32 * eps^4 - 9/2048 * eps^6 + 7/4096 * eps^8 + 1/65536 * eps^10; C1[3] = - 1/48 * eps^3 + 3/256 * eps^5 - 3/2048 * eps^7 + 17/24576 * eps^9; C1[4] = - 5/512 * eps^4 + 3/512 * eps^6 - 11/16384 * eps^8 + 3/8192 * eps^10; C1[5] = - 7/1280 * eps^5 + 7/2048 * eps^7 - 3/8192 * eps^9; C1[6] = - 7/2048 * eps^6 + 9/4096 * eps^8 - 117/524288 * eps^10; C1[7] = - 33/14336 * eps^7 + 99/65536 * eps^9; C1[8] = - 429/262144 * eps^8 + 143/131072 * eps^10; C1[9] = - 715/589824 * eps^9; C1[10] = - 2431/2621440 * eps^10; \endverbatim The function \f$ \tau(\sigma) = s/(b A_1) = \sigma + B_1(\sigma) \f$ may be inverted by series reversion giving \f[ \sigma(\tau) = \tau + \sum_{j=1} C'_{1j} \sin 2j\sigma \f] where \verbatim C1'[1] = + 1/2 * eps - 9/32 * eps^3 + 205/1536 * eps^5 - 4879/73728 * eps^7 + 9039/327680 * eps^9; C1'[2] = + 5/16 * eps^2 - 37/96 * eps^4 + 1335/4096 * eps^6 - 86171/368640 * eps^8 + 4119073/28311552 * eps^10; C1'[3] = + 29/96 * eps^3 - 75/128 * eps^5 + 2901/4096 * eps^7 - 443327/655360 * eps^9; C1'[4] = + 539/1536 * eps^4 - 2391/2560 * eps^6 + 1082857/737280 * eps^8 - 2722891/1548288 * eps^10; C1'[5] = + 3467/7680 * eps^5 - 28223/18432 * eps^7 + 1361343/458752 * eps^9; C1'[6] = + 38081/61440 * eps^6 - 733437/286720 * eps^8 + 10820079/1835008 * eps^10; C1'[7] = + 459485/516096 * eps^7 - 709743/163840 * eps^9; C1'[8] = + 109167851/82575360 * eps^8 - 550835669/74317824 * eps^10; C1'[9] = + 83141299/41287680 * eps^9; C1'[10] = + 9303339907/2972712960 * eps^10; \endverbatim The reduced length is given by \f[ \begin{align} \frac mb &= \sqrt{1 + k^2 \sin^2\sigma_2} \cos\sigma_1 \sin\sigma_2 \\ &\quad {}-\sqrt{1 + k^2 \sin^2\sigma_1} \sin\sigma_1 \cos\sigma_2 \\ &\quad {}-\cos\sigma_1 \cos\sigma_2 \bigl(J(\sigma_2) - J(\sigma_1)\bigr) \end{align} \f] where \f[ \begin{align} J(\sigma) &= I_1(\sigma) - I_2(\sigma) \\ I_2(\sigma) &= A_2\bigl(\sigma + B_2(\sigma)\bigr) \\ B_2(\sigma) &= \sum_{j=1} C_{2j} \sin 2j\sigma \end{align} \f] \verbatim A2 = (1 - 3/4 * eps^2 - 7/64 * eps^4 - 11/256 * eps^6 - 375/16384 * eps^8 - 931/65536 * eps^10) / (1 + eps); \endverbatim \verbatim C2[1] = + 1/2 * eps + 1/16 * eps^3 + 1/32 * eps^5 + 41/2048 * eps^7 + 59/4096 * eps^9; C2[2] = + 3/16 * eps^2 + 1/32 * eps^4 + 35/2048 * eps^6 + 47/4096 * eps^8 + 557/65536 * eps^10; C2[3] = + 5/48 * eps^3 + 5/256 * eps^5 + 23/2048 * eps^7 + 191/24576 * eps^9; C2[4] = + 35/512 * eps^4 + 7/512 * eps^6 + 133/16384 * eps^8 + 47/8192 * eps^10; C2[5] = + 63/1280 * eps^5 + 21/2048 * eps^7 + 51/8192 * eps^9; C2[6] = + 77/2048 * eps^6 + 33/4096 * eps^8 + 2607/524288 * eps^10; C2[7] = + 429/14336 * eps^7 + 429/65536 * eps^9; C2[8] = + 6435/262144 * eps^8 + 715/131072 * eps^10; C2[9] = + 12155/589824 * eps^9; C2[10] = + 46189/2621440 * eps^10; \endverbatim The longitude is given in terms of the spherical longitude by \f[ \lambda = \omega - f \sin\alpha_0 I_3(\sigma) \f] where \f[ \begin{align} I_3(\sigma) &= A_3\bigl(\sigma + B_3(\sigma)\bigr) \\ B_3(\sigma) &= \sum_{j=1} C_{3j} \sin 2j\sigma \end{align} \f] and \verbatim A3 = 1 - (1/2 - 1/2*n) * eps - (1/4 + 1/8*n - 3/8*n^2) * eps^2 - (1/16 + 3/16*n + 1/16*n^2 - 5/16*n^3) * eps^3 - (3/64 + 1/32*n + 5/32*n^2 + 5/128*n^3 - 35/128*n^4) * eps^4 - (3/128 + 5/128*n + 5/256*n^2 + 35/256*n^3 + 7/256*n^4) * eps^5 - (5/256 + 15/1024*n + 35/1024*n^2 + 7/512*n^3) * eps^6 - (25/2048 + 35/2048*n + 21/2048*n^2) * eps^7 - (175/16384 + 35/4096*n) * eps^8 - 245/32768 * eps^9; \endverbatim \verbatim C3[1] = + (1/4 - 1/4*n) * eps + (1/8 - 1/8*n^2) * eps^2 + (3/64 + 3/64*n - 1/64*n^2 - 5/64*n^3) * eps^3 + (5/128 + 1/64*n + 1/64*n^2 - 1/64*n^3 - 7/128*n^4) * eps^4 + (3/128 + 11/512*n + 3/512*n^2 + 1/256*n^3 - 7/512*n^4) * eps^5 + (21/1024 + 5/512*n + 13/1024*n^2 + 1/512*n^3) * eps^6 + (243/16384 + 189/16384*n + 83/16384*n^2) * eps^7 + (435/32768 + 109/16384*n) * eps^8 + 345/32768 * eps^9; C3[2] = + (1/16 - 3/32*n + 1/32*n^2) * eps^2 + (3/64 - 1/32*n - 3/64*n^2 + 1/32*n^3) * eps^3 + (3/128 + 1/128*n - 9/256*n^2 - 3/128*n^3 + 7/256*n^4) * eps^4 + (5/256 + 1/256*n - 1/128*n^2 - 7/256*n^3 - 3/256*n^4) * eps^5 + (27/2048 + 69/8192*n - 39/8192*n^2 - 47/4096*n^3) * eps^6 + (187/16384 + 39/8192*n + 31/16384*n^2) * eps^7 + (287/32768 + 47/8192*n) * eps^8 + 255/32768 * eps^9; C3[3] = + (5/192 - 3/64*n + 5/192*n^2 - 1/192*n^3) * eps^3 + (3/128 - 5/192*n - 1/64*n^2 + 5/192*n^3 - 1/128*n^4) * eps^4 + (7/512 - 1/384*n - 77/3072*n^2 + 5/3072*n^3 + 65/3072*n^4) * eps^5 + (3/256 - 1/1024*n - 71/6144*n^2 - 47/3072*n^3) * eps^6 + (139/16384 + 143/49152*n - 383/49152*n^2) * eps^7 + (243/32768 + 95/49152*n) * eps^8 + 581/98304 * eps^9; C3[4] = + (7/512 - 7/256*n + 5/256*n^2 - 7/1024*n^3 + 1/1024*n^4) * eps^4 + (7/512 - 5/256*n - 7/2048*n^2 + 9/512*n^3 - 21/2048*n^4) * eps^5 + (9/1024 - 43/8192*n - 129/8192*n^2 + 39/4096*n^3) * eps^6 + (127/16384 - 23/8192*n - 165/16384*n^2) * eps^7 + (193/32768 + 3/8192*n) * eps^8 + 171/32768 * eps^9; C3[5] = + (21/2560 - 9/512*n + 15/1024*n^2 - 7/1024*n^3 + 9/5120*n^4) * eps^5 + (9/1024 - 15/1024*n + 3/2048*n^2 + 57/5120*n^3) * eps^6 + (99/16384 - 91/16384*n - 781/81920*n^2) * eps^7 + (179/32768 - 55/16384*n) * eps^8 + 141/32768 * eps^9; C3[6] = + (11/2048 - 99/8192*n + 275/24576*n^2 - 77/12288*n^3) * eps^6 + (99/16384 - 275/24576*n + 55/16384*n^2) * eps^7 + (143/32768 - 253/49152*n) * eps^8 + 33/8192 * eps^9; C3[7] = + (429/114688 - 143/16384*n + 143/16384*n^2) * eps^7 + (143/32768 - 143/16384*n) * eps^8 + 429/131072 * eps^9; C3[8] = + (715/262144 - 429/65536*n) * eps^8 + 429/131072 * eps^9; C3[9] = + 2431/1179648 * eps^9; \endverbatim The formula for area between the geodesic and the equator is given in Sec. 6 of Algorithms for geodesics in terms of \e S, \f[ S = c^2 \alpha + e^2 a^2 \cos\alpha_0 \sin\alpha_0 I_4(\sigma) \f] where \f[ I_4(\sigma) = \sum_{j=0} C_{4j} \cos(2j+1)\sigma \f] In the paper, this was expanded in \f$ e'^2 \f$ and \f$ k^2 \f$. However, the series converges faster for eccentric ellipsoids if the expansion is in \f$ n \f$ and \f$ \epsilon \f$. The series to order \f$ f^{10} \f$ becomes \verbatim C4[0] = + (2/3 - 4/15*n + 8/105*n^2 + 4/315*n^3 + 16/3465*n^4 + 20/9009*n^5 + 8/6435*n^6 + 28/36465*n^7 + 32/62985*n^8 + 4/11305*n^9) - (1/5 - 16/35*n + 32/105*n^2 - 16/385*n^3 - 64/15015*n^4 - 16/15015*n^5 - 32/85085*n^6 - 112/692835*n^7 - 128/1616615*n^8) * eps - (2/105 + 32/315*n - 1088/3465*n^2 + 1184/5005*n^3 - 128/3465*n^4 - 3232/765765*n^5 - 1856/1616615*n^6 - 6304/14549535*n^7) * eps^2 + (11/315 - 368/3465*n - 32/6435*n^2 + 976/4095*n^3 - 154048/765765*n^4 + 368/11115*n^5 + 5216/1322685*n^6) * eps^3 + (4/1155 + 1088/45045*n - 128/1287*n^2 + 64/3927*n^3 + 2877184/14549535*n^4 - 370112/2078505*n^5) * eps^4 + (97/15015 - 464/45045*n + 4192/153153*n^2 - 88240/969969*n^3 + 31168/1322685*n^4) * eps^5 + (10/9009 + 4192/765765*n - 188096/14549535*n^2 + 23392/855855*n^3) * eps^6 + (193/85085 - 6832/2078505*n + 106976/14549535*n^2) * eps^7 + (632/1322685 + 3456/1616615*n) * eps^8 + 107/101745 * eps^9; C4[1] = + (1/45 - 16/315*n + 32/945*n^2 - 16/3465*n^3 - 64/135135*n^4 - 16/135135*n^5 - 32/765765*n^6 - 112/6235515*n^7 - 128/14549535*n^8) * eps - (2/105 - 64/945*n + 128/1485*n^2 - 1984/45045*n^3 + 256/45045*n^4 + 64/109395*n^5 + 128/855855*n^6 + 2368/43648605*n^7) * eps^2 - (1/105 - 16/2079*n - 5792/135135*n^2 + 3568/45045*n^3 - 103744/2297295*n^4 + 264464/43648605*n^5 + 544/855855*n^6) * eps^3 + (4/1155 - 2944/135135*n + 256/9009*n^2 + 17536/765765*n^3 - 3053056/43648605*n^4 + 1923968/43648605*n^5) * eps^4 + (1/9009 + 16/19305*n - 2656/153153*n^2 + 65072/2078505*n^3 + 526912/43648605*n^4) * eps^5 + (10/9009 - 1472/459459*n + 106112/43648605*n^2 - 204352/14549535*n^3) * eps^6 + (349/2297295 + 28144/43648605*n - 32288/8729721*n^2) * eps^7 + (632/1322685 - 44288/43648605*n) * eps^8 + 43/479655 * eps^9; C4[2] = + (4/525 - 32/1575*n + 64/3465*n^2 - 32/5005*n^3 + 128/225225*n^4 + 32/765765*n^5 + 64/8083075*n^6 + 32/14549535*n^7) * eps^2 - (8/1575 - 128/5775*n + 256/6825*n^2 - 6784/225225*n^3 + 4608/425425*n^4 - 128/124355*n^5 - 5888/72747675*n^6) * eps^3 - (8/1925 - 1856/225225*n - 128/17325*n^2 + 42176/1276275*n^3 - 2434816/72747675*n^4 + 195136/14549535*n^5) * eps^4 + (8/10725 - 128/17325*n + 64256/3828825*n^2 - 128/25935*n^3 - 266752/10392525*n^4) * eps^5 - (4/25025 + 928/3828825*n + 292288/72747675*n^2 - 106528/6613425*n^3) * eps^6 + (464/1276275 - 17152/10392525*n + 83456/72747675*n^2) * eps^7 + (1168/72747675 + 128/1865325*n) * eps^8 + 208/1119195 * eps^9; C4[3] = + (8/2205 - 256/24255*n + 512/45045*n^2 - 256/45045*n^3 + 1024/765765*n^4 - 256/2909907*n^5 - 512/101846745*n^6) * eps^3 - (16/8085 - 1024/105105*n + 2048/105105*n^2 - 1024/51051*n^3 + 4096/373065*n^4 - 1024/357357*n^5) * eps^4 - (136/63063 - 256/45045*n + 512/1072071*n^2 + 494336/33948915*n^3 - 44032/1996995*n^4) * eps^5 + (64/315315 - 16384/5360355*n + 966656/101846745*n^2 - 868352/101846745*n^3) * eps^6 - (16/97461 + 14848/101846745*n + 74752/101846745*n^2) * eps^7 + (5024/33948915 - 96256/101846745*n) * eps^8 - 1744/101846745 * eps^9; C4[4] = + (64/31185 - 512/81081*n + 1024/135135*n^2 - 512/109395*n^3 + 2048/1247103*n^4 - 2560/8729721*n^5) * eps^4 - (128/135135 - 2048/405405*n + 77824/6891885*n^2 - 198656/14549535*n^3 + 8192/855855*n^4) * eps^5 - (512/405405 - 2048/530145*n + 299008/130945815*n^2 + 280576/43648605*n^3) * eps^6 + (128/2297295 - 2048/1438965*n + 241664/43648605*n^2) * eps^7 - (17536/130945815 + 1024/43648605*n) * eps^8 + 2944/43648605 * eps^9; C4[5] = + (128/99099 - 2048/495495*n + 4096/765765*n^2 - 6144/1616615*n^3 + 8192/4849845*n^4) * eps^5 - (256/495495 - 8192/2807805*n + 376832/53348295*n^2 - 8192/855855*n^3) * eps^6 - (6784/8423415 - 432128/160044885*n + 397312/160044885*n^2) * eps^7 + (512/53348295 - 16384/22863555*n) * eps^8 - 16768/160044885 * eps^9; C4[6] = + (512/585585 - 4096/1422135*n + 8192/2078505*n^2 - 4096/1322685*n^3) * eps^6 - (1024/3318315 - 16384/9006855*n + 98304/21015995*n^2) * eps^7 - (103424/189143955 - 8192/4203199*n) * eps^8 - 1024/189143955 * eps^9; C4[7] = + (1024/1640925 - 65536/31177575*n + 131072/43648605*n^2) * eps^7 - (2048/10392525 - 262144/218243025*n) * eps^8 - 84992/218243025 * eps^9; C4[8] = + (16384/35334585 - 131072/82447365*n) * eps^8 - 32768/247342095 * eps^9; C4[9] = + 32768/92147055 * eps^9; \endverbatim \section geodellip Geodesics in terms of elliptic integrals GeodesicExact and GeodesicLineExact solve the geodesic problem using elliptic integrals. The formulation of geodesic in terms of incomplete elliptic integrals is given in - C. F. F. Karney, Geodesics on an ellipsoid of revolution, Feb. 2011; preprint arxiv:1102.1215v1. . It is most convenient to use the form derived for a prolate ellipsoid in Appendix D. For an oblate ellipsoid this results in elliptic integrals with an imaginary modulus. However, the integrals themselves are real and the algorithms used to compute the elliptic integrals handles the case of an imaginary modulus using real arithmetic. The key relations used by GeographicLib are \f[ \begin{align} \frac sb &= E(\sigma, ik), \\ \lambda &= (1 - f) \sin\alpha_0 G(\sigma, \cos^2\alpha_0, ik) \\ &= \chi - \frac{e'^2}{\sqrt{1+e'^2}}\sin\alpha_0 H(\sigma, -e'^2, ik), \\ J(\sigma) &= k^2 D(\sigma, ik), \end{align} \f] where \f$ \chi \f$ is a modified spherical longitude given by \f[ \tan\chi = \sqrt{\frac{1+e'^2}{1+k^2\sin^2\sigma}}\tan\omega, \f] and \f[ \begin{align} D(\phi,k) &= \int_0^\phi \frac{\sin^2\theta}{\sqrt{1 - k^2\sin^2\theta}}\,d\theta\\ &=\frac{F(\phi, k) - E(\phi, k)}{k^2},\\ G(\phi,\alpha^2,k) &= \int_0^\phi \frac{\sqrt{1 - k^2\sin^2\theta}}{1 - \alpha^2\sin^2\theta}\,d\theta\\ &=\frac{k^2}{\alpha^2}F(\phi, k) +\biggl(1-\frac{k^2}{\alpha^2}\biggr)\Pi(\phi, \alpha^2, k),\\ H(\phi, \alpha^2, k) &= \int_0^\phi \frac{\cos^2\theta}{(1-\alpha^2\sin^2\theta)\sqrt{1-k^2\sin^2\theta}} \,d\theta \\ &= \frac1{\alpha^2} F(\phi, k) + \biggl(1 - \frac1{\alpha^2}\biggr) \Pi(\phi, \alpha^2, k), \end{align} \f] and \f$F(\phi, k)\f$, \f$E(\phi, k)\f$, \f$D(\phi, k)\f$, and \f$\Pi(\phi, \alpha^2, k)\f$, are incomplete elliptic integrals (see https://dlmf.nist.gov/19.2.ii). The formula for \f$ s \f$ and the first expression for \f$ \lambda \f$ are given by Legendre (1811) and are the most common representation of geodesics in terms of elliptic integrals. The second (equivalent) expression for \f$ \lambda \f$, which was given by Cayley (1870), is useful in that the elliptic integral is relegated to a small correction term. This form allows the longitude to be computed more accurately and is used in GeographicLib. (The equivalence of the two expressions for \f$ \lambda \f$ follows from https://dlmf.nist.gov/19.7.E8.) Nominally, GeodesicExact and GeodesicLineExact will give "exact" results for any value of the flattening. However, the geographic latitude is a distorted measure of distance from the equator with very eccentric ellipsoids and this introducing an irreducible representational error in the algorithms in this case. It is therefore recommended to restrict the use of these classes to b/\e a ∈ [0.01, 100] or \e f ∈ [−99, 0.99]. Note that GeodesicExact still uses a series expansion for the area \e S12. However the series is taken out to 30th order and gives accurate results for b/\e a ∈ [1/2, 2]; the accuracy is about 8 decimal digits for b/\e a ∈ [1/4, 4]. Additional work planned for this aspect of the geodesic problem: - formulate the area integral \e S12 in terms of elliptic integrals; - generate accurate test geodesics for highly eccentric ellipsoids so that the roundoff errors can be quantified. Thomas (1952) and Rollins (2010) use a different independent variable for geodesics, \f$\theta\f$ instead of \f$\sigma\f$, where \f$ \tan\theta = \sqrt{1 + k^2} \tan\sigma \f$. The corresponding expressions for \f$ s \f$ and \f$ \lambda \f$ are given here for completeness: \f[ \begin{align} \frac sb &= \sqrt{1-k'^2} \Pi(\theta, k'^2, k'), \\ \lambda &= (1-f) \sqrt{1-k'^2} \sin\alpha_0 \Pi(\theta, k'^2/e^2, k'), \end{align} \f] where \f$ k' = k/\sqrt{1 + k^2} \f$. The expression for \f$ s \f$ can be written in terms of elliptic integrals of the second kind and Cayley's technique can be used to subtract out the leading order behavior of \f$ \lambda \f$ to give \f[ \begin{align} \frac sb &=\frac1{\sqrt{1-k'^2}} \biggl( E(\theta, k') - \frac{k'^2 \sin\theta \cos\theta}{\sqrt{1-k'^2\sin^2\theta}} \biggr), \\ \lambda &= \psi + (1-f) \sqrt{1-k'^2} \sin\alpha_0 \bigl( F(\theta, k') - \Pi(\theta, e^2, k') \bigr), \end{align} \f] where \f[ \begin{align} \tan\psi &= \sqrt{\frac{1+k^2\sin^2\sigma}{1+e'^2}}\tan\omega \\ &= \sqrt{\frac{1-e^2}{1+k^2\cos^2\theta}}\sin\alpha_0\tan\theta. \end{align} \f] The tangents of the three "longitude-like" angles are in geometric progression, \f$ \tan\chi/\tan\omega = \tan\omega/\tan\psi \f$. \section meridian Parameters for the meridian The formulas for \f$ s \f$ given in the previous section are the same as those for the distance along a meridian for an ellipsoid with equatorial radius \f$ a \sqrt{1 - e^2 \sin^2\alpha_0} \f$ and polar semi-axis \f$ b \f$. Here is a list of possible ways of expressing the meridian distance in terms of elliptic integrals using the notation: - \f$ a \f$, equatorial axis, - \f$ b \f$, polar axis, - \f$ e = \sqrt{(a^2 - b^2)/a^2} \f$, eccentricity, - \f$ e' = \sqrt{(a^2 - b^2)/b^2} \f$, second eccentricity, - \f$ \phi = \mathrm{am}(u, e) \f$, the geographic latitude, - \f$ \phi' = \mathrm{am}(v', ie') = \pi/2 - \phi \f$, the geographic colatitude, - \f$ \beta = \mathrm{am}(v, ie') \f$, the parametric latitude (\f$ \tan^2\beta = (1 - e^2) \tan^2\phi \f$), - \f$ \beta' = \mathrm{am}(u', e) = \pi/2 - \beta \f$, the parametric colatitude, - \f$ M \f$, the length of a quarter meridian (equator to pole), - \f$ y \f$, the distance along the meridian (measured from the equator). - \f$ y' = M -y \f$, the distance along the meridian (measured from the pole). . The eccentricities \f$ (e, e') \f$ are real (resp. imaginary) for oblate (resp. prolate) ellipsoids. The elliptic variables \f$(u, u')\f$ and \f$(v, v')\f$ are defined by - \f$ u = F(\phi, e) ,\quad u' = F(\beta', e) \f$ - \f$ v = F(\beta, ie') ,\quad v' = F(\phi', ie') \f$, . and are linearly related by - \f$ u + u' = K(e) ,\quad v + v' = K(ie') \f$ - \f$ v = \sqrt{1-e^2} u ,\quad u = \sqrt{1+e'^2} v \f$. . The cartesian coordinates for the meridian \f$ (x, z) \f$ are given by \f[ \begin{align} x &= a \cos\beta = a \cos\phi / \sqrt{1 - e^2 \sin^2\phi} \\ &= a \sin\beta' = (a^2/b) \sin\phi' / \sqrt{1 + e'^2 \sin^2\phi'} \\ &= a \,\mathrm{cn}(v, ie) = a \,\mathrm{cd}(u, e) \\ &= a \,\mathrm{sn}(u', e) = (a^2/b) \,\mathrm{sd}(v', ie'), \end{align} \f] \f[ \begin{align} z &= b \sin\beta = (b^2/a) \sin\phi / \sqrt{1 - e^2 \sin^2\phi} \\ &= b \cos\beta' = b \cos\phi' / \sqrt{1 + e'^2 \sin^2\phi'} \\ &= b \,\mathrm{sn}(v, ie) = (b^2/a) \,\mathrm{sd}(u, e) \\ &= b \,\mathrm{cn}(u', e) = b \,\mathrm{cd}(v', ie'). \end{align} \f] The distance along the meridian can be expressed variously as \f[ \begin{align} y &= b \int \sqrt{1 + e'^2 \sin^2\beta}\, d\beta = b E(\beta, ie') \\ &= \frac{b^2}a \int \frac1{(1 - e^2 \sin^2\phi)^{3/2}}\, d\phi = \frac{b^2}a \Pi(\phi, e^2, e) \\ &= a \biggl(E(\phi, e) - \frac{e^2\sin\phi \cos\phi}{\sqrt{1 - e^2\sin^2\phi}}\biggr) \\ &= b \int \mathrm{dn}^2(v, ie')\, dv = \frac{b^2}a \int \mathrm{nd}^2(u, e)\, du = \cal E(v, ie'), \end{align} \f] \f[ \begin{align} y' &= a \int \sqrt{1 - e^2 \sin^2\beta'}\, d\beta' = a E(\beta', e) \\ &= \frac{a^2}b \int \frac1{(1 + e'^2 \sin^2\phi')^{3/2}}\, d\phi' = \frac{a^2}b \Pi(\phi', -e'^2, ie') \\ &= b \biggl(E(\phi', ie') + \frac{e'^2\sin\phi' \cos\phi'}{\sqrt{1 + e'^2\sin^2\phi'}}\biggr) \\ &= a \int \mathrm{dn}^2(u', e)\, du' = \frac{a^2}b \int \mathrm{nd}^2(v', ie')\, dv' = \cal E(u', e), \end{align} \f] with the quarter meridian distance given by \f[ M = aE(e) = bE(ie') = (b^2/a)\Pi(e^2,e) = (a^2/b)\Pi(-e'^2,ie'). \f] (Here \f$ E, F, \Pi \f$ are elliptic integrals defined in https://dlmf.nist.gov/19.2.ii. \f$ \cal E, \mathrm{am}, \mathrm{sn}, \mathrm{cn}, \mathrm{sd}, \mathrm{cd}, \mathrm{dn}, \mathrm{nd} \f$ are Jacobi elliptic functions defined in https://dlmf.nist.gov/22.2 and https://dlmf.nist.gov/22.16.) There are several considerations in the choice of independent variable for evaluate the meridian distance - The use of an imaginary modulus (namely, \f$ ie' \f$, above) is of no practical concern. The integrals are real in this case and modern methods (GeographicLib uses the method given in https://dlmf.nist.gov/19.36.i) for computing integrals handles this case using just real arithmetic. - If the "natural" origin is the equator, choose one of \f$ \phi, \beta, u, v \f$ (this might be preferred in geodesy). If it's the pole, choose one of the complementary quantities \f$ \phi', \beta', u', v' \f$ (this might be preferred by mathematicians). - Applying these formulas to the geodesic problems, \f$ \beta \f$ becomes the arc length, \f$ \sigma \f$, on the auxiliary sphere. This is the traditional method of solution used by Legendre (1806), Oriani (1806), Bessel (1825), Helmert (1880), Rainsford (1955), Thomas (1970), Vincenty (1975), Rapp (1993), and so on. Many of the solutions in terms of elliptic functions use one of the elliptic variables (\f$ u \f$ or \f$ v \f$), see, for example, Jacobi (1855), Halphen (1888), Forsyth (1896). In the context of geodesics \f$ \phi \f$ becomes Thomas' variable \f$ \theta \f$; this is used by Thomas (1952) and Rollins (2010) in their formulation of the geodesic problem (see the previous section). - For highly eccentric ellipsoids the variation of the meridian with respect to \f$ \beta \f$ is considerably "better behaved" than other choices (see the figure below). The choice of \f$ \phi \f$ is probably a poor one in this case. . GeographicLib uses the geodesic generalization of \f$ y = b E(\beta, ie') \f$, namely \f$ s = b E(\sigma, ik) \f$. See \ref geodellip. \image html meridian-measures.png "Comparison of meridian measures" \section geodshort Short geodesics Here we describe Bowring's method for solving the inverse geodesic problem in the limit of short geodesics and contrast it with the great circle solution using Bessel's auxiliary sphere. References: - B. R. Bowring, The Direct and Inverse Problems for Short Geodesic Lines on the Ellipsoid, Surveying and Mapping 41(2), 135--141 (1981). - R. H. Rapp, Geometric Geodesy, Part I, Ohio State Univ. (1991), Sec. 6.5. Bowring considers the conformal mapping of the ellipsoid to a sphere of radius \f$ R \f$ such that circles of latitude and meridians are preserved (and hence the azimuth of a line is preserved). Let \f$ (\phi, \lambda) \f$ and \f$ (\phi', \lambda') \f$ be the latitude and longitude on the ellipsoid and sphere respectively. Define isometric latitudes for the sphere and the ellipsoid as \f[ \begin{align} \psi' &= \sinh^{-1} \tan \phi', \\ \psi &= \sinh^{-1} \tan \phi - e \tanh^{-1}(e \sin\phi). \end{align} \f] The most general conformal mapping satisfying Bowring's conditions is \f[ \psi' = A \psi + K, \quad \lambda' = A \lambda, \f] where \f$ A \f$ and \f$ K \f$ are constants. (In fact a constant can be added to the equation for \f$ \lambda' \f$, but this does affect the analysis.) The scale of this mapping is \f[ m(\phi) = \frac{AR}{\nu}\frac{\cos\phi'}{\cos\phi}, \f] where \f$ \nu = a/\sqrt{1 - e^2\sin^2\phi} \f$ is the transverse radius of curvature. (Note that in Bowring's Eq. (10), \f$ \phi \f$ should be replaced by \f$ \phi' \f$.) The mapping from the ellipsoid to the sphere depends on three parameters \f$ R, A, K \f$. These will be selected to satisfy certain conditions at some representative latitude \f$ \phi_0 \f$. Two possible choices are given below. \subsection bowring Bowring's method Bowring (1981) requires that \f[ m(\phi_0) = 1,\quad \left.\frac{dm(\phi)}{d\phi}\right|_{\phi=\phi_0} = 0,\quad \left.\frac{d^2m(\phi)}{d\phi^2}\right|_{\phi=\phi_0} = 0, \f] i.e, \f$m\approx 1\f$ in the vicinity of \f$\phi = \phi_0\f$. This gives \f[ \begin{align} R &= \frac{\sqrt{1 + e'^2}}{B^2} a, \\ A &= \sqrt{1 + e'^2 \cos^4\phi_0}, \\ \tan\phi'_0 &= \frac1B \tan\phi_0, \end{align} \f] where \f$ e' = e/\sqrt{1-e^2} \f$ is the second eccentricity, \f$ B = \sqrt{1+e'^2\cos^2\phi_0} \f$, and \f$ K \f$ is defined implicitly by the equation for \f$\phi'_0\f$. The radius \f$ R \f$ is the (Gaussian) mean radius of curvature of the ellipsoid at \f$\phi_0\f$ (so near \f$\phi_0\f$ the ellipsoid can be deformed to fit the sphere snugly). The third derivative of \f$ m \f$ is given by \f[ \left.\frac{d^3m(\phi)}{d\phi^3}\right|_{\phi=\phi_0} = \frac{-2e'^2\sin2\phi_0}{B^4}. \f] The method for solving the inverse problem between two nearby points \f$ (\phi_1, \lambda_1) \f$ and \f$ (\phi_2, \lambda_2) \f$ is as follows: Set \f$\phi_0 = (\phi_1 + \phi_2)/2\f$. Compute \f$ R, A, \phi'_0 \f$, and hence find \f$ (\phi'_1, \lambda'_1) \f$ and \f$ (\phi'_2, \lambda'_2) \f$. Finally, solve for the great circle on a sphere of radius \f$ R \f$; the resulting distance and azimuths are good approximations for the corresponding quantities for the ellipsoidal geodesic. Consistent with the accuracy of this method, we can compute \f$\phi'_1\f$ and \f$\phi'_2\f$ using a Taylor expansion about \f$\phi_0\f$. This also avoids numerical errors that arise from subtracting nearly equal quantities when using the equation for \f$\phi'\f$ directly. Write \f$\Delta \phi = \phi - \phi_0\f$ and \f$\Delta \phi' = \phi' - \phi'_0\f$; then we have \f[ \Delta\phi' \approx \frac{\Delta\phi}B \biggl[1 + \frac{\Delta\phi}{B^2}\frac{e'^2}2 \biggl(3\sin\phi_0\cos\phi_0 + \frac{\Delta\phi}{B^2} \bigl(B^2 - \sin^2\phi_0(2 - 3 e'^2 \cos^2\phi_0)\bigr)\biggr)\biggr], \f] where the error is \f$O(f\Delta\phi^4)\f$. This is essentially Bowring's method. Significant differences between this result, "Bowring (improved)", compared to Bowring's paper, "Bowring (original)", are: - Bowring elects to use \f$\phi_0 = \phi_1\f$. This simplifies the calculations somewhat but increases the error by about a factor of 4. - Bowring's expression for \f$ \Delta\phi' \f$ is only accurate in the limit \f$ e' \rightarrow 0 \f$. . In fact, arguably, the highest order \f$O(f\Delta\phi^3)\f$ terms should be dropped altogether. Their inclusion does result in a better estimate for the distance. However, if your goal is to generate both accurate distances \e and accurate azimuths, then \f$\Delta\phi\f$ needs to be restricted sufficiently to allow these terms to be dropped to give the "Bowring (truncated)" method. With highly eccentric ellipsoids, the parametric latitude \f$ \beta \f$ is a better behaved independent variable to use. In this case, \f$ \phi_0 \f$ is naturally defined using \f$\beta_0 = (\beta_1 + \beta_2)/2\f$ and in terms of \f$\Delta\beta = \beta - \beta_0\f$, we have \f[ \Delta\phi' \approx \frac{\Delta\beta}{B'} \biggl[1 + \frac{\Delta\beta}{B'^2}\frac{e'^2}2 \biggl(\sin\beta_0\cos\beta_0 + \frac{\Delta\beta}{3B'^2} \bigl( \cos^2\beta_0 - \sin^2\beta_0 B'^2\bigr) \biggr)\biggr], \f] where \f$B' = \sqrt{1+e'^2\sin^2\beta_0} = \sqrt{1+e'^2}/B\f$, and the error once again is \f$O(f\Delta\phi^4)\f$. This is the "Bowring (using \f$\beta\f$)" method. \subsection auxsphere Bessel's auxiliary sphere GeographicLib's uses the auxiliary sphere method of Legendre, Bessel, and Helmert. For short geodesics, this is equivalent to picking \f$ R, A, K \f$ so that \f[ m(\phi_0) = 1,\quad \left.\frac{dm(\phi)}{d\phi}\right|_{\phi=\phi_0} = 0,\quad \tan\phi'_0 = (1 - f) \tan\phi_0. \f] Bowring's requirement that the second derivative of \f$m\f$ vanish has been replaced by the last relation which states that \f$\phi'_0 = \beta_0\f$, the parametric latitude corresponding to \f$\phi_0\f$. This gives \f[ \begin{align} R &= B'(1-f)a, \\ A &= \frac1{B'(1-f)}, \\ \left.\frac{d^2m(\phi)}{d\phi^2}\right|_{\phi=\phi_0} &= -e^2B'^2\sin^2\phi_0. \end{align} \f] Similar to Bowring's method, we can compute \f$\phi'_1\f$ and \f$\phi'_2\f$ using a Taylor expansion about \f$\beta_0\f$. This results in the simple expression \f[ \Delta\phi' \approx \Delta\beta, \f] where the error is \f$O(f\Delta\beta^2)\f$. \subsection shorterr Estimating the accuracy In assessing the accuracy of these methods we use two metrics: - The absolute error in the distance. - The consistency of the predicted azimuths. Imagine starting ellipsoidal geodesics at \f$ (\phi_1, \lambda_1) \f$ and \f$ (\phi_2, \lambda_2) \f$ with the predicted azimuths. What is the distance between them when they are extended a distance \f$ a \f$ beyond the second point? . (The second metric is much more stringent.) We may now compare the methods by asking for a bound to the length of a geodesic which ensures that the one or other of the errors fall below 1 mm (an "engineering" definition of accurate) or 1 nm (1 nanometer, about the round-off limit).
Maximum distance that can be used in various methods for computing short geodesics while keeping the errors within prescribed bounds
method
distance metric
azimuth metric
1 mm error 1 nm error 1 mm error 1 nm error
Bowring (original)
87 km
870 m
35 km
350 m
Bowring (improved)
180 km
1.8 km
58 km
580 m
Bowring (truncated)
52 km
520 m
52 km
520 m
Bowring (using \f$\beta\f$)
380 km
24 km
60 km
600 m
Bessel's aux. sphere
42 km
420 m
1.7 km
1.7 m
For example, if you're only interested in measuring distances and an accuracy of 1 mm is sufficient, then Bowring's improved method can be used for distances up to 180 km. On the other hand, GeographicLib uses Bessel's auxiliary sphere and we require both the distance and the azimuth to be accurate, so the great circle approximation can only be used for distances less than 1.7 m. The reason that GeographicLib does not use Bowring's method is that the information necessary for auxiliary sphere method is already available as part of the general solution and, as much as possible, we allow all geodesics to be computed by the general method.
Back to \ref magnetic. Forward to \ref nearest. Up to \ref contents.
**********************************************************************/ /** \page nearest Finding nearest neighbors
Back to \ref geodesic. Forward to \ref triaxial. Up to \ref contents.
The problem of finding the maritime boundary defined by the "median line" is discussed in Section 14 of - C. F. F. Karney, Geodesics on an ellipsoid of revolution, Feb. 2011; preprint arxiv:1102.1215v1. . Figure 14 shows the median line which is equidistant from Britain and mainland Europe. Determining the median line involves finding, for any given \e P, the closest points on the coast of Britain and on the coast of mainland Europe. The operation of finding the closest in a set of points is usually referred to as the nearest neighbor problem and the NearestNeighbor class implements an efficient algorithm for solving it. The NearestNeighbor class implements nearest-neighbor calculations using the vantage-point tree described by - J. K. Uhlmann, Satisfying general proximity/similarity queries with metric trees, Information Processing Letters 40 175--179 (1991). - P. N. Yianilos, Data structures and algorithms for nearest neighbor search in general metric spaces, Proc. 4th ACM-SIAM Symposium on Discrete Algorithms, (SIAM, 1993). pp. 311--321. Given a set of points \e x, \e y, \e z, …, in some space and a distance function \e d satisfying the metric conditions, \f[ \begin{align} d(x,y) &\ge 0,\\ d(x,y) &= 0, \ \text{iff $x = y$},\\ d(x,y) &= d(y,x),\\ d(x,z) &\le d(x,y) + d(y,z), \end{align} \f] the vantage-point (VP) tree provides an efficient way of determining nearest neighbors. The geodesic distance (implemented by the Geodesic class) satisfies these metric conditions, while the great ellipse distance and the rhumb line distance do not (they do not satisfy the last condition, the triangle inequality). Typically the cost of constructing a VP tree of \e N points is \e N log \e N, while the cost of a query is log \e N. Thus a VP tree should be used in situations where \e N is large and at least log \e N queries are to be made. The condition, \e N is large, means that \f$ N \gg 2^D \f$, where \e D is the dimensionality of the space. - This implementation includes Yianilos' upper and lower bounds for the inside and outside sets. This helps limit the number of searches (compared to just using the median distance). - Rather than do a depth-first or breath-first search on the tree, the nodes to be processed are put on a priority queue with the nodes most likely to contain close points processed first. Frequently, this allows nodes lower down on the priority queue to be skipped. - This technique also allows non-exhaustive searchs to be performed (to answer questions such as "are there any points within 1km of the query point?). - When building the tree, the first vantage point is (arbitrarily) chosen as the middle element of the set. Thereafter, the points furthest from the parent vantage point in both the inside and outside sets are selected as the children's vantage points. This information is already available from the computation of the upper and lower bounds of the children. This choice seems to lead to a reasonably optimized tree. - The leaf nodes can contain a bucket of points (instead of just a vantage point). - Coincident points are allowed in the set; these are treated as distinct points. The figure below shows the construction of the VP tree for the points making up the coastlines of Britain and Ireland (about 5000 points shown in blue). The set of points is recursively split into 2 equal "inside" and "outside" subsets based on the distance from a "vantage point". The boundaries between the inside and outside sets are shown as green circular arcs (arcs of geodesic circles). At each stage, the newly added vantage points are shown as red dots and the vantage points for the next stage are shown as red plus signs. The data is shown in the Cassini-Soldner projection with a central meridian of 5°W. \image html vptree.gif "Vantage-point tree"
Back to \ref geodesic. Forward to \ref triaxial. Up to \ref contents.
**********************************************************************/ /** \page triaxial Geodesics on a triaxial ellipsoid
Back to \ref nearest. Forward to \ref jacobi. Up to \ref contents.
Jacobi (1839) showed that the problem of geodesics on a triaxial ellipsoid (with 3 unequal axes) can be reduced to quadrature. Despite this, the detailed behavior of the geodesics is not very well known. In this section, I briefly give Jacobi's solution and illustrate the behavior of the geodesics and outline an algorithm for the solution of the inverse problem. See also - The wikipedia page, Geodesics on a triaxial ellipsoid. Go to - \ref triaxial-coords - \ref triaxial-jacobi - \ref triaxial-survey - \ref triaxial-stab - \ref triaxial-inverse NOTES -# A triaxial ellipsoid approximates the earth only slightly better than an ellipsoid of revolution. If you are really considering measuring distances on the earth using a triaxial ellipsoid, you should also be worrying about the shape of the geoid, which essentially makes the geodesic problem a hopeless mess; see, for example, Waters (2011). -# There is nothing new in this section. It is just an exercise in exploring Jacobi's solution. My interest here is in generating long geodesics with the correct long-time behavior. Arnold gives a nice qualitative description of the solution in Mathematical Methods of Classical Mechanics (2nd edition, Springer, 1989), pp. 264--266. -# Possible reasons this problem might, nevertheless, be of interest are: - It is the first example of a dynamical system which has a non-trivial constant of motion. As such, Jacobi's paper generated a lot of excitement and was followed by many papers elaborating his solution. In particular, the unstable behavior of one of the closed geodesics of the ellipsoid, is an early example of a system with a positive Lyapunov exponent (one of the essential ingredients for chaotic behavior in dynamical systems). - Knowledge of ellipsoidal coordinates (used by Jacobi) might be useful in other areas of geodesy. - Geodesics which pass through the pole on an ellipsoid of revolution represent a degenerate class (they are all closed and all pass through the opposite pole). It is of interest to see how this degeneracy is broken with a surface with a more general shape. - Similarly, it is of interest to see how the Mercator projection of the ellipsoid generalizes; this is another problem addressed by Jacobi. -# My interest in this problem was piqued by Jean-Marc Baillard. I put him onto Jacobi's solution without having looked at it in detail myself; and he quickly implemented the solution for an HP-41 calculator(!) which is posted here. -# I do not give full citations of the papers here. You can find these in the Geodesic Bibliography; this includes links to online versions of the papers. -# An alternative to exploring geodesics using Jacobi's solution is to integrate the equations for the geodesics directly. This is the approach taken by Oliver Knill and Michael Teodorescu. However it is difficult to ensure that the long time behavior is correctly modeled with such an approach. -# At this point, I have no plans to add the solution of triaxial geodesic problem to GeographicLib. -# If you only want to learn about geodesics on a biaxial ellipsoid (an ellipsoid of revolution), then see \ref geodesic or the paper - C. F. F. Karney, Algorithms for geodesics, J. Geodesy 87(1), 43--55 (2013); DOI: 10.1007/s00190-012-0578-z; addenda: geod-addenda.html. \section triaxial-coords Triaxial coordinate systems Consider the ellipsoid defined by \f[ f = \frac{X^2}{a^2} + \frac{Y^2}{b^2} + \frac{Z^2}{c^2} = 1, \f] where, without loss of generality, \f$ a \ge b \ge c \gt 0\f$. A point on the surface is specified by a latitude and longitude. The \e geographical latitude and longitude \f$(\phi, \lambda)\f$ are defined by \f[ \frac{\nabla f}{\left| \nabla f\right|} = \left( \begin{array}{c} \cos\phi \cos\lambda \\ \cos\phi \sin\lambda \\ \sin\phi \end{array}\right). \f] The \e parametric latitude and longitude \f$(\phi', \lambda')\f$ are defined by \f[ \begin{align} X &= a \cos\phi' \cos\lambda', \\ Y &= b \cos\phi' \sin\lambda', \\ Z &= c \sin\phi'. \end{align} \f] Jacobi employed the \e ellipsoidal latitude and longitude \f$(\beta, \omega)\f$ defined by \f[ \begin{align} X &= a \cos\omega \frac{\sqrt{a^2 - b^2\sin^2\beta - c^2\cos^2\beta}} {\sqrt{a^2 - c^2}}, \\ Y &= b \cos\beta \sin\omega, \\ Z &= c \sin\beta \frac{\sqrt{a^2\sin^2\omega + b^2\cos^2\omega - c^2}} {\sqrt{a^2 - c^2}}. \end{align} \f] Grid lines of constant \f$\beta\f$ and \f$\omega\f$ are given in Fig. 1.
Geodesic grid on a triaxial ellipsoid Fig. 1
\n Fig. 1: The ellipsoidal grid. The blue (resp. green) lines are lines of constant \f$\beta\f$ (resp. \f$\omega\f$); the grid spacing is 10°. Also shown in red are two of the principal sections of the ellipsoid, defined by \f$x = 0\f$ and \f$z = 0\f$. The third principal section, \f$y = 0\f$, is covered by the lines \f$\beta = \pm 90^\circ\f$ and \f$\omega = 90^\circ \pm 90^\circ\f$. These lines meet at four umbilical points (two of which are visible in this figure) where the principal radii of curvature are equal. The parameters of the ellipsoid are \f$a = 1.01\f$, \f$b = 1\f$, \f$c = 0.8\f$, and it is viewed in an orthographic projection from a point above \f$\phi = 40^\circ\f$, \f$\lambda = 30^\circ\f$. These parameters were chosen to accentuate the ellipsoidal effects on geodesics (relative to those on the earth) while still allowing the connection to an ellipsoid of revolution to be made. The grid lines of the ellipsoid coordinates are "lines of curvature" on the ellipsoid, i.e., they are parallel to the direction of principal curvature (Monge, 1796). They are also intersections of the ellipsoid with confocal systems of hyperboloids of one and two sheets (Dupin, 1813). Finally they are geodesic ellipses and hyperbolas defined using two adjacent umbilical points. For example, the lines of constant \f$\beta\f$ in Fig. 1 can be generated with the familiar string construction for ellipses with the ends of the string pinned to the two umbilical points. The element of length on the ellipsoid in ellipsoidal coordinates is given by \f[ \begin{align} \frac{ds^2}{(a^2-b^2)\sin^2\omega+(b^2-c^2)\cos^2\beta} &= \frac{b^2\sin^2\beta+c^2\cos^2\beta} {a^2-b^2\sin^2\beta-c^2\cos^2\beta} d\beta^2 \\ &\qquad+ \frac{a^2\sin^2\omega+b^2\cos^2\omega} {a^2\sin^2\omega+b^2\cos^2\omega-c^2} d\omega^2. \end{align} \f] The torus \f$(\omega, \beta) \in [-\pi,\pi] \times [-\pi,\pi]\f$ covers the ellipsoid twice. In order to facilitate passing to the limit of an oblate ellipsoid, we may regard as the principal sheet \f$[-\pi,\pi] \times [-\frac12\pi,\frac12\pi]\f$ and insert branch cuts at \f$\beta=\pm\frac12\pi\f$. The rule for switching sheets is \f[ \begin{align} \omega & \rightarrow -\omega,\\ \beta & \rightarrow \pi-\beta,\\ \alpha & \rightarrow \pi+\alpha, \end{align} \f] where \f$\alpha\f$ is the heading of a path, relative to a line of constant \f$\omega\f$. In the limit \f$b\rightarrow a\f$ (resp. \f$b\rightarrow c\f$), the umbilic points converge on the \f$z\f$ (resp. \f$x\f$) axis and an oblate (resp. prolate) ellipsoid is obtained with \f$\beta\f$ (resp. \f$\omega\f$) becoming the standard parametric latitude and \f$\omega\f$ (resp. \f$\beta\f$) becoming the standard longitude. The sphere is a non-uniform limit, with the position of the umbilic points depending on the ratio \f$(a-b)/(b-c)\f$. Inter-conversions between the three different latitudes and longitudes and the cartesian coordinates are simple algebraic exercises. \section triaxial-jacobi Jacobi's solution Solving the geodesic problem for an ellipsoid of revolution is, from the mathematical point of view, trivial; because of symmetry, geodesics have a constant of the motion (analogous to the angular momentum) which was found by Clairaut (1733). By 1806 (with the work of Legendre, Oriani, et al.), there was a complete understanding of the qualitative behavior of geodesics on an ellipsoid of revolution. On the other hand, geodesics on a triaxial ellipsoid have no obvious constant of the motion and thus represented a challenging "unsolved" problem in the first half of the nineteenth century. Jacobi discovered that the geodesic equations are separable if they are expressed in ellipsoidal coordinates. You can get an idea of the importance Jacobi attached to his discovery from the letter he wrote to his friend and neighbor Bessel:
The day before yesterday, I reduced to quadrature the problem of geodesic lines on an ellipsoid with three unequal axes. They are the simplest formulas in the world, Abelian integrals, which become the well known elliptic integrals if 2 axes are set equal.\n Königsberg, 28th Dec. '38.
On the same day he wrote a similar letter to the editor of Compte Rendus and his result was published in J. Crelle in (1839) with a French translation (from German) appearing in J. Liouville in (1841). Here is the solution, exactly as given by Jacobi here (with minor changes in notation): \f[ \begin{align} \delta &= \int \frac {\sqrt{b^2\sin^2\beta + c^2\cos^2\beta}\,d\beta} {\sqrt{a^2 - b^2\sin^2\beta - c^2\cos^2\beta} \sqrt{(b^2-c^2)\cos^2\beta - \gamma}}\\ &\quad - \int \frac {\sqrt{a^2\sin^2\omega + b^2\cos^2\omega}\,d\omega} {\sqrt{a^2\sin^2\omega + b^2\cos^2\omega - c^2} \sqrt{(a^2-b^2)\sin^2\omega + \gamma}} \end{align} \f] As Jacobi notes "a function of the angle \f$\beta\f$ equals a function of the angle \f$\omega\f$. These two functions are just Abelian integrals…" Two constants \f$\delta\f$ and \f$\gamma\f$ appear in the solution. Typically \f$\delta\f$ is zero if the lower limits of the integrals are taken to be the starting point of the geodesic and the direction of the geodesics is determined by \f$\gamma\f$. However for geodesics that start at an umbilical points, we have \f$\gamma = 0\f$ and \f$\delta\f$ determines the direction at the umbilical point. Incidentally the constant \f$\gamma\f$ may be expressed as \f[ \gamma = (b^2-c^2)\cos^2\beta\sin^2\alpha-(a^2-b^2)\sin^2\omega\cos^2\alpha \f] where \f$\alpha\f$ is the angle the geodesic makes with lines of constant \f$\omega\f$. In the limit \f$b\rightarrow a\f$, this reduces to \f$\cos\beta\sin\alpha = \text{const.}\f$, the familiar Clairaut relation. A nice derivation of Jacobi's result is given by Darboux (1894) §§583--584 where he gives the solution found by Liouville (1846) for general quadratic surfaces. In this formulation, the distance along the geodesic, \f$s\f$, is also found using \f[ \begin{align} \frac{ds}{(b^2-c^2)\cos^2\beta + (a^2-b^2)\sin^2\omega} &= \frac {\sqrt{b^2\sin^2\beta + c^2\cos^2\beta}\,d\beta} {\sqrt{a^2 - b^2\sin^2\beta - c^2\cos^2\beta} \sqrt{(b^2-c^2)\cos^2\beta - \gamma}}\\ &= \frac {\sqrt{a^2\sin^2\omega + b^2\cos^2\omega}\,d\omega} {\sqrt{a^2\sin^2\omega + b^2\cos^2\omega - c^2} \sqrt{(a^2-b^2)\sin^2\omega + \gamma}} \end{align} \f] An alternative expression for the distance is \f[ \begin{align} ds &= \frac {\sqrt{b^2\sin^2\beta + c^2\cos^2\beta} \sqrt{(b^2-c^2)\cos^2\beta - \gamma}\,d\beta} {\sqrt{a^2 - b^2\sin^2\beta - c^2\cos^2\beta}}\\ &\quad {}+ \frac {\sqrt{a^2\sin^2\omega + b^2\cos^2\omega} \sqrt{(a^2-b^2)\sin^2\omega + \gamma}\,d\omega} {\sqrt{a^2\sin^2\omega + b^2\cos^2\omega - c^2}} \end{align} \f] Jacobi's solution is a convenient way to compute geodesics on an ellipsoid. Care must be taken with the signs of the square roots (which are determined by the initial azimuth of the geodesic). Also if \f$\gamma \gt 0\f$ (resp. \f$\gamma \lt 0\f$), then the \f$\beta\f$ (resp. \f$\omega\f$) integrand diverges. The integrand can be transformed into a finite one by a change of variable, e.g., \f$\sin\beta = \sin\sigma \sqrt{1 - \gamma/(b^2-c^2)}\f$. The resulting integrals are periodic, so the behavior of an arbitrarily long geodesic is entirely captured by tabulating the integrals over a single period. The situation is more complicated if \f$\gamma = 0\f$ (corresponding to umbilical geodesics). Both integrands have simple poles at the umbilical points. However, this behavior may be subtracted from the integrands to yield (for example) the sum of a term involving \f$\tanh^{-1}\sin\beta\f$ and a finite integral. Since both integrals contain similar logarithmic singularities they can be equated (thus fixing the ratio \f$\cos\beta/\sin\omega\f$ at the umbilical point) and connection formulas can be found which allow the geodesic to be followed through the umbilical point. The study of umbilical geodesics was of special interest to a group of Irish mathematicians in the 1840's and 1850's, including Michael and William Roberts (twins!), Hart, Graves, and Salmon. \section triaxial-survey Survey of triaxial geodesics Before delving into the nature of geodesics on a triaxial geodesic, it is worth reviewing geodesics on an ellipsoid of revolution. There are two classes of simple closed geodesics (i.e., geodesics which close on themselves without intersection): the equator and all the meridians. All other geodesics oscillate between two equal and opposite circles of latitude; but after completing a full oscillation in latitude these fall slightly short (for an oblate ellipsoid) of completing a full circuit in longitude. Turning to the triaxial case, we find that there are only 3 simple closed geodesics, the three principal sections of the ellipsoid given by \f$x = 0\f$, \f$y = 0\f$, and \f$z = 0\f$. To survey the other geodesics, it is convenient to consider geodesics which intersect the middle principal section, \f$y = 0\f$, at right angles. Such geodesics are shown in Figs. 2--6, where I use the same ellipsoid parameters as in Fig. 1 and the same viewing direction. In addition, the three principal ellipses are shown in red in each of these figures. If the starting point is \f$\beta_1 \in (-90^\circ, 90^\circ)\f$, \f$\omega_1 = 0\f$, and \f$\alpha_1 = 90^\circ\f$, then the geodesic encircles the ellipsoid in a "circumpolar" sense. The geodesic oscillates north and south of the equator; on each oscillation it completes slightly less that a full circuit around the ellipsoid resulting in the geodesic filling the area bounded by the two latitude lines \f$\beta = \pm \beta_1\f$. Two examples are given in Figs. 2 and 3. Figure 2 shows practically the same behavior as for an oblate ellipsoid of revolution (because \f$a \approx b\f$). However, if the starting point is at a higher latitude (Fig. 3) the distortions resulting from \f$a \ne b\f$ are evident.
Example of a circumpolar geodesic on a
triaxial ellipsoid Fig. 2
\n Fig. 2: Example of a circumpolar geodesic on a triaxial ellipsoid. The starting point of this geodesic is \f$\beta_1 = 45.1^\circ\f$, \f$\omega_1 = 0^\circ\f$, and \f$\alpha_1 = 90^\circ\f$.
Another example of a circumpolar geodesic on a
triaxial ellipsoid Fig. 3
\n Fig. 3: Another example of a circumpolar geodesic on a triaxial ellipsoid. The starting point of this geodesic is \f$\beta_1 = 87.48^\circ\f$, \f$\omega_1 = 0^\circ\f$, and \f$\alpha_1 = 90^\circ\f$. If the starting point is \f$\beta_1 = 90^\circ\f$, \f$\omega_1 \in (0^\circ, 180^\circ)\f$, and \f$\alpha_1 = 180^\circ\f$, then the geodesic encircles the ellipsoid in a "transpolar" sense. The geodesic oscillates east and west of the ellipse \f$x = 0\f$; on each oscillation it completes slightly more that a full circuit around the ellipsoid resulting in the geodesic filling the area bounded by the two longitude lines \f$\omega = \omega_1\f$ and \f$\omega = 180^\circ - \omega_1\f$. If \f$a = b\f$, all meridians are geodesics; the effect of \f$a \ne b\f$ causes such geodesics to oscillate east and west. Two examples are given in Figs. 4 and 5.
Example of a transpolar geodesic on a
triaxial ellipsoid Fig. 4
\n Fig. 4: Example of a transpolar geodesic on a triaxial ellipsoid. The starting point of this geodesic is \f$\beta_1 = 90^\circ\f$, \f$\omega_1 = 39.9^\circ\f$, and \f$\alpha_1 = 180^\circ\f$.
Another example of a transpolar geodesic on a
triaxial ellipsoid Fig. 5
\n Fig. 5: Another example of a transpolar geodesic on a triaxial ellipsoid. The starting point of this geodesic is \f$\beta_1 = 90^\circ\f$, \f$\omega_1 = 9.966^\circ\f$, and \f$\alpha_1 = 180^\circ\f$. If the starting point is \f$\beta_1 = 90^\circ\f$, \f$\omega_1 = 0^\circ\f$ (an umbilical point), and \f$\alpha_1 = 135^\circ\f$ (the geodesic leaves the ellipse \f$y = 0\f$ at right angles), then the geodesic repeatedly intersects the opposite umbilical point and returns to its starting point. However on each circuit the angle at which it intersects \f$y = 0\f$ becomes closer to \f$0^\circ\f$ or \f$180^\circ\f$ so that asymptotically the geodesic lies on the ellipse \f$y = 0\f$. This is shown in Fig. 6. Note that a single geodesic does not fill an area on the ellipsoid.
Example of an umbilical geodesic on a
triaxial ellipsoid Fig. 6
\n Fig. 6: Example of an umbilical geodesic on a triaxial ellipsoid. The starting point of this geodesic is \f$\beta_1 = 90^\circ\f$, \f$\omega_1 = 0^\circ\f$, and \f$\alpha_1 = 135^\circ\f$ and the geodesics is followed forwards and backwards until it lies close to the plane \f$y = 0\f$ in both directions. Umbilical geodesics enjoy several interesting properties. - Through any point on the ellipsoid, there are two umbilical geodesics. - The geodesic distance between opposite umbilical points is the same regardless of the initial direction of the geodesic. - Whereas the closed geodesics on the ellipses \f$x = 0\f$ and \f$z = 0\f$ are stable (an geodesic initially close to and nearly parallel to the ellipse remains close to the ellipse), the closed geodesic on the ellipse \f$y = 0\f$, which goes through all 4 umbilical points, is \e unstable. If it is perturbed, it will swing out of the plane \f$y = 0\f$ and flip around before returning to close to the plane. (This behavior may repeat depending on the nature of the initial perturbation.). \section triaxial-stab The stability of closed geodesics The stability of the three simple closed geodesics can be determined by examining the properties of Jacobi's solution. In particular the unstable behavior of umbilical geodesics was shown by Hart (1849). However an alternative approach is to use the equations that Gauss (1828) gives for a perturbed geodesic \f[ \frac {d^2m}{ds^2} + Km = 0 \f] where \f$m\f$ is the distance of perturbed geodesic from a reference geodesic and \f$K\f$ is the Gaussian curvature of the surface. If the reference geodesic is closed, then this is a linear homogeneous differential equation with periodic coefficients. In fact it's a special case of Hill's equation which can be treated using Floquet theory, see DLMF, §28.29. Using the notation of §3 of Algorithms for geodesics, the stability is determined by computing the reduced length \f$m_{12}\f$ and the geodesic scales \f$M_{12}, M_{21}\f$ over half the perimeter of the ellipse and determining the eigenvalues \f$\lambda_{1,2}\f$ of \f[ {\cal M} = \left(\begin{array}{cc} M_{12} & m_{12}\\ -\frac{1 - M_{12}M_{21}}{m_{12}} & M_{21} \end{array}\right). \f] Because \f$\mathrm{det}\,{\cal M} = 1\f$, the eigenvalues are determined by \f$\mathrm{tr}\,{\cal M}\f$. In particular if \f$\left|\mathrm{tr}\,{\cal M}\right| < 2\f$, we have \f$\left|\lambda_{1,2}\right| = 1\f$ and the solution is stable; if \f$\left|\mathrm{tr}\,{\cal M}\right| > 2\f$, one of \f$\left|\lambda_{1,2}\right|\f$ is larger than unity and the solution is (exponentially) unstable. In the transition case, \f$\left|\mathrm{tr}\,{\cal M}\right| = 2\f$, the solution is stable provided that the off-diagonal elements of \f${\cal M}\f$ are zero; otherwise the solution is linearly unstable. The exponential instability of the geodesic on the ellipse \f$y = 0\f$ is confirmed by this analysis and results from the resonance between the natural frequency of the equation for \f$m\f$ and the driving frequency when \f$b\f$ lies in \f$(c, a)\f$. If \f$b\f$ is equal to either of the other axes (and the triaxial ellipsoid degenerates to an ellipsoid of revolution), then the solution is linearly unstable. (For example, a geodesic is which is close to a meridian on an oblate ellipsoid, slowly moves away from that meridian.) \section triaxial-inverse The inverse problem In order to solve the inverse geodesic problem, it helps to have an understanding of the properties of all the geodesics emanating from a single point \f$(\beta_1, \omega_1)\f$. - If the point is an umbilical point, all the lines meet at the opposite umbilical point. - Otherwise, the first envelope of the geodesics is a 4-pointed astroid. The cusps of the astroid lie on either \f$\beta = - \beta_1\f$ or \f$\omega = \omega_1 + \pi\f$; see Sinclair (2003). - All geodesics intersect (or, in the case of \f$\alpha_1 = 0\f$ or \f$\pi\f$, touch) the line \f$\omega = \omega_1 + \pi\f$. - All geodesics intersect (or, in the case of \f$\alpha_1 = \pm\pi/2\f$, touch) the line \f$\beta = -\beta_1\f$. - Two geodesics with azimuths \f$\pm\alpha_1\f$ first intersect on \f$\omega = \omega_1 + \pi\f$ and their lengths to the point of intersection are equal. - Two geodesics with azimuths \f$\alpha_1\f$ and \f$\pi-\alpha_1\f$ first intersect on \f$\beta = -\beta_1\f$ and their lengths to the point of intersection are equal. . (These assertions follow directly from the equations for the geodesics; some of them are somewhat surprising given the asymmetries of the ellipsoid.) Consider now terminating the geodesics from \f$(\beta_1, \omega_1)\f$ at the point where they first intersect (or touch) the line \f$\beta = -\beta_1\f$. To focus the discussion, take \f$\beta_1 \le 0\f$. - The geodesics completely fill the portion of the ellipsoid satisfying \f$\beta \le -\beta_1\f$. - None of geodesics intersect any other geodesics. - Any initial portion of these geodesics is a shortest path. - Each geodesic intersects the line \f$\beta = \beta_2\f$, where \f$\beta_1 < \beta_2 < -\beta_1\f$, exactly once. - For a given \f$\beta_2\f$, this defines a continuous monotonic mapping of the circle of azimuths \f$\alpha_1\f$ to the circle of longitudes \f$\omega_2\f$. - If \f$\beta_2 = \pm \beta_1\f$, then the previous two assertions need to be modified similarly to the case for an ellipsoid of revolution. These properties show that the inverse problem can be solved using techniques similar to those employed for an ellipsoid of revolution (see §4 of Algorithms for geodesics). - If the points are opposite umbilical points, an arbitrary \f$\alpha_1\f$ may be chosen. - If the points are neighboring umbilical points, the shortest path lies on the ellipse \f$y = 0\f$. - If only one point is an umbilicial point, the azimuth at the non-umbilical point is found using the generalization of Clairaut's equation (given above) with \f$\gamma = 0\f$. - Treat the cases where the geodesic might follow a line of constant \f$\beta\f$. There are two such cases: (a) the points lie on the ellipse \f$z = 0\f$ on a general ellipsoid and (b) the points lie on an ellipse whose major axis is the \f$x\f$ axis on a prolate ellipsoid (\f$a = b > c\f$). Determine the reduced length \f$m_{12}\f$ for the geodesic which is the shorter path along the ellipse. If \f$m_{12} \ge 0\f$, then this is the shortest path on the ellipsoid; otherwise proceed to the general case (next). - Swap the points, if necessary, so that the first point is the one closest to a pole. Estimate \f$\alpha_1\f$ (by some means) and solve the \e hybrid problem, i.e., determine the longitude \f$\omega_2\f$ corresponding to the first intersection of the geodesic with \f$\beta = \beta_2\f$. Adjust \f$\alpha_1\f$ so that the value of \f$\omega_2\f$ matches the given \f$\omega_2\f$ (there is a single root). If a sufficiently close solution can be found, Newton's method can be employed since the necessary derivative can be expressed in terms of the reduced length \f$m_{12}\f$. The shortest path found by this method is unique unless: - The length of the geodesic vanishes \f$s_{12}=0\f$, in which case any constant can be added to the azimuths. - The points are opposite umbilical points. In this case, \f$\alpha_1\f$ can take on any value and \f$\alpha_2\f$ needs to be adjusted to maintain the value of \f$\tan\alpha_1 / \tan\alpha_2\f$. Note that \f$\alpha\f$ increases by \f$\pm 90^\circ\f$ as the geodesic passes through an umbilical point, depending on whether the geodesic is considered as passing to the right or left of the point. Here \f$\alpha_2\f$ is the \e forward azimuth at the second umbilical point, i.e., its azimuth immediately \e after passage through the umbilical point. - \f$\beta_1 + \beta_2 = 0\f$ and \f$\cos\alpha_1\f$ and \f$\cos\alpha_2\f$ have opposite signs. In this case, there another shortest geodesic with azimuths \f$\pi - \alpha_1\f$ and \f$\pi - \alpha_2\f$. \section triaxial-conformal Jacobi's conformal projection This material is now on its own page; see \ref jacobi.
Back to \ref nearest. Forward to \ref jacobi. Up to \ref contents.
**********************************************************************/ /** \page jacobi Jacobi's conformal projection
Back to \ref triaxial. Forward to \ref rhumb. Up to \ref contents.
In addition to solving the geodesic problem for the triaxial ellipsoid, Jacobi (1839) briefly mentions the problem of the conformal projection of ellipsoid. He covers this in greater detail in Vorlesungen über Dynamik, §28, which is now available in an English translation: Lectures on Dynamics ( errata). \section jacobi-conformal Conformal projection It is convenient to rotate Jacobi's ellipsoidal coordinate system so that \f$(X,Y,Z)\f$ are respectively the middle, large, and small axes of the ellipsoid. The longitude \f$\omega\f$ is shifted so that \f$(\beta=0,\omega=0)\f$ is the point \f$(b,0,0)\f$. The coordinates are thus defined by \f[ \begin{align} X &= b \cos\beta \cos\omega, \\ Y &= a \sin\omega \frac{\sqrt{a^2 - b^2\sin^2\beta - c^2\cos^2\beta}} {\sqrt{a^2 - c^2}}, \\ Z &= c \sin\beta \frac{\sqrt{a^2\cos^2\omega + b^2\sin^2\omega - c^2}} {\sqrt{a^2 - c^2}}. \end{align} \f] After this change, the large principal ellipse is the equator, \f$\beta=0\f$, while the small principal ellipse is the prime meridian, \f$\omega=0\f$. The four umbilic points, \f$\left|\omega\right| = \left|\beta\right| = \frac12\pi\f$, lie on middle principal ellipse in the plane \f$X=0\f$. Jacobi gives the following conformal mapping of the triaxial ellipsoid onto a plane \f[ \begin{align} x &= \frac{\sqrt{a^2-c^2}}b \int \frac {\sqrt{a^2 \cos^2\omega + b^2 \sin^2\omega}} {\sqrt{a^2 \cos^2\omega + b^2 \sin^2\omega - c^2}}\, d\omega, \\ y &= \frac{\sqrt{a^2-c^2}}b \int \frac {\sqrt{b^2 \sin^2\beta + c^2 \cos^2\beta}} {\sqrt{a^2 - b^2 \sin^2\beta - c^2 \cos^2\beta}}\, d\beta. \end{align} \f] The scale of the projection is \f[ k = \frac{\sqrt{a^2-c^2}} {b\sqrt{a^2 \cos^2\omega + b^2 (\sin^2\omega-\sin^2\beta) - c^2 \cos^2\beta}}. \f] I have scaled the Jacobi's projection by a constant factor, \f[ \frac{\sqrt{a^2-c^2}}{2b}, \f] so that it reduces to the familiar formulas in the case of an oblate ellipsoid. \section jacobi-elliptic The projection in terms of elliptic integrals The projection may be expressed in terms of elliptic integrals, \f[ \begin{align} x&=(1+e_a^2)\,\Pi(\omega',-e_a^2, \cos\nu),\\ y&=(1-e_c^2)\,\Pi(\beta' , e_c^2, \sin\nu),\\ k&=\frac{\sqrt{e_a^2+e_c^2}}{b\sqrt{e_a^2\cos^2\omega+e_c^2\cos^2\beta}}, \end{align} \f] where \f[ \begin{align} e_a &= \frac{\sqrt{a^2-b^2}}b, \qquad e_c = \frac{\sqrt{b^2-c^2}}b, \\ \tan\omega' &= \frac ba \tan\omega = \frac 1{\sqrt{1+e_a^2}} \tan\omega, \\ \tan\beta' &= \frac bc \tan\beta = \frac 1{\sqrt{1-e_c^2}} \tan\beta, \\ \tan\nu &= \frac ac \frac{\sqrt{b^2-c^2}}{\sqrt{a^2-b^2}} =\frac{e_c}{e_a}\frac{\sqrt{1+e_a^2}}{\sqrt{1-e_c^2}}, \end{align} \f] \f$\nu\f$ is the geographic latitude of the umbilic point at \f$\beta = \omega = \frac12\pi\f$ (the angle a normal at the umbilic point makes with the equatorial plane), and \f$\Pi(\phi,\alpha^2,k)\f$ is the elliptic integral of the third kind, https://dlmf.nist.gov/19.2.E7. This allows the projection to be numerically computed using EllipticFunction::Pi(real phi) const. Nyrtsov, et al., - M. V. Nyrtsov, M. E. Flies, M. M. Borisov, P. J. Stooke, Jacobi conformal projection of the triaxial ellipsoid: new projection for mapping of small celestial bodies, in Cartography from Pole to Pole (Springer, 2014), pp. 235--246. . also expressed the projection in terms of elliptic integrals. However, their expressions don't allow the limits of ellipsoids of revolution to be readily recovered. The relations https://dlmf.nist.gov/19.7.E5 can be used to put their results in the form given here. \section jacobi-properties Properties of the projection \f$x\f$ (resp. \f$y\f$) depends on \f$\omega\f$ (resp. \f$\beta\f$) alone, so that latitude-longitude grid maps to straight lines in the projection. In this sense, the Jacobi projection is the natural generalization of the Mercator projection for the triaxial ellipsoid. (See below for the limit \f$a\rightarrow b\f$, which makes this connection explicit.) In the general case (all the axes are different), the scale diverges only at the umbilic points. The behavior of these singularities is illustrated by the complex function \f[ f(z;e) = \cosh^{-1}(z/e) - \log(2/e). \f] For \f$e > 0\f$, this function has two square root singularities at \f$\pm e\f$, corresponding to the two northern umbilic points. Plotting contours of its real (resp. imaginary) part gives the behavior of the lines of constant latitude (resp. longitude) near the north pole in Fig. 1. If we pass to the limit \f$e\rightarrow 0\f$, then \f$ f(z;e)\rightarrow\log z\f$, and the two branch points merge yielding a stronger (logarithmic) singularity at \f$z = 0\f$, concentric circles of latitude, and radial lines of longitude. Again in the general case, the extents of \f$x\f$ and \f$y\f$ are finite, \f[ \begin{align} x\bigl(\tfrac12\pi\bigr) &=(1+e_a^2)\,\Pi(-e_a^2, \cos\nu),\\ y\bigl(\tfrac12\pi\bigr) &=(1-e_c^2)\,\Pi(e_c^2, \sin\nu), \end{align} \f] where \f$\Pi(\alpha^2,k)\f$ is the complete elliptic integral of the third kind, https://dlmf.nist.gov/19.2.E8. In particular, if we substitute values appropriate for the earth, \f[ \begin{align} a&=(6378137+35)\,\mathrm m,\\ b&=(6378137-35)\,\mathrm m,\\ c&=6356752\,\mathrm m,\\ \end{align} \f] we have \f[ \begin{align} x\bigl({\textstyle\frac12}\pi\bigr) &= 1.5720928 = \hphantom{0}90.07428^\circ,\\ y\bigl({\textstyle\frac12}\pi\bigr) &= 4.2465810 = 243.31117^\circ.\\ \end{align} \f] The projection may be inverted (to give \f$\omega\f$ in terms of \f$x\f$ and \f$\beta\f$ in terms of \f$y\f$) by using Newton's method to find the root of, for example, \f$x(\omega) - x_0 = 0\f$. The derivative of the elliptic integral is, of course, just given by its defining relation. If rhumb lines are defined as curves with a constant bearing relative to the ellipsoid coordinates, then these are straight lines in the Jacobi projection. A rhumb line which passes over an umbilic point immediately retraces its path. A rhumb line which crosses the line joining the two northerly umbilic points starts traveling south with a reversed heading (e.g., a NE heading becomes a SW heading). This behavior is preserved in the limit \f$a\rightarrow b\f$ (although the longitude becomes indeterminate in this limit). \section jacobi-limiting Limiting cases Oblate ellipsoid, \f$a\rightarrow b\f$. The coordinate system is \f[ \begin{align} X &= b \cos\beta \cos\omega, \\ Y &= b \cos\beta \sin\omega, \\ Z &= c \sin\beta. \end{align} \f] Thus \f$\beta\f$ (resp. \f$\beta'\f$) is the parametric (resp. geographic) latitude and \f$\omega=\omega'\f$ is the longitude; the quantity \f$e_c\f$ is the eccentricity of the ellipsoid. Using https://dlmf.nist.gov/19.6.E12 and https://dlmf.nist.gov/19.2.E19 the projection reduces to the normal Mercator projection for an oblate ellipsoid, \f[ \begin{align} x &= \omega,\\ y &= \sinh^{-1}\tan\beta' - e_c \tanh^{-1}(e_c\sin\beta'),\\ k &= \frac1{b\cos\beta}. \end{align} \f] Prolate ellipsoid, \f$c\rightarrow b\f$. The coordinate system is \f[ \begin{align} X &= b \cos\omega \cos\beta, \\ Y &= a \sin\omega, \\ Z &= b \cos\omega \sin\beta. \end{align} \f] Thus \f$\omega\f$ (resp. \f$\omega'\f$) now plays the role of the parametric (resp. geographic) latitude and while \f$\beta=\beta'\f$ is the longitude. Using https://dlmf.nist.gov/19.6.E12 https://dlmf.nist.gov/19.2.E19 and https://dlmf.nist.gov/19.2.E18 the projection reduces to similar expressions with the roles of \f$\beta\f$ and \f$\omega\f$ switched, \f[ \begin{align} x &= \sinh^{-1}\tan\omega' + e_a \tan^{-1}(e_a\sin\omega'),\\ y &= \beta,\\ k &= \frac1{b\cos\omega}. \end{align} \f] Sphere, \f$a\rightarrow b\f$ and \f$c\rightarrow b\f$. This is a non-uniform limit depending on the parameter \f$\nu\f$, \f[ \begin{align} X &= b \cos\omega \cos\beta, \\ Y &= b \sin\omega \sqrt{1 - \sin^2\nu\sin^2\beta}, \\ Z &= b \sin\beta \sqrt{1 - \cos^2\nu\sin^2\omega}. \end{align} \f] Using https://dlmf.nist.gov/19.6.E13 the projection can be put in terms of the elliptic integral of the first kind, https://dlmf.nist.gov/19.2.E4 \f[ \begin{align} x &= F(\omega, \cos\nu), \\ y &= F(\beta, \sin\nu), \\ k &= \frac1{b \sqrt{\cos^2\nu\cos^2\omega + \sin^2\nu\cos^2\beta}}, \end{align} \f] Obtaining the limit of a sphere via an oblate (resp. prolate) ellipsoid corresponds to setting \f$\nu = \frac12\pi\f$ (resp. \f$\nu =0\f$). In these limits, the elliptic integral reduces to elementary functions https://dlmf.nist.gov/19.6.E7 and https://dlmf.nist.gov/19.6.E8 \f[ \begin{align} F(\phi, 0) &= \phi, \\ F(\phi, 1) &= \mathop{\mathrm{gd}}\nolimits^{-1}\phi = \sinh^{-1}\tan\phi. \end{align} \f] The spherical limit gives the projection found by É. Guyou in - Sur un nouveau système de projection de la sphère, Comptes Rendus 102(6), 308--310 (1886). - Nouveau système de projection de la sphère: généralisation de la projection de Mercator, Annales Hydrographiques (2nd series) 9, 16--35 (1887). . who apparently derived it without realizing that it is just a special case of the projection Jacobi had given some 40 years earlier. Guyou's name is usually associated with the particular choice, \f$\nu=\frac14\pi\f$, in which case the hemisphere \f$\left|\omega\right|\le\frac12\pi\f$ is mapped into a square. However, by varying \f$\nu\in[0,\frac12\pi]\f$ the hemisphere can be mapped into a rectangle with any aspect ratio, \f$K(\cos\nu) : K(\sin\nu)\f$, where \f$K(k)\f$ is the complete elliptic integral of the first find, https://dlmf.nist.gov/19.2.E8. \section jacobi-sphere Conformal mapping of an ellipsoid to a sphere An essential tool in deriving conformal projections of an ellipsoid of revolution is the conformal mapping of the ellipsoid onto a sphere. This allows conformal projections of the sphere to be generalized to the case of an ellipsoid of revolution. This conformal mapping is obtained by using the ellipsoidal Mercator projection to map the ellipsoid to the plane and then using the spherical Mercator projection to map the plane onto the sphere. A similar construction is possible for a triaxial ellipsoid. Map each octant of the ellipsoid onto a rectangle using the Jacobi projection. The aspect ratio of this rectangle is \f[ (1+e_a^2)\,\Pi(-e_a^2, \cos\nu) : (1-e_c^2)\,\Pi( e_c^2, \sin\nu). \f] Find the value of \f$\nu'\f$ such that this ratio equals \f[ K(\cos\nu') : K(\sin\nu'). \f] Map the rectangle onto the equivalent octant of the sphere using Guyou's projection with parameter \f$\nu = \nu'\f$. This reduces to the standard construction in the limit of an ellipsoid of revolution. \section jacobi-implementation An implementation of the projection The JacobiConformal class provides an implementation of the Jacobi conformal projection is given here. NOTE: This is just sample code. It is not part of GeographicLib itself.
Back to \ref triaxial. Forward to \ref rhumb. Up to \ref contents.
**********************************************************************/ /** \page rhumb Rhumb lines
Back to \ref jacobi. Forward to \ref greatellipse. Up to \ref contents.
The Rhumb and RhumbLine classes together with the RhumbSolve utility perform rhumb line calculations. A rhumb line (also called a loxodrome) is a line of constant azimuth on the surface of the ellipsoid. It is important for historical reasons because sailing with a constant compass heading is simpler than sailing the shorter geodesic course; see Osborne (2013). The formulation of the problem on an ellipsoid is covered by Smart (1946) and Carlton-Wippern (1992). Computational approaches are given by Williams (1950) and Bennett (1996). My interest in this problem was piqued by Botnev and Ustinov (2014) who discuss various techniques to improve the accuracy of rhumb line calculations. The items of interest here are: - Review of accurate formulas for the auxiliary latitudes. - The calculation of the area under a rhumb line. - Using divided differences to compute \f$\mu_{12}/\psi_{12}\f$ maintaining full accuracy. Two cases are treated: - If \f$f\f$ is small, Krüger's series for the transverse Mercator projection relate \f$\chi\f$ and \f$\mu\f$. - For arbitrary \f$f\f$, the divided difference formula for incomplete elliptic integrals of the second relates \f$\beta\f$ and \f$\mu\f$. . - Extending Clenshaw summation to compute the divided difference of a trigonometric sum. Go to - \ref rhumbform - \ref rhumblat - \ref rhumbarea - \ref divideddiffs - \ref dividedclenshaw References: - G. G. Bennett, Practical Rhumb Line Calculations on the Spheroid J. Navigation 49(1), 112--119 (1996). - F. W. Bessel, The calculation of longitude and latitude from geodesic measurements (1825), Astron. Nachr. 331(8), 852--861 (2010); translated by C. F. F. Karney and R. E. Deakin; preprint: arXiv:0908.1824. - V.A. Botnev, S.M. Ustinov, Metody resheniya pryamoy i obratnoy geodezicheskikh zadach s vysokoy tochnost'yu (Methods for direct and inverse geodesic problems solving with high precision), St. Petersburg State Polytechnical University Journal 3(198), 49--58 (2014). - K. C. Carlton-Wippern On Loxodromic Navigation, J. Navigation 45(2), 292--297 (1992). - K. E. Engsager and K. Poder, A highly accurate world wide algorithm for the transverse Mercator mapping (almost), Proc. XXIII Intl. Cartographic Conf. (ICC2007), Moscow (2007). - F. R. Helmert, Mathematical and Physical Theories of Higher Geodesy, Part 1 (1880), Aeronautical Chart and Information Center (St. Louis, 1964), Chaps. 5--7. - W. M. Kahan and R. J. Fateman, Symbolic computation of divided differences, SIGSAM Bull. 33(3), 7--28 (1999) DOI: 10.1145/334714.334716. - C. F. F. Karney, Transverse Mercator with an accuracy of a few nanometers, J. Geodesy 85(8), 475--485 (Aug. 2011); addenda: tm-addenda.html; preprint: arXiv:1002.1417; resource page: tm.html. - C. F. F. Karney, Algorithms for geodesics, J. Geodesy 87(1), 43--55 (2013); DOI: 10.1007/s00190-012-0578-z; addenda: geod-addenda.html; resource page: geod.html. - L. Krüger, Konforme Abbildung des Erdellipsoids in der Ebene (Conformal mapping of the ellipsoidal earth to the plane), Royal Prussian Geodetic Institute, New Series 52, 172 pp. (1912). - P. Osborne, The Mercator Projections (2013), §2.5 and §6.5; DOI: 10.5281/zenodo.35392. - W. M. Smart On a Problem in Navigation MNRAS 106(2), 124--127 (1946). - J. E. D. Williams Loxodromic Distances on the Terrestrial Spheroid Journal, J. Navigation 3(2), 133--140 (1950) \section rhumbform Formulation of the rhumb line problem The rhumb line can formulated in terms of three types of latitude, the isometric latitude \f$\psi\f$ (this serves to define the course of rhumb lines), the rectifying latitude \f$\mu\f$ (needed for computing distances along rhumb lines), and the parametric latitude \f$\beta\f$ (needed for dealing with rhumb lines that run along a parallel). These are defined in terms of the geographical latitude \f$\phi\f$ by \f[ \begin{align} \frac{d\psi}{d\phi} &= \frac{\rho}R, \\ \frac{d\mu}{d\phi} &= \frac{\pi}{2M}\rho, \\ \end{align} \f] where \f$\rho\f$ is the meridional radius of curvature, \f$R = a\cos\beta\f$ is the radius of a circle of latitude, and \f$M\f$ is the length of a quarter meridian (from the equator to the pole). Rhumb lines are straight in the Mercator projection, which maps a point with geographical coordinates \f$ (\phi,\lambda) \f$ on the ellipsoid to a point \f$ (\psi,\lambda) \f$. The azimuth \f$\alpha_{12}\f$ of a rhumb line from \f$ (\phi_1,\lambda_1) \f$ to \f$ (\phi_2,\lambda_2) \f$ is thus given by \f[ \tan\alpha_{12} = \frac{\lambda_{12}}{\psi_{12}}, \f] where the quadrant of \f$\alpha_{12}\f$ is determined by the signs of the numerator and denominator of the right-hand side, \f$\lambda_{12} = \lambda_2 - \lambda_1\f$, \f$\psi_{12} = \psi_2 - \psi_1\f$, and, typically, \f$\lambda_{12}\f$ is reduced to the range \f$[-\pi,\pi]\f$ (thus giving the course of the shortest rhumb line). The distance is given by \f[ \begin{align} s_{12} &= \frac {2M}{\pi} \mu_{12} \sec\alpha_{12} \\ &= \frac {2M}{\pi} \frac{\mu_{12}}{\psi_{12}} \sqrt{\lambda_{12}^2 + \psi_{12}^2}, \end{align} \f] where \f$\mu_{12} = \mu_2 - \mu_1\f$. This relation is indeterminate if \f$\phi_1 = \phi_2\f$, so we take the limits \f$\psi_{12}\rightarrow0\f$ and \f$\mu_{12}\rightarrow0\f$ and apply L'Hôpital's rule to yield \f[ \begin{align} s_{12} &= \frac {2M}{\pi} \frac{d\mu}{d\psi} \left|\lambda_{12}\right|\\ &=a \cos\beta \left|\lambda_{12}\right|, \end{align} \f] where the last relation is given by the defining equations for \f$\psi\f$ and \f$\mu\f$. This provides a complete solution for rhumb lines. This formulation entirely encapsulates the ellipsoidal shape of the earth via the \ref auxlat; thus in the Rhumb class, the ellipsoidal generalization is handled by the Ellipsoid class where the auxiliary latitudes are defined. \section rhumblat Determining the auxiliary latitudes Here we brief develop the necessary formulas for the \ref auxlat. Isometric latitude: The equation for \f$\psi\f$ can be integrated to give \f[ \psi = \sinh^{-1}\tan\phi - e\tanh^{-1}(e \sin\phi), \f] where \f$e = \sqrt{f(2-f)}\f$ is the eccentricity of the ellipsoid. To invert this equation (to give \f$\phi\f$ in terms of \f$\psi\f$), it is convenient to introduce the variables \f$\tau=\tan\phi\f$ and \f$\tau' = \tan\chi = \sinh\psi\f$ (\f$\chi\f$ is the conformal latitude) which are related by (Karney, 2011) \f[ \begin{align} \tau' &= \tau \sqrt{1 + \sigma^2} - \sigma \sqrt{1 + \tau^2}, \\ \sigma &= \sinh\bigl(e \tanh^{-1}(e \tau/\sqrt{1 + \tau^2}) \bigr). \end{align} \f] The equation for \f$\tau'\f$ can be inverted to give \f$\tau\f$ in terms of \f$\tau'\f$ using Newton's method with \f$\tau_0 = \tau'/(1-e^2)\f$ as a starting guess; and, of course, \f$\phi\f$ and \f$\psi\f$ are then given by \f[ \begin{align} \phi &= \tan^{-1}\tau,\\ \psi &= \sinh^{-1}\tau'. \end{align} \f] This allows conversions to and from \f$\psi\f$ to be carried out for any value of the flattening \f$f\f$; these conversions are implemented by Ellipsoid::IsometricLatitude and Ellipsoid::InverseIsometricLatitude. (For prolate ellipsoids, \f$f\f$ is negative and \f$e\f$ is imaginary, and the equation for \f$\sigma\f$ needs to be recast in terms of the tangent function.) For small values of \f$f\f$, Engsager and Poder (2007) express \f$\chi\f$ as a trigonometric series in \f$\phi\f$. This series can be reverted to give a series for \f$\phi\f$ in terms of \f$\chi\f$. Both series can be efficiently evaluated using Clenshaw summation and this provides a fast non-iterative way of making the conversions. Parametric latitude: This is given by \f[ \tan\beta = (1-f)\tan\phi, \f] which allows rapid and accurate conversions; these conversions are implemented by Ellipsoid::ParametricLatitude and Ellipsoid::InverseParametricLatitude. Rectifying latitude: Solving for distances on the meridian is naturally carried out in terms of the parametric latitude instead of the geographical latitude. This leads to a simpler elliptic integral which is easier to evaluate and to invert. Helmert (1880, §5.11) notes that the series for meridian distance in terms of \f$\beta\f$ converge faster than the corresponding ones in terms of \f$\phi\f$. In terms of \f$\beta\f$, the rectifying latitude is given by \f[ \mu = \frac{\pi}{2E(ie')} E(\beta,ie'), \f] where \f$e'=e/\sqrt{1-e^2}\f$ is the second eccentricity and \f$E(k)\f$ and \f$E(\phi,k)\f$ are the complete and incomplete elliptic integrals of the second kind; see https://dlmf.nist.gov/19.2.ii. These can be evaluated accurately for arbitrary flattening using the method given in https://dlmf.nist.gov/19.36.i. To find \f$\beta\f$ in terms of \f$\mu\f$, Newton's method can be used (noting that \f$dE(\phi,k)/d\phi = \sqrt{1 - k^2\sin^2\phi}\f$); for a starting guess use \f$\beta_0 = \mu\f$ (or use the first terms in the reverted series; see below). These conversions are implemented by Ellipsoid::RectifyingLatitude and Ellipsoid::InverseRectifyingLatitude. If the flattening is small, \f$\mu\f$ can be expressed as a series in various ways. The most economical series is in terms of the third flattening \f$ n = f/(2-f)\f$ and was found by Bessel (1825); see Eq. 5.5.7 of Helmert (1880). Helmert (1880, Eq. 5.6.8) also gives the reverted series (finding \f$\beta\f$ given \f$\mu\f$). These series are used by the Geodesic class where the coefficients are \f$C_{1j}\f$ and \f$C_{1j}'\f$; see Eqs. (18) and (21) of Karney (2013) and \ref geodseries. (Make the replacements, \f$\sigma\rightarrow\beta\f$, \f$\tau\rightarrow\mu\f$, \f$\epsilon\rightarrow n\f$, to convert the notation of the geodesic problem to the problem at hand.) The series are evaluated by Clenshaw summation. These relations allow inter-conversions between the various latitudes \f$\phi\f$, \f$\psi\f$, \f$\chi\f$, \f$\beta\f$, \f$\mu\f$ to be carried out simply and accurately. The approaches using series apply only if \f$f\f$ is small. The others apply for arbitrary values of \f$f\f$. \section rhumbarea The area under a rhumb line The area between a rhumb line and the equator is given by \f[ S_{12} = \int_{\lambda_1}^{\lambda_2} c^2 \sin\xi \,d\lambda, \f] where \f$c\f$ is the authalic radius and \f$\xi\f$ is the authalic latitude. Express \f$\sin\xi\f$ in terms of the conformal latitude \f$\chi\f$ and expand as a series in the third flattening \f$n\f$. This can be expressed in terms of powers of \f$\sin\chi\f$. Substitute \f$\sin\chi=\tanh\psi\f$, where \f$\psi\f$ is the isometric latitude. For a rhumb line we have \f[ \begin{align} \psi &= m(\lambda-\lambda_0),\\ m &= \frac{\psi_2 - \psi_1}{\lambda_2 - \lambda_1}. \end{align} \f] Performing the integral over \f$\lambda\f$ gives \f[ S_{12} = c^2 \lambda_{12} \left<\sin\xi\right>_{12}, \f] where \f$\left<\sin\xi\right>_{12}\f$ is the mean value of \f$\sin\xi\f$ given by \f[ \begin{align} \left<\sin\xi\right>_{12} &= \frac{S(\chi_2) - S(\chi_1)}{\psi_2 - \psi_1},\\ S(\chi) &= \log\sec\chi + \sum_{l=1} R_l\cos(2l\chi), \end{align} \f] \f$\log\f$ is the natural logarithm, and \f$R_l = O(n^l)\f$ is given as a series in \f$n\f$ below. In the spherical limit, the sum vanishes. Note the simple way that longitude enters into the expression for the area. In the limit \f$\chi_2 \rightarrow \chi_1\f$, we can apply l'Hôpital's rule \f[ \left<\sin\xi\right>_{12} \rightarrow \frac{dS(\chi_1)/d\chi_1}{\sec\chi_1} =\sin\xi_1, \f] as expected. In order to maintain accuracy, particularly for rhumb lines which nearly follow a parallel, evaluate \f$\left<\sin\xi\right>_{12}\f$ using divided differences (see the \ref divideddiffs "next section") and use Clenshaw summation to evaluate the sum (see the \ref dividedclenshaw "last section"). Here is the series expansion accurate to 10th order, found by the Maxima script rhumbarea.mac: \verbatim R[1] = - 1/3 * n + 22/45 * n^2 - 356/945 * n^3 + 1772/14175 * n^4 + 41662/467775 * n^5 - 114456994/638512875 * n^6 + 258618446/1915538625 * n^7 - 1053168268/37574026875 * n^8 - 9127715873002/194896477400625 * n^9 + 33380126058386/656284056553125 * n^10; R[2] = - 2/15 * n^2 + 106/315 * n^3 - 1747/4725 * n^4 + 18118/155925 * n^5 + 51304574/212837625 * n^6 - 248174686/638512875 * n^7 + 2800191349/14801889375 * n^8 + 10890707749202/64965492466875 * n^9 - 3594078400868794/10719306257034375 * n^10; R[3] = - 31/315 * n^3 + 104/315 * n^4 - 23011/51975 * n^5 + 1554472/14189175 * n^6 + 114450437/212837625 * n^7 - 8934064508/10854718875 * n^8 + 4913033737121/21655164155625 * n^9 + 591251098891888/714620417135625 * n^10; R[4] = - 41/420 * n^4 + 274/693 * n^5 - 1228489/2027025 * n^6 + 3861434/42567525 * n^7 + 1788295991/1550674125 * n^8 - 215233237178/123743795175 * n^9 + 95577582133463/714620417135625 * n^10; R[5] = - 668/5775 * n^5 + 1092376/2027025 * n^6 - 3966679/4343625 * n^7 + 359094172/10854718875 * n^8 + 7597613999411/3093594879375 * n^9 - 378396252233936/102088631019375 * n^10; R[6] = - 313076/2027025 * n^6 + 4892722/6081075 * n^7 - 1234918799/834978375 * n^8 - 74958999806/618718975875 * n^9 + 48696857431916/9280784638125 * n^10; R[7] = - 3189007/14189175 * n^7 + 930092876/723647925 * n^8 - 522477774212/206239658625 * n^9 - 2163049830386/4331032831125 * n^10; R[8] = - 673429061/1929727800 * n^8 + 16523158892/7638505875 * n^9 - 85076917909/18749059875 * n^10; R[9] = - 39191022457/68746552875 * n^9 + 260863656866/68746552875 * n^10; R[10] = - 22228737368/22915517625 * n^10; \endverbatim \section divideddiffs Use of divided differences Despite our ability to compute latitudes accurately, the way that distances enter into the solution involves the ratio \f$\mu_{12}/\psi_{12}\f$; the numerical calculation of this term is subject to catastrophic round-off errors when \f$\phi_1\f$ and \f$\phi_2\f$ are close. A simple solution, suggested by Bennett (1996), is to extend the treatment of rhumb lines along parallels to this case, i.e., to replace the ratio by the derivative evaluated at the midpoint. However this is not entirely satisfactory: you have to pick the transition point where the derivative takes over from the ratio of differences; and, near this transition point, many bits of accuracy will be lost (I estimate that about 1/3 of bits are lost, leading to errors on the order of 0.1 mm for double precision). Note too that this problem crops up even in the spherical limit. It turns out that we can do substantially better than this and maintain full double precision accuracy. Indeed Botnev and Ustinov provide formulas which allow \f$\mu_{12}/\psi_{12}\f$ to be computed accurately (but the formula for \f$\mu_{12}\f$ applies only for small flattening). Here I give a more systematic treatment using the algebra of divided differences. Many readers will be already using this technique, e.g., when writing, for example, \f[ \frac{\sin(2x) - \sin(2y)}{x-y} = 2\frac{\sin(x-y)}{x-y}\cos(x+y). \f] However, Kahan and Fateman (1999) provide an extensive set of rules which allow the technique to be applied to a wide range of problems. (The classes LambertConformalConic and AlbersEqualArea use this technique to improve the accuracy.) To illustrate the technique, consider the relation between \f$\psi\f$ and \f$\chi\f$, \f[ \psi = \sinh^{-1}\tan\chi. \f] The divided difference operator is defined by \f[ \Delta[f](x,y) = \begin{cases} df(x)/dx, & \text{if $x=y$,} \\ \displaystyle\frac{f(x)-f(y)}{x-y}, & \text{otherwise.} \end{cases} \f] Many of the rules for differentiation apply to divided differences; in particular, we can use the chain rule to write \f[ \frac{\psi_1 - \psi_2}{\chi_1 - \chi_2} = \Delta[\sinh^{-1}](\tan\chi_1,\tan\chi_2) \times \Delta[\tan](\chi_1,\chi_2). \f] Kahan and Fateman catalog the divided difference formulas for all the elementary functions. In this case, we need \f[ \begin{align} \Delta[\tan](x,y) &= \frac{\tan(x-y)}{x-y} (1 + \tan x\tan y),\\ \Delta[\sinh^{-1}](x,y) &= \frac1{x-y} \sinh^{-1}\biggl(\frac{(x-y)(x+y)}{x\sqrt{1+y^2}+y\sqrt{1+x^2}}\biggr). \end{align} \f] The crucial point in these formulas is that the right hand sides can be evaluated accurately even if \f$x-y\f$ is small. (I've only included the basic results here; Kahan and Fateman supplement these with the derivatives if \f$x-y\f$ vanishes or the direct ratios if \f$x-y\f$ is not small.) To complete the computation of \f$\mu_{12}/\psi_{12}\f$, we now need \f$(\mu_1 - \mu_2)/(\chi_1 - \chi_2)\f$, i.e., we need the divided difference of the function that converts the conformal latitude to rectifying latitude. We could go through the chain of relations between these quantities. However, we can take a short cut and recognize that this function was given as a trigonometric series by Krüger (1912) in his development of the transverse Mercator projection. This is also given by Eqs. (5) and (35) of Karney (2011) with the replacements \f$\zeta \rightarrow \mu\f$ and \f$\zeta' \rightarrow \chi\f$. The coefficients appearing in this series and the reverted series Eqs. (6) and (36) are already computed by the TransverseMercator class. The series can be readily converted to divided difference form (see the example at the beginning of this section) and Clenshaw summation can be used to evaluate it (see below). The approach of using the series for the transverse Mercator projection limits the applicability of the method to \f$\left|f\right|\lt 0.01\f$. If we want to extend the method to arbitrary flattening we need to compute \f$\Delta[E](x,y;k)\f$. The necessary relation is the "addition theorem" for the incomplete elliptic integral of the second kind given in https://dlmf.nist.gov/19.11.E2. This can be converted in the following divided difference formula \f[ \Delta[E](x,y;k) =\begin{cases} \sqrt{1 - k^2\sin^2x}, & \text{if $x=y$,} \\ \displaystyle \frac{E(x,k)-E(y,k)}{x-y}, & \text{if $xy \le0$,}\\ \displaystyle \biggl(\frac{E(z,k)}{\sin z} - k^2 \sin x \sin y\biggr)\frac{\sin z}{x-y}, &\text{otherwise,} \end{cases} \f] where the angle \f$z\f$ is given by \f[ \begin{align} \sin z &= \frac{2t}{1 + t^2},\quad\cos z = \frac{(1-t)(1+t)}{1 + t^2},\\ t &= \frac{(x-y)\Delta[\sin](x,y)} {\sin x\sqrt{1 - k^2\sin^2y} + \sin y\sqrt{1 - k^2\sin^2x}} \frac{\sin x + \sin y}{\cos x + \cos y}. \end{align} \f] We also need to apply the divided difference formulas to the conversions from \f$\phi\f$ to \f$\beta\f$ and \f$\phi\f$ to \f$\psi\f$; but these all involve elementary functions and the techniques given in Kahan and Fateman can be used. The end result is that the Rhumb class allows the computation of all rhumb lines for any flattening with full double precision accuracy (the maximum error is about 10 nanometers). I've kept the implementation simple, which results in rather a lot of repeated evaluations of quantities. However, in this case, the need for clarity trumps the desire for speed. \section dividedclenshaw Clenshaw evaluation of differenced sums The use of Clenshaw summation for summing series of the form, \f[ g(x) = \sum_{k=1}^N c_k \sin kx, \f] is well established. However when computing divided differences, we are interested in evaluating \f[ g(x)-g(y) = \sum_{k=1}^N 2 c_k \sin\bigl({\textstyle\frac12}k(x-y)\bigr) \cos\bigl({\textstyle\frac12}k(x+y)\bigr). \f] Clenshaw summation can be used in this case if we simultaneously compute \f$g(x)+g(y)\f$ and perform a matrix summation, \f[ \mathsf G(x,y) = \begin{bmatrix} (g(x) + g(y)) / 2\\ (g(x) - g(y)) / (x - y) \end{bmatrix} = \sum_{k=1}^N c_k \mathsf F_k(x,y), \f] where \f[ \mathsf F_k(x,y)= \begin{bmatrix} \cos kd \sin kp\\ {\displaystyle\frac{\sin kd}d} \cos kp \end{bmatrix}, \f] \f$d=\frac12(x-y)\f$, \f$p=\frac12(x+y)\f$, and, in the limit \f$d\rightarrow0\f$, \f$(\sin kd)/d \rightarrow k\f$. The first element of \f$\mathsf G(x,y)\f$ is the average value of \f$g\f$ and the second element, the divided difference, is the average slope. \f$\mathsf F_k(x,y)\f$ satisfies the recurrence relation \f[ \mathsf F_{k+1}(x,y) = \mathsf A(x,y) \mathsf F_k(x,y) - \mathsf F_{k-1}(x,y), \f] where \f[ \mathsf A(x,y) = 2\begin{bmatrix} \cos d \cos p & -d\sin d \sin p \\ - {\displaystyle\frac{\sin d}d} \sin p & \cos d \cos p \end{bmatrix}, \f] and \f$\lim_{d\rightarrow0}(\sin d)/d = 1\f$. The standard Clenshaw algorithm can now be applied to yield \f[ \begin{align} \mathsf B_{N+1} &= \mathsf B_{N+2} = \mathsf 0, \\ \mathsf B_k &= \mathsf A \mathsf B_{k+1} - \mathsf B_{k+2} + c_k \mathsf I, \qquad\text{for $N\ge k \ge 1$},\\ \mathsf G(x,y) &= \mathsf B_1 \mathsf F_1(x,y), \end{align} \f] where \f$\mathsf B_k\f$ are \f$2\times2\f$ matrices. The divided difference \f$\Delta[g](x,y)\f$ is given by the second element of \f$\mathsf G(x,y)\f$. The same basic recursion applies to the more general case, \f[ g(x) = \sum_{k=0}^N c_k \sin\bigl( (k+k_0)x + x_0\bigr). \f] For example, the sum area arising in the computation of geodesic areas, \f[ \sum_{k=0}^N c_k\cos\bigl((2k+1)\sigma) \f] is given by \f$x=2\sigma\f$, \f$x_0=\frac12\pi\f$, \f$k_0=\frac12\f$. Again we consider the matrix sum, \f[ \mathsf G(x,y) = \begin{bmatrix} (g(x) + g(y)) / 2\\ (g(x) - g(y)) / (x - y) \end{bmatrix} = \sum_{k=0}^N c_k \mathsf F_k(x,y), \f] where \f[ \mathsf F_k(x,y)= \begin{bmatrix} \cos\bigl( (k+k_0)d \bigr) \sin \bigl( (k+k_0)p + x_0 \bigr)\\ {\displaystyle\frac{\sin\bigl( (k+k_0)d \bigr)}d} \cos \bigl( (k+k_0)p + x_0 \bigr) \end{bmatrix}. \f] The recursion for \f$\mathsf B_k\f$ is identical to the previous case; in particular, the expression for \f$\mathsf A(x,y)\f$ remains unchanged. The result for the sum is \f[ \mathsf G(x,y) = (c_0\mathsf I - \mathsf B_2) \mathsf F_0(x,y) + \mathsf B_1 \mathsf F_1(x,y). \f]
Back to \ref jacobi. Forward to \ref greatellipse. Up to \ref contents.
**********************************************************************/ /** \page greatellipse Great Ellipses
Back to \ref rhumb. Forward to \ref transversemercator. Up to \ref contents.
Great ellipses are sometimes proposed (Williams, 1996; Pallikaris & Latsas, 2009) as alternatives to geodesics for the purposes of navigation. This is predicated on the assumption that solving the geodesic problems is complex and costly. These assumptions are no longer true, and geodesics should normally be used in place of great ellipses. This is discussed in more detail in \ref gevsgeodesic. Solutions of the great ellipse problems implemented for MATLAB and Octave are provided by - gedoc: briefly describe the routines - gereckon: solve the direct great ellipse problem - gedistance: solve the inverse great ellipse problem . At this time, there is C++ support in GeographicLib for great ellipses. References: - P. D. Thomas, Mathematical Models for Navigation Systems, TR-182 (U.S. Naval Oceanographic Office, 1965). - B. R. Bowring, The direct and inverse solutions for the great elliptic line on the reference ellipsoid, Bull. Geod. 58, 101--108 (1984). - M. A. Earle, A vector solution for navigation on a great ellipse, J. Navigation 53(3), 473--481 (2000). - M. A. Earle, Vector solutions for azimuth, J. Navigation 61(3), 537--545 (2008). - C. F. F. Karney, Algorithms for geodesics, J. Geodesy 87(1), 43--55 (2013); addenda: geod-addenda.html. - A. Pallikaris & G. Latsas, New algorithm for great elliptic sailing (GES), J. Navigation 62(3), 493--507 (2009). - A. Pallikaris, L. Tsoulos, & D. Paradissis, New meridian arc formulas for sailing calculations in navigational GIS, International Hydrographic Review, 24--34 (May 2009). - L. E. Sjöberg, Solutions to the direct and inverse navigation problems on the great ellipse, J. Geodetic Science 2(3), 200--205 (2012). - R. Williams, The Great Ellipse on the Surface of the Spheroid, J. Navigation 49(2), 229--234 (1996). - T. Vincenty, Direct and Inverse Solutions of Geodesics on the Ellipsoid with Application of Nested Equations, Survey Review 23(176), 88--93 (1975). - Wikipedia page, Great ellipse. Go to - \ref geformulation - \ref gearea - \ref gevsgeodesic \section geformulation Solution of great ellipse problems Adopt the usual notation for the ellipsoid: equatorial semi-axis \f$a\f$, polar semi-axis \f$b\f$, flattening \f$f = (a-b)/a\f$, eccentricity \f$e = \sqrt{f(2-f)}\f$, second eccentricity \f$e' = e/(1-f)\f$, and third flattening \f$n=(a-b)/(a+b)=f/(2-f)\f$. There are several ways in which an ellipsoid can be mapped into a sphere converting the great ellipse into a great circle. The simplest ones entail scaling the ellipsoid in the \f$\hat z\f$ direction, the direction of the axis of rotation, scaling the ellipsoid radially, or a combination of the two. One such combination (scaling by \f$a^2/b\f$ in the \f$\hat z\f$ direction, following by a radial scaling to the sphere) preserves the geographical latitude \f$\phi\f$. This enables a great ellipse to be plotted on a chart merely by determining way points on the corresponding great circle and transferring them directly on the chart. In this exercise the flattening of the ellipsoid can be ignored! Bowring (1984), Williams (1996), Earle (2000, 2008) and Pallikaris & Latsas (2009), scale the ellipsoid radially onto a sphere preserving the geocentric latitude \f$\theta\f$. More convenient than this is to scale the ellipsoid along \f$\hat z\f$ onto the sphere, as is done by Thomas (1965) and Sjöberg (2012), thus preserving the parametric latitude \f$\beta\f$. The advantage of this "parametric" mapping is that Bessel's rapidly converging series for meridian arc in terms of parametric latitude can be used (a possibility that is overlooked by Sjöberg). The full parametric mapping is: - The geographic latitude \f$\phi\f$ on the ellipsoid maps to the parametric latitude \f$\beta\f$ on the sphere, where \f[a\tan\beta = b\tan\phi.\f] - The longitude \f$\lambda\f$ is unchanged. - The azimuth \f$\alpha\f$ on the ellipsoid maps to an azimuth \f$\gamma\f$ on the sphere where \f[ \begin{align} \tan\alpha &= \frac{\tan\gamma}{\sqrt{1-e^2\cos^2\beta}}, \\ \tan\gamma &= \frac{\tan\alpha}{\sqrt{1+e'^2\cos^2\phi}}, \end{align} \f] and the quadrants of \f$\alpha\f$ and \f$\gamma\f$ are the same. - Positions on the great circle of radius \f$a\f$ are parametrized by arc length \f$\sigma\f$ measured from the northward crossing of the equator. The great ellipse has semi-axes \f$a\f$ and \f$b'=a\sqrt{1-e^2\cos^2\gamma_0}\f$, where \f$\gamma_0\f$ is the great-circle azimuth at the northward equator crossing, and \f$\sigma\f$ is the parametric angle on the ellipse. [In contrast, the ellipse giving distances on a geodesic has semi-axes \f$b\sqrt{1+e'^2\cos^2\alpha_0}\f$ and \f$b\f$.] . To determine the distance along the ellipse in terms of \f$\sigma\f$ and vice versa, the series for distance \f$s\f$ and for \f$\tau\f$ given in \ref geodseries can be used. The direct and inverse great ellipse problems are now simply solved by mapping the problem to the sphere, solving the resulting great circle problem, and mapping this back onto the ellipsoid. \section gearea The area under a great ellipse The area between the segment of a great ellipse and the equator can be found by very similar methods to those used for geodesic areas; see Danielsen (1989). The notation here is similar to that employed by Karney (2013). \f[ \begin{align} S_{12} &= S(\sigma_2) - S(\sigma_1) \\ S(\sigma) &= c^2\gamma + e^2 a^2 \cos\gamma_0 \sin\gamma_0 I_4(\sigma)\\ c^2 &= {\textstyle\frac12}\bigl(a^2 + b^2 (\tanh^{-1}e)/e\bigr) \end{align} \f] \f[ I_4(\sigma) = - \sqrt{1+e'^2}\int \frac{r(e'^2) - r(k^2\sin^2\sigma)}{e'^2 - k^2\sin^2\sigma} \frac{\sin\sigma}2 \,d\sigma \f] \f[ \begin{align} k &= e' \cos\gamma_0,\\ r(x) &= \sqrt{1+x} + (\sinh^{-1}\sqrt x)/\sqrt x. \end{align} \f] Expand in terms of the third flattening of the ellipsoid, \f$n\f$, and the third flattening of the great ellipse, \f$\epsilon=(a-b')/(a+b')\f$, by substituting \f[ \begin{align} e'&=\frac{2\sqrt n}{1-n},\\ k&=\frac{1+n}{1-n} \frac{2\sqrt{\epsilon}}{1+\epsilon}, \end{align} \f] to give \f[ I_4(\sigma) = \sum_{l = 0}^\infty G_{4l}\cos \bigl((2l+1)\sigma\bigr). \f] Compared to the area under a geodesic, we have - \f$\gamma\f$ and \f$\gamma_0\f$ instead of \f$\alpha\f$ and \f$\alpha_0\f$. In both cases, these are azimuths on the auxiliary sphere; however, for the geodesic, they are also the azimuths on the ellipsoid. - \f$r(x) = \bigl(1+t(x)\bigr)/\sqrt{1+x}\f$ instead of \f$t(x)\f$ with a balancing factor of \f$\sqrt{1+e'^2}\f$ appearing in front of the integral. These changes are because expressing \f$\sin\phi\,d\lambda\f$ in terms of \f$\sigma\f$ is a little more complicated with great ellipses. (Don't worry about the addition of \f$1\f$ to \f$t(x)\f$; that's immaterial.) - the factors involving \f$n\f$ in the expression for \f$k\f$ in terms of \f$\epsilon\f$. This is because \f$k\f$ is defined in terms of \f$e'\f$, whereas it is \f$e\cos\gamma_0\f$ that plays the role of the eccentricity for the great ellipse. Here is the series expansion accurate to 10th order, found by gearea.mac: \verbatim G4[0] = + (1/6 + 7/30 * n + 8/105 * n^2 + 4/315 * n^3 + 16/3465 * n^4 + 20/9009 * n^5 + 8/6435 * n^6 + 28/36465 * n^7 + 32/62985 * n^8 + 4/11305 * n^9) - (3/40 + 12/35 * n + 589/840 * n^2 + 1063/1155 * n^3 + 14743/15015 * n^4 + 14899/15015 * n^5 + 254207/255255 * n^6 + 691127/692835 * n^7 + 1614023/1616615 * n^8) * eps + (67/280 + 7081/5040 * n + 5519/1320 * n^2 + 6417449/720720 * n^3 + 708713/45045 * n^4 + 2700154/109395 * n^5 + 519037063/14549535 * n^6 + 78681626/1616615 * n^7) * eps^2 - (29597/40320 + 30013/5280 * n + 33759497/1441440 * n^2 + 100611307/1441440 * n^3 + 16639623457/98017920 * n^4 + 3789780779/10581480 * n^5 + 1027832503/1511640 * n^6) * eps^3 + (357407/147840 + 19833349/823680 * n + 61890679/480480 * n^2 + 97030756063/196035840 * n^3 + 2853930388817/1862340480 * n^4 + 15123282583393/3724680960 * n^5) * eps^4 - (13200233/1537536 + 306285589/2882880 * n + 26279482199/37340160 * n^2 + 3091446335399/931170240 * n^3 + 93089556575647/7449361920 * n^4) * eps^5 + (107042267/3294720 + 253176989449/522762240 * n + 57210830762263/14898723840 * n^2 + 641067300459403/29797447680 * n^3) * eps^6 - (51544067373/398295040 + 38586720036247/17027112960 * n + 104152290127363/4966241280 * n^2) * eps^7 + (369575321823/687964160 + 1721481081751393/158919720960 * n) * eps^8 - 10251814360817/4445306880 * eps^9; G4[1] = + (1/120 + 4/105 * n + 589/7560 * n^2 + 1063/10395 * n^3 + 14743/135135 * n^4 + 14899/135135 * n^5 + 254207/2297295 * n^6 + 691127/6235515 * n^7 + 1614023/14549535 * n^8) * eps - (53/1680 + 847/4320 * n + 102941/166320 * n^2 + 1991747/1441440 * n^3 + 226409/90090 * n^4 + 3065752/765765 * n^5 + 24256057/4157010 * n^6 + 349229428/43648605 * n^7) * eps^2 + (4633/40320 + 315851/332640 * n + 5948333/1441440 * n^2 + 11046565/864864 * n^3 + 9366910279/294053760 * n^4 + 23863367599/349188840 * n^5 + 45824943037/349188840 * n^6) * eps^3 - (8021/18480 + 39452953/8648640 * n + 3433618/135135 * n^2 + 29548772933/294053760 * n^3 + 44355142973/139675536 * n^4 + 4771229132843/5587021440 * n^5) * eps^4 + (2625577/1537536 + 5439457/247104 * n + 353552588953/2352430080 * n^2 + 405002114215/558702144 * n^3 + 61996934629789/22348085760 * n^4) * eps^5 - (91909777/13178880 + 2017395395921/18819440640 * n + 51831652526149/59594895360 * n^2 + 1773086701957889/357569372160 * n^3) * eps^6 + (35166639971/1194885120 + 26948019211109/51081338880 * n + 7934238355871/1596291840 * n^2) * eps^7 - (131854991623/1031946240 + 312710596037369/119189790720 * n) * eps^8 + 842282436291/1481768960 * eps^9; G4[2] = + (1/560 + 29/2016 * n + 1027/18480 * n^2 + 203633/1441440 * n^3 + 124051/450450 * n^4 + 1738138/3828825 * n^5 + 98011493/145495350 * n^6 + 4527382/4849845 * n^7) * eps^2 - (533/40320 + 14269/110880 * n + 908669/1441440 * n^2 + 15253627/7207200 * n^3 + 910103119/163363200 * n^4 + 2403810527/193993800 * n^5 + 746888717/30630600 * n^6) * eps^3 + (2669/36960 + 2443153/2882880 * n + 1024791/200200 * n^2 + 10517570057/490089600 * n^3 + 164668999127/2327925600 * n^4 + 1826633124599/9311702400 * n^5) * eps^4 - (5512967/15375360 + 28823749/5765760 * n + 31539382001/871270400 * n^2 + 1699098121381/9311702400 * n^3 + 287618085731/398361600 * n^4) * eps^5 + (22684703/13178880 + 25126873327/896163840 * n + 10124249914577/42567782400 * n^2 + 836412216748957/595948953600 * n^3) * eps^6 - (3259030001/398295040 + 2610375232847/17027112960 * n + 2121882247763/1418926080 * n^2) * eps^7 + (13387413913/343982080 + 939097138279/1135140864 * n) * eps^8 - 82722916855/444530688 * eps^9; G4[3] = + (5/8064 + 23/3168 * n + 1715/41184 * n^2 + 76061/480480 * n^3 + 812779/1782144 * n^4 + 9661921/8953560 * n^5 + 40072069/18106088 * n^6) * eps^3 - (409/59136 + 10211/109824 * n + 46381/73920 * n^2 + 124922951/43563520 * n^3 + 12524132449/1241560320 * n^4 + 30022391821/1022461440 * n^5) * eps^4 + (22397/439296 + 302399/384384 * n + 461624513/74680320 * n^2 + 1375058687/41385344 * n^3 + 4805085120841/34763688960 * n^4) * eps^5 - (14650421/46126080 + 17533571183/3136573440 * n + 1503945368767/29797447680 * n^2 + 43536234862451/139054755840 * n^3) * eps^6 + (5074867067/2788065280 + 479752611137/13243310080 * n + 1228808683449/3310827520 * n^2) * eps^7 - (12004715823/1203937280 + 17671119291563/79459860480 * n) * eps^8 + 118372499107/2222653440 * eps^9; G4[4] = + (7/25344 + 469/109824 * n + 13439/411840 * n^2 + 9282863/56010240 * n^3 + 37558503/59121920 * n^4 + 44204289461/22348085760 * n^5) * eps^4 - (5453/1317888 + 58753/823680 * n + 138158857/224040960 * n^2 + 191056103/53209728 * n^3 + 712704605341/44696171520 * n^4) * eps^5 + (28213/732160 + 331920271/448081920 * n + 2046013913/283785216 * n^2 + 11489035343/241274880 * n^3) * eps^6 - (346326947/1194885120 + 11716182499/1891901440 * n + 860494893431/12770334720 * n^2) * eps^7 + (750128501/386979840 + 425425087409/9287516160 * n) * eps^8 - 80510858479/6667960320 * eps^9; G4[5] = + (21/146432 + 23/8320 * n + 59859/2263040 * n^2 + 452691/2687360 * n^3 + 21458911/26557440 * n^4) * eps^5 - (3959/1464320 + 516077/9052160 * n + 51814927/85995520 * n^2 + 15444083489/3611811840 * n^3) * eps^6 + (1103391/36208640 + 120920041/171991040 * n + 18522863/2263040 * n^2) * eps^7 - (92526613/343982080 + 24477436759/3611811840 * n) * eps^8 + 1526273559/740884480 * eps^9; G4[6] = + (11/133120 + 1331/696320 * n + 145541/6615040 * n^2 + 46863487/277831680 * n^3) * eps^6 - (68079/36208640 + 621093/13230080 * n + 399883/680960 * n^2) * eps^7 + (658669/26460160 + 186416197/277831680 * n) * eps^8 - 748030679/2963537920 * eps^9; G4[7] = + (143/2785280 + 11011/7938048 * n + 972829/52093440 * n^2) * eps^7 - (434863/317521920 + 263678129/6667960320 * n) * eps^8 + 185257501/8890613760 * eps^9; G4[8] = + (715/21168128 + 27313/26148864 * n) * eps^8 - 1838551/1778122752 * eps^9; G4[9] = + 2431/104595456 * eps^9; \endverbatim \section gevsgeodesic Great ellipses vs geodesics Some papers advocating the use of great ellipses for navigation exhibit a prejudice against the use of geodesics. These excerpts from Pallikaris, Tsoulos, & Paradissis (2009) give the flavor - … it is required to adopt realistic accuracy standards in order not only to eliminate the significant errors of the spherical model but also to avoid the exaggerated and unrealistic requirements of sub meter accuracy. - Calculation of shortest sailings paths on the ellipsoid by a geodetic inverse method involve formulas that are much too complex. - Despite the fact that contemporary computers are fast enough to handle more complete geodetic formulas of sub meter accuracy, a basic principle for the design of navigational systems is the avoidance of unnecessary consumption of computing power. . This prejudice was probably due to the fact that the most well-known algorithms for geodesics, by Vincenty (1975), come with some "asterisks": - no derivation was given (although they follow in a straightforward fashion from classic 19th century methods); - the accuracy is "only" 0.5 mm or so, surely good enough for most applications, but still a reason for a user to worry and a spur to numerous studies "validating" the algorithms; - no indication is given for how to extend the series to improve the accuracy; - there was a belief in some quarters (erroneous!) that the Vincenty algorithms could not be used to compute waypoints; - the algorithm for the inverse problem fails to converge for some inputs. . These problems meant that users were reluctant to bundle the algorithms into a library and treat them as a part of the software infrastructure (much as you might regard the computation of \f$\sin x\f$ as a given). In particular, I regard the last issue, lack of convergence of the inverse solution, as fatal. Even though the problem only arises for nearly antipodal points, it means all users of the library must have some way to handle this problem. For these reasons, substitution of a great ellipse for the geodesic makes some sense. The solution of the great ellipse is, in principle, no more difficult than solving for the great circle and, for paths of less then 10000 km, the error in the distance is less than 13.5 m. Now (2014), however, the situation has reversed. The algorithms given by Karney (2013)—and used in GeographicLib since 2009—explicitly resolve the issues with Vincenty's algorithm. The geodesic problem is conveniently bundled into a library. Users can call this with an assurance of an accurate result much as they would when evaluating \f$\sin x\f$. On the other hand, great ellipses come with their own set of asterisks: - To the extent that they are regarded as approximations to geodesics, the errors need to be quantified, the limits of allowable use documented, etc. - The user is now left with decisions on when to trust the results and to find alternative solutions if necessary. - Even though the great ellipse is no more that 13.5 m longer than a 10000 km geodesic, the path of the great ellipse can deviate from the geodesic by as much as 8.3 km. This disqualifies great ellipses from use in congested air corridors where the strategic lateral offset procedure is in effect and in any situation which demands coordination in the routes of vessels. - Because geodesics obey the triangle inequality, while great ellipses do not, the solutions for realistic navigational problems, e.g., determining the time of closest approach of two vessels, are often simpler in terms of geodesics. To address some other of the objections in the quotes from Pallikaris et al. given above: - "exaggerated and unrealistic requirements of sub meter accuracy": The geodesic algorithms allow full double precision accuracy at essentially no cost. This is because Clenshaw summation allows additional terms to be added to the series without the need for addition trigonometric evaluations. Full accuracy is important to maintain because it allows the results to be used reliably in more complex problems (e.g., in the determination of maritime boundaries). - "unnecessary consumption of computing power": The solution of the inverse geodesic problem takes 2.3 μs; multiple points on a geodesic can be computed at a rate of one point per 0.4 μs. The actual power consumed in these calculations is minuscule compared to the power needed to drive the display of a navigational computer. - "formulas that are much too complex": There's no question that the solution of the geodesic problem is more complex than for great ellipses. However this complexity is only an issue when implementing the algorithms. For the end user, navigational software employing geodesics is less complex compared with that employing great ellipses. Here is what the user needs to know about the geodesic solution:
"The shortest path is found."
And here is the corresponding documentation for great ellipses:
"A path which closely approximates the shortest path is found. Provided that the distance is less than 10000 km, the error in distance is no more than 14 m and the deviation the route from that of the shortest path is no more than 9 km. These bounds apply to the WGS84 ellipsoid. The deviation of the path means that it should be used with caution when planning routes. In addition, great ellipses do not obey the triangle inequality; this disqualifies them from use in some applications."
Having all the geodesic functions bundled up into a reliable "black box" enables users to concentrate on how to solve problems using geodesics (instead of figuring out how to solve for the geodesics). A wide range of problems (intersection of paths, the path for an interception, the time of closest approach, median lines, tri-points, etc.) are all amenable to simple and fast solutions in terms of geodesics.
Back to \ref rhumb. Forward to \ref transversemercator. Up to \ref contents.
**********************************************************************/ /** \page transversemercator Transverse Mercator projection
Back to \ref greatellipse. Forward to \ref geocentric. Up to \ref contents.
TransverseMercator and TransverseMercatorExact provide accurate implementations of the transverse Mercator projection. The TransverseMercatorProj utility provides an interface to these classes. Go to - \ref testmerc - \ref tmseries - \ref tmfigures References: - L. Krüger, Konforme Abbildung des Erdellipsoids in der Ebene (Conformal mapping of the ellipsoidal earth to the plane), Royal Prussian Geodetic Institute, New Series 52, 172 pp. (1912). - L. P. Lee, Conformal Projections Based on Elliptic Functions, (B. V. Gutsell, Toronto, 1976), 128pp., ISBN: 0919870163 (Also appeared as: Monograph 16, Suppl. No. 1 to Canadian Cartographer, Vol 13). Part V, pp. 67--101, Conformal Projections Based On Jacobian Elliptic Functions. - C. F. F. Karney, Transverse Mercator with an accuracy of a few nanometers, J. Geodesy 85(8), 475--485 (Aug. 2011); addenda: tm-addenda.html; preprint: arXiv:1002.1417; resource page: tm.html. . The algorithm for TransverseMercator is based on Krüger (1912); that for TransverseMercatorExact is based on Lee (1976). See tm-grid.kmz, for an illustration of the exact transverse Mercator grid in Google Earth. \section testmerc Test data for the transverse Mercator projection A test set for the transverse Mercator projection is available at - TMcoords.dat.gz - C. F. F. Karney, Test data for the transverse Mercator projection (2009),
DOI: 10.5281/zenodo.32470. . This is about 17 MB (compressed). This test set consists of a set of geographic coordinates together with the corresponding transverse Mercator coordinates. The WGS84 ellipsoid is used, with central meridian 0°, central scale factor 0.9996 (the UTM value), false easting = false northing = 0 m. Each line of the test set gives 6 space delimited numbers - latitude (degrees, exact) - longitude (degrees, exact — see below) - easting (meters, accurate to 0.1 pm) - northing (meters, accurate to 0.1 pm) - meridian convergence (degrees, accurate to 10−18 deg) - scale (accurate to 10−20) . The latitude and longitude are all multiples of 10−12 deg and should be regarded as exact, except that longitude = 82.63627282416406551 should be interpreted as exactly (1 − \e e) 90°. These results are computed using Lee's formulas with Maxima's bfloats and fpprec set to 80 (so the errors in the data are probably 1/2 of the values quoted above). The Maxima code, tm.mac and ellint.mac, was used to prepare this data set is included in the distribution; you will need to have Maxima installed to use this code. The comments at the top of tm.mac illustrate how to run it. The contents of the file are as follows: - 250000 entries randomly distributed in lat in [0°, 90°], lon in [0°, 90°]; - 1000 entries randomly distributed on lat in [0°, 90°], lon = 0°; - 1000 entries randomly distributed on lat = 0°, lon in [0°, 90°]; - 1000 entries randomly distributed on lat in [0°, 90°], lon = 90°; - 1000 entries close to lat = 90° with lon in [0°, 90°]; - 1000 entries close to lat = 0°, lon = 0° with lat ≥ 0°, lon ≥ 0°; - 1000 entries close to lat = 0°, lon = 90° with lat ≥ 0°, lon ≤ 90°; - 2000 entries close to lat = 0°, lon = (1 − \e e) 90° with lat ≥ 0°; - 25000 entries randomly distributed in lat in [−89°, 0°], lon in [(1 − \e e) 90°, 90°]; - 1000 entries randomly distributed on lat in [−89°, 0°], lon = 90°; - 1000 entries randomly distributed on lat in [−89°, 0°], lon = (1 − \e e) 90°; - 1000 entries close to lat = 0°, lon = 90° (lat < 0°, lon ≤ 90°); - 1000 entries close to lat = 0°, lon = (1 − \e e) 90° (lat < 0°, lon ≤ (1 − \e e) 90°); . (a total of 287000 entries). The entries for lat < 0° and lon in [(1 − \e e) 90°, 90°] use the "extended" domain for the transverse Mercator projection explained in Sec. 5 of Karney (2011). The first 258000 entries have lat ≥ 0° and are suitable for testing implementations following the standard convention. \section tmseries Series approximation for transverse Mercator Krüger (1912) gives a 4th-order approximation to the transverse Mercator projection. This is accurate to about 200 nm (200 nanometers) within the UTM domain. Here we present the series extended to 10th order. By default, TransverseMercator uses the 6th-order approximation. The preprocessor macro GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER can be used to select an order from 4 thru 8. The series expanded to order n30 are given in tmseries30.html. In the formulas below ^ indicates exponentiation (n^3 = n*n*n) and / indicates real division (3/5 = 0.6). The equations need to be converted to Horner form, but are here left in expanded form so that they can be easily truncated to lower order in \e n. Some of the integers here are not representable as 32-bit integers and will need to be included as 64-bit integers. \e A in Krüger, p. 12, eq. (5) \verbatim A = a/(n + 1) * (1 + 1/4 * n^2 + 1/64 * n^4 + 1/256 * n^6 + 25/16384 * n^8 + 49/65536 * n^10); \endverbatim γ in Krüger, p. 21, eq. (41) \verbatim alpha[1] = 1/2 * n - 2/3 * n^2 + 5/16 * n^3 + 41/180 * n^4 - 127/288 * n^5 + 7891/37800 * n^6 + 72161/387072 * n^7 - 18975107/50803200 * n^8 + 60193001/290304000 * n^9 + 134592031/1026432000 * n^10; alpha[2] = 13/48 * n^2 - 3/5 * n^3 + 557/1440 * n^4 + 281/630 * n^5 - 1983433/1935360 * n^6 + 13769/28800 * n^7 + 148003883/174182400 * n^8 - 705286231/465696000 * n^9 + 1703267974087/3218890752000 * n^10; alpha[3] = 61/240 * n^3 - 103/140 * n^4 + 15061/26880 * n^5 + 167603/181440 * n^6 - 67102379/29030400 * n^7 + 79682431/79833600 * n^8 + 6304945039/2128896000 * n^9 - 6601904925257/1307674368000 * n^10; alpha[4] = 49561/161280 * n^4 - 179/168 * n^5 + 6601661/7257600 * n^6 + 97445/49896 * n^7 - 40176129013/7664025600 * n^8 + 138471097/66528000 * n^9 + 48087451385201/5230697472000 * n^10; alpha[5] = 34729/80640 * n^5 - 3418889/1995840 * n^6 + 14644087/9123840 * n^7 + 2605413599/622702080 * n^8 - 31015475399/2583060480 * n^9 + 5820486440369/1307674368000 * n^10; alpha[6] = 212378941/319334400 * n^6 - 30705481/10378368 * n^7 + 175214326799/58118860800 * n^8 + 870492877/96096000 * n^9 - 1328004581729009/47823519744000 * n^10; alpha[7] = 1522256789/1383782400 * n^7 - 16759934899/3113510400 * n^8 + 1315149374443/221405184000 * n^9 + 71809987837451/3629463552000 * n^10; alpha[8] = 1424729850961/743921418240 * n^8 - 256783708069/25204608000 * n^9 + 2468749292989891/203249958912000 * n^10; alpha[9] = 21091646195357/6080126976000 * n^9 - 67196182138355857/3379030566912000 * n^10; alpha[10]= 77911515623232821/12014330904576000 * n^10; \endverbatim β in Krüger, p. 18, eq. (26*) \verbatim beta[1] = 1/2 * n - 2/3 * n^2 + 37/96 * n^3 - 1/360 * n^4 - 81/512 * n^5 + 96199/604800 * n^6 - 5406467/38707200 * n^7 + 7944359/67737600 * n^8 - 7378753979/97542144000 * n^9 + 25123531261/804722688000 * n^10; beta[2] = 1/48 * n^2 + 1/15 * n^3 - 437/1440 * n^4 + 46/105 * n^5 - 1118711/3870720 * n^6 + 51841/1209600 * n^7 + 24749483/348364800 * n^8 - 115295683/1397088000 * n^9 + 5487737251099/51502252032000 * n^10; beta[3] = 17/480 * n^3 - 37/840 * n^4 - 209/4480 * n^5 + 5569/90720 * n^6 + 9261899/58060800 * n^7 - 6457463/17740800 * n^8 + 2473691167/9289728000 * n^9 - 852549456029/20922789888000 * n^10; beta[4] = 4397/161280 * n^4 - 11/504 * n^5 - 830251/7257600 * n^6 + 466511/2494800 * n^7 + 324154477/7664025600 * n^8 - 937932223/3891888000 * n^9 - 89112264211/5230697472000 * n^10; beta[5] = 4583/161280 * n^5 - 108847/3991680 * n^6 - 8005831/63866880 * n^7 + 22894433/124540416 * n^8 + 112731569449/557941063680 * n^9 - 5391039814733/10461394944000 * n^10; beta[6] = 20648693/638668800 * n^6 - 16363163/518918400 * n^7 - 2204645983/12915302400 * n^8 + 4543317553/18162144000 * n^9 + 54894890298749/167382319104000 * n^10; beta[7] = 219941297/5535129600 * n^7 - 497323811/12454041600 * n^8 - 79431132943/332107776000 * n^9 + 4346429528407/12703122432000 * n^10; beta[8] = 191773887257/3719607091200 * n^8 - 17822319343/336825216000 * n^9 - 497155444501631/1422749712384000 * n^10; beta[9] = 11025641854267/158083301376000 * n^9 - 492293158444691/6758061133824000 * n^10; beta[10]= 7028504530429621/72085985427456000 * n^10; \endverbatim The high-order expansions for α and β were produced by the Maxima program tmseries.mac (included in the distribution). To run, start Maxima and enter \verbatim load("tmseries.mac")$ \endverbatim Further instructions are included at the top of the file. \section tmfigures Figures from paper on transverse Mercator projection This section gives color versions of the figures in - C. F. F. Karney, Transverse Mercator with an accuracy of a few nanometers, J. Geodesy 85(8), 475--485 (Aug. 2011); addenda: tm-addenda.html; preprint: arXiv:1002.1417; resource page: tm.html. \b NOTE: The numbering of the figures matches that in the paper cited above. The figures in this section are relatively small in order to allow them to be displayed quickly. Vector versions of these figures are available in tm-figs.pdf. This allows you to magnify the figures to show the details more clearly. \image html gauss-schreiber-graticule-a.png "Fig. 1(a)" Fig. 1(a): The graticule for the spherical transverse Mercator projection. The equator lies on \e y = 0. Compare this with Lee, Fig. 1 (right), which shows the graticule for half a sphere, but note that in his notation \e x and \e y have switched meanings. The graticule for the ellipsoid differs from that for a sphere only in that the latitude lines have shifted slightly. (The conformal transformation from an ellipsoid to a sphere merely relabels the lines of latitude.) This projection places the point latitude = 0°, longitude = 90° at infinity. \image html gauss-krueger-graticule-a.png "Fig. 1(b)" Fig. 1(b): The graticule for the Gauss-Krüger transverse Mercator projection. The equator lies on \e y = 0 for longitude < 81°; beyond this, it arcs up to meet \e y = 1. Compare this with Lee, Fig. 45 (upper), which shows the graticule for the International Ellipsoid. Lee, Fig. 46, shows the graticule for the entire ellipsoid. This projection (like the Thompson projection) projects the ellipsoid to a finite area. \image html thompson-tm-graticule-a.png "Fig. 1(c)" Fig. 1(c): The graticule for the Thompson transverse Mercator projection. The equator lies on \e y = 0 for longitude < 81°; at longitude = 81°, it turns by 120° and heads for \e y = 1. Compare this with Lee, Fig. 43, which shows the graticule for the International Ellipsoid. Lee, Fig. 44, shows the graticule for the entire ellipsoid. This projection (like the Gauss-Krüger projection) projects the ellipsoid to a finite area. \image html gauss-krueger-error.png "Fig. 2" Fig. 2: The truncation error for the series for the Gauss-Krüger transverse Mercator projection. The blue curves show the truncation error for the order of the series \e J = 2 (top) thru \e J = 12 (bottom). The red curves show the combined truncation and round-off errors for - float and \e J = 4 (top) - double and \e J = 6 (middle) - long double and \e J = 8 (bottom) \image html gauss-krueger-graticule.png "Fig. 3(a)" Fig. 3(a): The graticule for the extended domain. The blue lines show latitude and longitude at multiples of 10°. The green lines show 1° intervals for longitude in [80°, 90°] and latitude in [−5°, 10°]. \image html gauss-krueger-convergence-scale.png "Fig. 3(b)" Fig. 3(b): The convergence and scale for the Gauss-Krüger transverse Mercator projection in the extended domain. The blue lines emanating from the top left corner (the north pole) are lines of constant convergence. Convergence = 0° is given by the dog-legged line joining the points (0,1), (0,0), (1.71,0), (1.71,−∞). Convergence = 90° is given by the line y = 1. The other lines show multiples of 10° between 0° and 90°. The other blue, the green and the black lines show scale = 1 thru 2 at intervals of 0.1, 2 thru 15 at intervals of 1, and 15 thru 35 at intervals of 5. Multiples of 5 are shown in black, multiples of 1 are shown in blue, and the rest are shown in green. Scale = 1 is given by the line segment (0,0) to (0,1). The red line shows the equator between lon = 81° and 90°. The scale and convergence at the branch point are 1/\e e = 10 and 0°, respectively. \image html thompson-tm-graticule.png "Fig. 3(c)" Fig. 3(c): The graticule for the Thompson transverse Mercator projection for the extended domain. The range of the projection is the rectangular region shown - 0 ≤ \e u ≤ K(e2), 0 ≤ \e v ≤ K(1 − e2) . The coloring of the lines is the same as Fig. 3(a), except that latitude lines extended down to −10° and a red line has been added showing the line \e y = 0 for \e x > 1.71 in the Gauss-Krüger projection (Fig. 3(a)). The extended Thompson projection figure has reflection symmetry on all the four sides of Fig. 3(c).
Back to \ref greatellipse. Forward to \ref geocentric. Up to \ref contents.
**********************************************************************/ /** \page geocentric Geocentric coordinates
Back to \ref transversemercator. Forward to \ref auxlat. Up to \ref contents.
The implementation of Geocentric::Reverse is adapted from - H. Vermeille, Direct transformation from geocentric coordinates to geodetic coordinates, J. Geodesy 76, 451--454 (2002). This provides a closed-form solution but can't directly be applied close to the center of the earth. Several changes have been made to remove this restriction and to improve the numerical accuracy. Now the method is accurate for all inputs (even if \e h is infinite). The changes are described in Appendix B of - C. F. F. Karney, Geodesics on an ellipsoid of revolution, Feb. 2011; preprint arxiv:1102.1215v1. . Vermeille similarly updated his method in - H. Vermeille, An analytical method to transform geocentric into geodetic coordinates, J. Geodesy 85, 105--117 (2011). The problems encountered near the center of the ellipsoid are: - There's a potential division by zero in the definition of \e s. The equations are easily reformulated to avoid this problem. - t3 may be negative. This is OK; we just take the real root. - The solution for \e t may be complex. However this leads to 3 real roots for u/\e r. It's then just a matter of picking the one that computes the geodetic result which minimizes |h| and which avoids large round-off errors. - Some of the equations result in a large loss of accuracy due to subtracting nearly equal quantities. E.g., \e k = sqrt(\e u + \e v + w2) − \e w is inaccurate if \e u + \e v is small; we can fix this by writing \e k = (\e u + \e v)/(sqrt(\e u + \e v + w2) + \e w). The error is computed as follows. Write a version of Geocentric::WGS84.Forward which uses long doubles (including using long doubles for the WGS84 parameters). Generate random (long double) geodetic coordinates (\e lat0, \e lon0, \e h0) and use the "long double" WGS84.Forward to obtain the corresponding (long double) geocentric coordinates (\e x0, \e y0, \e z0). [We restrict \e h0 so that \e h0 ≥ − \e a (1 − e2) / sqrt(1 − e2 sin2\e lat0), which ensures that (\e lat0, \e lon0, \e h0) is the principal geodetic inverse of (\e x0, \e y0, \e z0).] Because the forward calculation is numerically stable and because long doubles (on Linux systems using g++) provide 11 bits additional accuracy (about 3.3 decimal digits), we regard this set of test data as exact. Apply the double version of WGS84.Reverse to (\e x0, \e y0, \e z0) to compute the approximate geodetic coordinates (\e lat1, \e lon1, \e h1). Convert (\e lat1 − \e lat0, \e lon1 − \e lon0) to a distance, \e ds, on the surface of the ellipsoid and define \e err = hypot(\e ds, \e h1 − \e h0). For |h0| < 5000 km, we have \e err < 7 nm (7 nanometers). This methodology is not very useful very far from the globe, because the absolute errors in the approximate geodetic height become large, or within 50 km of the center of the earth, because of errors in computing the approximate geodetic latitude. To illustrate the second issue, the maximum value of \e err for \e h0 < 0 is about 80 mm. The error is maximum close to the circle given by geocentric coordinates satisfying hypot(\e x, \e y) = \e a e2 (= 42.7 km), \e z = 0. (This is the center of meridional curvature for \e lat = 0.) The geodetic latitude for these points is \e lat = 0. However, if we move 1 nm towards the center of the earth, the geodetic latitude becomes 0.04", a distance of 1.4 m from the equator. If, instead, we move 1 nm up, the geodetic latitude becomes 7.45", a distance of 229 m from the equator. In light of this, Reverse does quite well in this vicinity. To obtain a practical measure of the error for the general case we define - errh = |\e h1 − h0| / max(1, \e h0 / \e a) - for \e h0 > 0, errout = \e ds - for \e h0 < 0, apply the long double version of WGS84.Forward to (\e lat1, \e lon1, \e h1) to give (\e x1, \e y1, \e z1) and compute errin = hypot(\e x1 − \e x0, \e y1 − \e y0, \e z1 − \e z0). . We then find errh < 8 nm, errout < 4 nm, and errin < 7 nm (1 nm = 1 nanometer). The testing has been confined to the WGS84 ellipsoid. The method will work for all ellipsoids used in terrestrial geodesy. However, the central region, which leads to multiple real roots for the cubic equation in Reverse, pokes outside the ellipsoid (at the poles) for ellipsoids with \e e > 1/sqrt(2); Reverse has not been analyzed for this case. Similarly ellipsoids which are very nearly spherical may yield inaccurate results due to underflow; in the other hand, the case of the sphere, \e f = 0, is treated specially and gives accurate results. Other comparable methods are K. M. Borkowski, Transformation of geocentric to geodetic coordinates without approximations, Astrophys. Space Sci. 139, 1--4 (1987) ( erratum) and T. Fukushima, Fast transform from geocentric to geodetic coordinates, J. Geodesy 73, 603--610 (1999). However the choice of independent variables in these methods leads to a loss of accuracy for points near the equatorial plane.
Back to \ref transversemercator. Forward to \ref auxlat. Up to \ref contents.
**********************************************************************/ /** \page auxlat Auxiliary latitudes
Back to \ref geocentric. Forward to \ref highprec. Up to \ref contents.
Go to - \ref auxlatformula - \ref auxlattable - \ref auxlaterror Six latitudes are used by GeographicLib: - φ, the (geographic) latitude; - β, the parametric latitude; - θ, the geocentric latitude; - μ, the rectifying latitude; - χ, the conformal latitude; - ξ, the authalic latitude. . The last five of these are called auxiliary latitudes. These quantities are all defined in the Wikipedia article on latitudes. The Ellipsoid class contains methods for converting all of these and the geographic latitude. In addition there's the isometric latitude, ψ, defined by ψ = gd−1χ = sinh−1 tanχ and χ = gdψ = tan−1 sinhψ. This is not an angle-like variable (for example, it diverges at the poles) and so we don't treat it further here. However conversions between ψ and any of the auxiliary latitudes is easily accomplished via an intermediate conversion to χ. The relations between φ, β, and θ are all simple elementary functions. The latitudes χ and ξ can be expressed as elementary functions of φ; however, these functions can only be inverted iteratively. The rectifying latitude μ as a function of φ (or β) involves the incomplete elliptic integral of the second kind (which is not an elementary function) and this needs to be inverted iteratively. The Ellipsoid class evaluates all the auxiliary latitudes (and the corresponding inverse relations) in terms of their basic definitions. An alternative method of evaluating these auxiliary latitudes is in terms of trigonometric series. This offers some advantages: - these series give a uniform way of expressing any latitude in terms of any other latitude; - the evaluation may be faster, particularly if Clenshaw summation is used; - provided that the flattening is sufficiently small, the result may be more accurate (because the round-off errors are smaller). Here we give the complete matrix of relations between all six latitudes; there are 30 (= 6 × 5) such relations. These expansions complement the work of - O. S. Adams, Latitude developments connected with geodesy and cartography, Spec. Pub. 67 (US Coast and Geodetic Survey, 1921). - P. Osborne, The Mercator Projections (2013), Chap. 5. - S. Orihuela, Funciones de Latitud (2013). . Here, the expansions are in terms of the third flattening n = (a − b)/(a + b). This choice of expansion parameter results in expansions in which half the coefficients vanish for all relations between φ, β, θ, and μ. In addition, the expansions converge for b/a ∈ (0, ∞). These expansions were obtained with the the maxima code, auxlat.mac. Adams (1921) uses the eccentricity squared e2 as the expansion parameter, but the resulting series only converge for b/a ∈ (0, √2). In addition, it is shown in \ref auxlaterror, that the errors when the series are truncated are much worse than for the corresponding series in \e n. \section auxlatformula Series approximations for conversions Here are the relations between φ, β, θ, and μ carried out to 4th order in n: \f[ \begin{align} \beta-\phi&=\textstyle{} -n\sin 2\phi +\frac{1}{2}n^{2}\sin 4\phi -\frac{1}{3}n^{3}\sin 6\phi +\frac{1}{4}n^{4}\sin 8\phi -\ldots\\ \phi-\beta&=\textstyle{} +n\sin 2\beta +\frac{1}{2}n^{2}\sin 4\beta +\frac{1}{3}n^{3}\sin 6\beta +\frac{1}{4}n^{4}\sin 8\beta +\ldots\\ \theta-\phi&=\textstyle{} -\bigl(2n-2n^{3}\bigr)\sin 2\phi +\bigl(2n^{2}-4n^{4}\bigr)\sin 4\phi -\frac{8}{3}n^{3}\sin 6\phi +4n^{4}\sin 8\phi -\ldots\\ \phi-\theta&=\textstyle{} +\bigl(2n-2n^{3}\bigr)\sin 2\theta +\bigl(2n^{2}-4n^{4}\bigr)\sin 4\theta +\frac{8}{3}n^{3}\sin 6\theta +4n^{4}\sin 8\theta +\ldots\\ \theta-\beta&=\textstyle{} -n\sin 2\beta +\frac{1}{2}n^{2}\sin 4\beta -\frac{1}{3}n^{3}\sin 6\beta +\frac{1}{4}n^{4}\sin 8\beta -\ldots\\ \beta-\theta&=\textstyle{} +n\sin 2\theta +\frac{1}{2}n^{2}\sin 4\theta +\frac{1}{3}n^{3}\sin 6\theta +\frac{1}{4}n^{4}\sin 8\theta +\ldots\\ \mu-\phi&=\textstyle{} -\bigl(\frac{3}{2}n-\frac{9}{16}n^{3}\bigr)\sin 2\phi +\bigl(\frac{15}{16}n^{2}-\frac{15}{32}n^{4}\bigr)\sin 4\phi -\frac{35}{48}n^{3}\sin 6\phi +\frac{315}{512}n^{4}\sin 8\phi -\ldots\\ \phi-\mu&=\textstyle{} +\bigl(\frac{3}{2}n-\frac{27}{32}n^{3}\bigr)\sin 2\mu +\bigl(\frac{21}{16}n^{2}-\frac{55}{32}n^{4}\bigr)\sin 4\mu +\frac{151}{96}n^{3}\sin 6\mu +\frac{1097}{512}n^{4}\sin 8\mu +\ldots\\ \mu-\beta&=\textstyle{} -\bigl(\frac{1}{2}n-\frac{3}{16}n^{3}\bigr)\sin 2\beta -\bigl(\frac{1}{16}n^{2}-\frac{1}{32}n^{4}\bigr)\sin 4\beta -\frac{1}{48}n^{3}\sin 6\beta -\frac{5}{512}n^{4}\sin 8\beta -\ldots\\ \beta-\mu&=\textstyle{} +\bigl(\frac{1}{2}n-\frac{9}{32}n^{3}\bigr)\sin 2\mu +\bigl(\frac{5}{16}n^{2}-\frac{37}{96}n^{4}\bigr)\sin 4\mu +\frac{29}{96}n^{3}\sin 6\mu +\frac{539}{1536}n^{4}\sin 8\mu +\ldots\\ \mu-\theta&=\textstyle{} +\bigl(\frac{1}{2}n+\frac{13}{16}n^{3}\bigr)\sin 2\theta -\bigl(\frac{1}{16}n^{2}-\frac{33}{32}n^{4}\bigr)\sin 4\theta -\frac{5}{16}n^{3}\sin 6\theta -\frac{261}{512}n^{4}\sin 8\theta -\ldots\\ \theta-\mu&=\textstyle{} -\bigl(\frac{1}{2}n+\frac{23}{32}n^{3}\bigr)\sin 2\mu +\bigl(\frac{5}{16}n^{2}-\frac{5}{96}n^{4}\bigr)\sin 4\mu +\frac{1}{32}n^{3}\sin 6\mu +\frac{283}{1536}n^{4}\sin 8\mu +\ldots\\ \end{align} \f] Here are the remaining relations (including χ and ξ) carried out to 3rd order in n: \f[ \begin{align} \chi-\phi&=\textstyle{} -\bigl(2n-\frac{2}{3}n^{2}-\frac{4}{3}n^{3}\bigr)\sin 2\phi +\bigl(\frac{5}{3}n^{2}-\frac{16}{15}n^{3}\bigr)\sin 4\phi -\frac{26}{15}n^{3}\sin 6\phi +\ldots\\ \phi-\chi&=\textstyle{} +\bigl(2n-\frac{2}{3}n^{2}-2n^{3}\bigr)\sin 2\chi +\bigl(\frac{7}{3}n^{2}-\frac{8}{5}n^{3}\bigr)\sin 4\chi +\frac{56}{15}n^{3}\sin 6\chi +\ldots\\ \chi-\beta&=\textstyle{} -\bigl(n-\frac{2}{3}n^{2}\bigr)\sin 2\beta +\bigl(\frac{1}{6}n^{2}-\frac{2}{5}n^{3}\bigr)\sin 4\beta -\frac{1}{15}n^{3}\sin 6\beta +\ldots\\ \beta-\chi&=\textstyle{} +\bigl(n-\frac{2}{3}n^{2}-\frac{1}{3}n^{3}\bigr)\sin 2\chi +\bigl(\frac{5}{6}n^{2}-\frac{14}{15}n^{3}\bigr)\sin 4\chi +\frac{16}{15}n^{3}\sin 6\chi +\ldots\\ \chi-\theta&=\textstyle{} +\bigl(\frac{2}{3}n^{2}+\frac{2}{3}n^{3}\bigr)\sin 2\theta -\bigl(\frac{1}{3}n^{2}-\frac{4}{15}n^{3}\bigr)\sin 4\theta -\frac{2}{5}n^{3}\sin 6\theta -\ldots\\ \theta-\chi&=\textstyle{} -\bigl(\frac{2}{3}n^{2}+\frac{2}{3}n^{3}\bigr)\sin 2\chi +\bigl(\frac{1}{3}n^{2}-\frac{4}{15}n^{3}\bigr)\sin 4\chi +\frac{2}{5}n^{3}\sin 6\chi +\ldots\\ \chi-\mu&=\textstyle{} -\bigl(\frac{1}{2}n-\frac{2}{3}n^{2}+\frac{37}{96}n^{3}\bigr)\sin 2\mu -\bigl(\frac{1}{48}n^{2}+\frac{1}{15}n^{3}\bigr)\sin 4\mu -\frac{17}{480}n^{3}\sin 6\mu -\ldots\\ \mu-\chi&=\textstyle{} +\bigl(\frac{1}{2}n-\frac{2}{3}n^{2}+\frac{5}{16}n^{3}\bigr)\sin 2\chi +\bigl(\frac{13}{48}n^{2}-\frac{3}{5}n^{3}\bigr)\sin 4\chi +\frac{61}{240}n^{3}\sin 6\chi +\ldots\\ \xi-\phi&=\textstyle{} -\bigl(\frac{4}{3}n+\frac{4}{45}n^{2}-\frac{88}{315}n^{3}\bigr)\sin 2\phi +\bigl(\frac{34}{45}n^{2}+\frac{8}{105}n^{3}\bigr)\sin 4\phi -\frac{1532}{2835}n^{3}\sin 6\phi +\ldots\\ \phi-\xi&=\textstyle{} +\bigl(\frac{4}{3}n+\frac{4}{45}n^{2}-\frac{16}{35}n^{3}\bigr)\sin 2\xi +\bigl(\frac{46}{45}n^{2}+\frac{152}{945}n^{3}\bigr)\sin 4\xi +\frac{3044}{2835}n^{3}\sin 6\xi +\ldots\\ \xi-\beta&=\textstyle{} -\bigl(\frac{1}{3}n+\frac{4}{45}n^{2}-\frac{32}{315}n^{3}\bigr)\sin 2\beta -\bigl(\frac{7}{90}n^{2}+\frac{4}{315}n^{3}\bigr)\sin 4\beta -\frac{83}{2835}n^{3}\sin 6\beta -\ldots\\ \beta-\xi&=\textstyle{} +\bigl(\frac{1}{3}n+\frac{4}{45}n^{2}-\frac{46}{315}n^{3}\bigr)\sin 2\xi +\bigl(\frac{17}{90}n^{2}+\frac{68}{945}n^{3}\bigr)\sin 4\xi +\frac{461}{2835}n^{3}\sin 6\xi +\ldots\\ \xi-\theta&=\textstyle{} +\bigl(\frac{2}{3}n-\frac{4}{45}n^{2}+\frac{62}{105}n^{3}\bigr)\sin 2\theta +\bigl(\frac{4}{45}n^{2}-\frac{32}{315}n^{3}\bigr)\sin 4\theta -\frac{524}{2835}n^{3}\sin 6\theta -\ldots\\ \theta-\xi&=\textstyle{} -\bigl(\frac{2}{3}n-\frac{4}{45}n^{2}+\frac{158}{315}n^{3}\bigr)\sin 2\xi +\bigl(\frac{16}{45}n^{2}-\frac{16}{945}n^{3}\bigr)\sin 4\xi -\frac{232}{2835}n^{3}\sin 6\xi +\ldots\\ \xi-\mu&=\textstyle{} +\bigl(\frac{1}{6}n-\frac{4}{45}n^{2}-\frac{817}{10080}n^{3}\bigr)\sin 2\mu +\bigl(\frac{49}{720}n^{2}-\frac{2}{35}n^{3}\bigr)\sin 4\mu +\frac{4463}{90720}n^{3}\sin 6\mu +\ldots\\ \mu-\xi&=\textstyle{} -\bigl(\frac{1}{6}n-\frac{4}{45}n^{2}-\frac{121}{1680}n^{3}\bigr)\sin 2\xi -\bigl(\frac{29}{720}n^{2}-\frac{26}{945}n^{3}\bigr)\sin 4\xi -\frac{1003}{45360}n^{3}\sin 6\xi -\ldots\\ \xi-\chi&=\textstyle{} +\bigl(\frac{2}{3}n-\frac{34}{45}n^{2}+\frac{46}{315}n^{3}\bigr)\sin 2\chi +\bigl(\frac{19}{45}n^{2}-\frac{256}{315}n^{3}\bigr)\sin 4\chi +\frac{248}{567}n^{3}\sin 6\chi +\ldots\\ \chi-\xi&=\textstyle{} -\bigl(\frac{2}{3}n-\frac{34}{45}n^{2}+\frac{88}{315}n^{3}\bigr)\sin 2\xi +\bigl(\frac{1}{45}n^{2}-\frac{184}{945}n^{3}\bigr)\sin 4\xi -\frac{106}{2835}n^{3}\sin 6\xi -\ldots\\ \end{align} \f] \section auxlattable Series approximations in tabular form Finally, this is a listing of all the coefficients for the expansions carried out to 8th order in n. Here's how to interpret this data: the 5th line for φ − θ is [32/5, 0, -32, 0]; this means that the coefficient of sin(10θ) is [(32/5)n5 − 32n7 + O(n9)].

β − φ:
   [-1, 0, 0, 0, 0, 0, 0, 0]
   [1/2, 0, 0, 0, 0, 0, 0]
   [-1/3, 0, 0, 0, 0, 0]
   [1/4, 0, 0, 0, 0]
   [-1/5, 0, 0, 0]
   [1/6, 0, 0]
   [-1/7, 0]
   [1/8]

φ − β:
   [1, 0, 0, 0, 0, 0, 0, 0]
   [1/2, 0, 0, 0, 0, 0, 0]
   [1/3, 0, 0, 0, 0, 0]
   [1/4, 0, 0, 0, 0]
   [1/5, 0, 0, 0]
   [1/6, 0, 0]
   [1/7, 0]
   [1/8]

θ − φ:
   [-2, 0, 2, 0, -2, 0, 2, 0]
   [2, 0, -4, 0, 6, 0, -8]
   [-8/3, 0, 8, 0, -16, 0]
   [4, 0, -16, 0, 40]
   [-32/5, 0, 32, 0]
   [32/3, 0, -64]
   [-128/7, 0]
   [32]

φ − θ:
   [2, 0, -2, 0, 2, 0, -2, 0]
   [2, 0, -4, 0, 6, 0, -8]
   [8/3, 0, -8, 0, 16, 0]
   [4, 0, -16, 0, 40]
   [32/5, 0, -32, 0]
   [32/3, 0, -64]
   [128/7, 0]
   [32]

θ − β:
   [-1, 0, 0, 0, 0, 0, 0, 0]
   [1/2, 0, 0, 0, 0, 0, 0]
   [-1/3, 0, 0, 0, 0, 0]
   [1/4, 0, 0, 0, 0]
   [-1/5, 0, 0, 0]
   [1/6, 0, 0]
   [-1/7, 0]
   [1/8]

β − θ:
   [1, 0, 0, 0, 0, 0, 0, 0]
   [1/2, 0, 0, 0, 0, 0, 0]
   [1/3, 0, 0, 0, 0, 0]
   [1/4, 0, 0, 0, 0]
   [1/5, 0, 0, 0]
   [1/6, 0, 0]
   [1/7, 0]
   [1/8]

μ − φ:
   [-3/2, 0, 9/16, 0, -3/32, 0, 57/2048, 0]
   [15/16, 0, -15/32, 0, 135/2048, 0, -105/4096]
   [-35/48, 0, 105/256, 0, -105/2048, 0]
   [315/512, 0, -189/512, 0, 693/16384]
   [-693/1280, 0, 693/2048, 0]
   [1001/2048, 0, -1287/4096]
   [-6435/14336, 0]
   [109395/262144]

φ − μ:
   [3/2, 0, -27/32, 0, 269/512, 0, -6607/24576, 0]
   [21/16, 0, -55/32, 0, 6759/4096, 0, -155113/122880]
   [151/96, 0, -417/128, 0, 87963/20480, 0]
   [1097/512, 0, -15543/2560, 0, 2514467/245760]
   [8011/2560, 0, -69119/6144, 0]
   [293393/61440, 0, -5962461/286720]
   [6459601/860160, 0]
   [332287993/27525120]

μ − β:
   [-1/2, 0, 3/16, 0, -1/32, 0, 19/2048, 0]
   [-1/16, 0, 1/32, 0, -9/2048, 0, 7/4096]
   [-1/48, 0, 3/256, 0, -3/2048, 0]
   [-5/512, 0, 3/512, 0, -11/16384]
   [-7/1280, 0, 7/2048, 0]
   [-7/2048, 0, 9/4096]
   [-33/14336, 0]
   [-429/262144]

β − μ:
   [1/2, 0, -9/32, 0, 205/1536, 0, -4879/73728, 0]
   [5/16, 0, -37/96, 0, 1335/4096, 0, -86171/368640]
   [29/96, 0, -75/128, 0, 2901/4096, 0]
   [539/1536, 0, -2391/2560, 0, 1082857/737280]
   [3467/7680, 0, -28223/18432, 0]
   [38081/61440, 0, -733437/286720]
   [459485/516096, 0]
   [109167851/82575360]

μ − θ:
   [1/2, 0, 13/16, 0, -15/32, 0, 509/2048, 0]
   [-1/16, 0, 33/32, 0, -1673/2048, 0, 2599/4096]
   [-5/16, 0, 349/256, 0, -2989/2048, 0]
   [-261/512, 0, 963/512, 0, -43531/16384]
   [-921/1280, 0, 5545/2048, 0]
   [-6037/6144, 0, 16617/4096]
   [-19279/14336, 0]
   [-490925/262144]

θ − μ:
   [-1/2, 0, -23/32, 0, 499/1536, 0, -14321/73728, 0]
   [5/16, 0, -5/96, 0, 6565/12288, 0, -201467/368640]
   [1/32, 0, -77/128, 0, 2939/4096, 0]
   [283/1536, 0, -4037/7680, 0, 1155049/737280]
   [1301/7680, 0, -19465/18432, 0]
   [17089/61440, 0, -442269/286720]
   [198115/516096, 0]
   [48689387/82575360]

χ − φ:
   [-2, 2/3, 4/3, -82/45, 32/45, 4642/4725, -8384/4725, 1514/1323]
   [5/3, -16/15, -13/9, 904/315, -1522/945, -2288/1575, 142607/42525]
   [-26/15, 34/21, 8/5, -12686/2835, 44644/14175, 120202/51975]
   [1237/630, -12/5, -24832/14175, 1077964/155925, -1097407/187110]
   [-734/315, 109598/31185, 1040/567, -12870194/1216215]
   [444337/155925, -941912/184275, -126463/72765]
   [-2405834/675675, 3463678/467775]
   [256663081/56756700]

φ − χ:
   [2, -2/3, -2, 116/45, 26/45, -2854/675, 16822/4725, 189416/99225]
   [7/3, -8/5, -227/45, 2704/315, 2323/945, -31256/1575, 141514/8505]
   [56/15, -136/35, -1262/105, 73814/2835, 98738/14175, -2363828/31185]
   [4279/630, -332/35, -399572/14175, 11763988/155925, 14416399/935550]
   [4174/315, -144838/6237, -2046082/31185, 258316372/1216215]
   [601676/22275, -115444544/2027025, -2155215124/14189175]
   [38341552/675675, -170079376/1216215]
   [1383243703/11351340]

χ − β:
   [-1, 2/3, 0, -16/45, 2/5, -998/4725, -34/4725, 1384/11025]
   [1/6, -2/5, 19/45, -22/105, -2/27, 1268/4725, -12616/42525]
   [-1/15, 16/105, -22/105, 116/567, -1858/14175, 1724/51975]
   [17/1260, -8/105, 2123/14175, -26836/155925, 115249/935550]
   [-1/105, 128/4455, -424/6237, 140836/1216215]
   [149/311850, -31232/2027025, 210152/4729725]
   [-499/225225, 30208/6081075]
   [-68251/113513400]

β − χ:
   [1, -2/3, -1/3, 38/45, -1/3, -3118/4725, 4769/4725, -25666/99225]
   [5/6, -14/15, -7/9, 50/21, -247/270, -14404/4725, 193931/42525]
   [16/15, -34/21, -5/3, 17564/2835, -36521/14175, -1709614/155925]
   [2069/1260, -28/9, -49877/14175, 2454416/155925, -637699/85050]
   [883/315, -28244/4455, -20989/2835, 48124558/1216215]
   [797222/155925, -2471888/184275, -16969807/1091475]
   [2199332/225225, -1238578/42525]
   [87600385/4540536]

χ − θ:
   [0, 2/3, 2/3, -2/9, -14/45, 1042/4725, 18/175, -1738/11025]
   [-1/3, 4/15, 43/45, -4/45, -712/945, 332/945, 23159/42525]
   [-2/5, 2/105, 124/105, 274/2835, -1352/945, 13102/31185]
   [-55/126, -16/105, 21068/14175, 1528/4725, -2414843/935550]
   [-22/45, -9202/31185, 20704/10395, 60334/93555]
   [-90263/155925, -299444/675675, 40458083/14189175]
   [-8962/12285, -3818498/6081075]
   [-4259027/4365900]

θ − χ:
   [0, -2/3, -2/3, 4/9, 2/9, -3658/4725, 76/225, 64424/99225]
   [1/3, -4/15, -23/45, 68/45, 61/135, -2728/945, 2146/1215]
   [2/5, -24/35, -46/35, 9446/2835, 428/945, -95948/10395]
   [83/126, -80/63, -34712/14175, 4472/525, 29741/85050]
   [52/45, -2362/891, -17432/3465, 280108/13365]
   [335882/155925, -548752/96525, -48965632/4729725]
   [51368/12285, -197456/15795]
   [1461335/174636]

χ − μ:
   [-1/2, 2/3, -37/96, 1/360, 81/512, -96199/604800, 5406467/38707200, -7944359/67737600]
   [-1/48, -1/15, 437/1440, -46/105, 1118711/3870720, -51841/1209600, -24749483/348364800]
   [-17/480, 37/840, 209/4480, -5569/90720, -9261899/58060800, 6457463/17740800]
   [-4397/161280, 11/504, 830251/7257600, -466511/2494800, -324154477/7664025600]
   [-4583/161280, 108847/3991680, 8005831/63866880, -22894433/124540416]
   [-20648693/638668800, 16363163/518918400, 2204645983/12915302400]
   [-219941297/5535129600, 497323811/12454041600]
   [-191773887257/3719607091200]

μ − χ:
   [1/2, -2/3, 5/16, 41/180, -127/288, 7891/37800, 72161/387072, -18975107/50803200]
   [13/48, -3/5, 557/1440, 281/630, -1983433/1935360, 13769/28800, 148003883/174182400]
   [61/240, -103/140, 15061/26880, 167603/181440, -67102379/29030400, 79682431/79833600]
   [49561/161280, -179/168, 6601661/7257600, 97445/49896, -40176129013/7664025600]
   [34729/80640, -3418889/1995840, 14644087/9123840, 2605413599/622702080]
   [212378941/319334400, -30705481/10378368, 175214326799/58118860800]
   [1522256789/1383782400, -16759934899/3113510400]
   [1424729850961/743921418240]

ξ − φ:
   [-4/3, -4/45, 88/315, 538/4725, 20824/467775, -44732/2837835, -86728/16372125, -88002076/13956067125]
   [34/45, 8/105, -2482/14175, -37192/467775, -12467764/212837625, -895712/147349125, -2641983469/488462349375]
   [-1532/2835, -898/14175, 54968/467775, 100320856/1915538625, 240616/4209975, 8457703444/488462349375]
   [6007/14175, 24496/467775, -5884124/70945875, -4832848/147349125, -4910552477/97692469875]
   [-23356/66825, -839792/19348875, 816824/13395375, 9393713176/488462349375]
   [570284222/1915538625, 1980656/54729675, -4532926649/97692469875]
   [-496894276/1915538625, -14848113968/488462349375]
   [224557742191/976924698750]

φ − ξ:
   [4/3, 4/45, -16/35, -2582/14175, 60136/467775, 28112932/212837625, 22947844/1915538625, -1683291094/37574026875]
   [46/45, 152/945, -11966/14175, -21016/51975, 251310128/638512875, 1228352/3007125, -14351220203/488462349375]
   [3044/2835, 3802/14175, -94388/66825, -8797648/10945935, 138128272/147349125, 505559334506/488462349375]
   [6059/4725, 41072/93555, -1472637812/638512875, -45079184/29469825, 973080708361/488462349375]
   [768272/467775, 455935736/638512875, -550000184/147349125, -1385645336626/488462349375]
   [4210684958/1915538625, 443810768/383107725, -2939205114427/488462349375]
   [387227992/127702575, 101885255158/54273594375]
   [1392441148867/325641566250]

ξ − β:
   [-1/3, -4/45, 32/315, 34/675, 2476/467775, -70496/8513505, -18484/4343625, 29232878/97692469875]
   [-7/90, -4/315, 74/2025, 3992/467775, 53836/212837625, -4160804/1915538625, -324943819/488462349375]
   [-83/2835, 2/14175, 7052/467775, -661844/1915538625, 237052/383107725, -168643106/488462349375]
   [-797/56700, 934/467775, 1425778/212837625, -2915326/1915538625, 113042383/97692469875]
   [-3673/467775, 390088/212837625, 6064888/1915538625, -558526274/488462349375]
   [-18623681/3831077250, 41288/29469825, 155665021/97692469875]
   [-6205669/1915538625, 504234982/488462349375]
   [-8913001661/3907698795000]

β − ξ:
   [1/3, 4/45, -46/315, -1082/14175, 11824/467775, 7947332/212837625, 9708931/1915538625, -5946082372/488462349375]
   [17/90, 68/945, -338/2025, -16672/155925, 39946703/638512875, 164328266/1915538625, 190673521/69780335625]
   [461/2835, 1102/14175, -101069/467775, -255454/1563705, 236067184/1915538625, 86402898356/488462349375]
   [3161/18900, 1786/18711, -189032762/638512875, -98401826/383107725, 110123070361/488462349375]
   [88868/467775, 80274086/638512875, -802887278/1915538625, -200020620676/488462349375]
   [880980241/3831077250, 66263486/383107725, -296107325077/488462349375]
   [37151038/127702575, 4433064236/18091198125]
   [495248998393/1302566265000]

ξ − θ:
   [2/3, -4/45, 62/105, 778/4725, -193082/467775, -4286228/42567525, 53702182/212837625, 182466964/8881133625]
   [4/45, -32/315, 12338/14175, 92696/467775, -61623938/70945875, -32500616/273648375, 367082779691/488462349375]
   [-524/2835, -1618/14175, 612536/467775, 427003576/1915538625, -663111728/383107725, -42668482796/488462349375]
   [-5933/14175, -8324/66825, 427770788/212837625, 421877252/1915538625, -327791986997/97692469875]
   [-320044/467775, -9153184/70945875, 6024982024/1915538625, 74612072536/488462349375]
   [-1978771378/1915538625, -46140784/383107725, 489898512247/97692469875]
   [-2926201612/1915538625, -42056042768/488462349375]
   [-2209250801969/976924698750]

θ − ξ:
   [-2/3, 4/45, -158/315, -2102/14175, 109042/467775, 216932/2627625, -189115382/1915538625, -230886326/6343666875]
   [16/45, -16/945, 934/14175, -7256/155925, 117952358/638512875, 288456008/1915538625, -11696145869/69780335625]
   [-232/2835, 922/14175, -25286/66825, -7391576/54729675, 478700902/1915538625, 91546732346/488462349375]
   [719/4725, 268/18711, -67048172/638512875, -67330724/383107725, 218929662961/488462349375]
   [14354/467775, 46774256/638512875, -117954842/273648375, -129039188386/488462349375]
   [253129538/1915538625, 2114368/34827975, -178084928947/488462349375]
   [13805944/127702575, 6489189398/54273594375]
   [59983985827/325641566250]

ξ − μ:
   [1/6, -4/45, -817/10080, 1297/18900, 7764059/239500800, -9292991/302702400, -25359310709/1743565824000, 39534358147/2858202547200]
   [49/720, -2/35, -29609/453600, 35474/467775, 36019108271/871782912000, -14814966289/245188944000, -13216941177599/571640509440000]
   [4463/90720, -2917/56700, -4306823/59875200, 3026004511/30648618000, 99871724539/1569209241600, -27782109847927/250092722880000]
   [331799/7257600, -102293/1871100, -368661577/4036032000, 2123926699/15324309000, 168979300892599/1600593426432000]
   [11744233/239500800, -875457073/13621608000, -493031379277/3923023104000, 1959350112697/9618950880000]
   [453002260127/7846046208000, -793693009/9807557760, -145659994071373/800296713216000]
   [103558761539/1426553856000, -53583096419057/500185445760000]
   [12272105438887727/128047474114560000]

μ − ξ:
   [-1/6, 4/45, 121/1680, -1609/28350, -384229/14968800, 12674323/851350500, 7183403063/560431872000, -375027460897/125046361440000]
   [-29/720, 26/945, 16463/453600, -431/17325, -31621753811/1307674368000, 1117820213/122594472000, 30410873385097/2000741783040000]
   [-1003/45360, 449/28350, 3746047/119750400, -32844781/1751349600, -116359346641/3923023104000, 151567502183/17863765920000]
   [-40457/2419200, 629/53460, 10650637121/326918592000, -13060303/766215450, -317251099510901/8002967132160000]
   [-1800439/119750400, 205072597/20432412000, 146875240637/3923023104000, -2105440822861/125046361440000]
   [-59109051671/3923023104000, 228253559/24518894400, 91496147778023/2000741783040000]
   [-4255034947/261534873600, 126430355893/13894040160000]
   [-791820407649841/42682491371520000]

ξ − χ:
   [2/3, -34/45, 46/315, 2458/4725, -55222/93555, 2706758/42567525, 16676974/30405375, -64724382148/97692469875]
   [19/45, -256/315, 3413/14175, 516944/467775, -340492279/212837625, 158999572/1915538625, 85904355287/37574026875]
   [248/567, -15958/14175, 206834/467775, 4430783356/1915538625, -7597644214/1915538625, 2986003168/37574026875]
   [16049/28350, -832976/467775, 62016436/70945875, 851209552/174139875, -375566203/39037950]
   [15602/18711, -651151712/212837625, 3475643362/1915538625, 5106181018156/488462349375]
   [2561772812/1915538625, -10656173804/1915538625, 34581190223/8881133625]
   [873037408/383107725, -5150169424688/488462349375]
   [7939103697617/1953849397500]

χ − ξ:
   [-2/3, 34/45, -88/315, -2312/14175, 27128/93555, -55271278/212837625, 308365186/1915538625, -17451293242/488462349375]
   [1/45, -184/945, 6079/14175, -65864/155925, 106691108/638512875, 149984636/1915538625, -101520127208/488462349375]
   [-106/2835, 772/14175, -14246/467775, 5921152/54729675, -99534832/383107725, 10010741462/37574026875]
   [-167/9450, -5312/467775, 75594328/638512875, -35573728/273648375, 1615002539/75148053750]
   [-248/13365, 2837636/638512875, 130601488/1915538625, -3358119706/488462349375]
   [-34761247/1915538625, -3196/3553875, 46771947158/488462349375]
   [-2530364/127702575, -18696014/18091198125]
   [-14744861191/651283132500]
\section auxlaterror Truncation errors There are two sources of error when using these series. The truncation error arises from retaing terms up to a certain order in \e n; it is the absolute difference between the value of the truncated series compared with the exact latitude (evaluated with exact arithmetic). In addition, using standard double-precision arithmetic entails accumulating round-off errors so that at the end of a complex calculation a few of the trailing bits of the result are wrong. Here's a table of the truncation errors. The errors are given in "units in the last place (ulp)" where 1 ulp = 2−53 radian = 6.4 × 10−15 degree = 2.3 × 10−11 arcsecond which is a measure of the round-off error for double precision. Here is some rough guidance on how to interpret these errors: - if the truncation error is less than 1 ulp, then round-off errors dominate; - if the truncation error is greater than 8 ulp, then truncation errors dominate; - otherwise, round-off and truncation errors are comparable. . The truncation errors are given accurate to 2 significant figures.

Auxiliary latitude truncation errors (ulp)
expression [f = 1/150, order = 6] [f = 1/297, order = 5]
n series e2 series n series e2 series
β − φ
0.0060 
28   
 0.035 
 41   
φ − β
0.0060 
28   
 0.035 
 41   
θ − φ
2.9    
82   
 6.0   
120   
φ − θ
2.9    
82   
 6.0   
120   
θ − β
0.0060 
28   
 0.035 
 41   
β − θ
0.0060 
28   
 0.035 
 41   
μ − φ
0.037  
41   
 0.18  
 60   
φ − μ
0.98   
59   
 2.3   
 84   
μ − β
0.00069
 5.8 
 0.0024
  9.6 
β − μ
0.13   
12   
 0.35  
 19   
μ − θ
0.24   
30   
 0.67  
 40   
θ − μ
0.099  
23   
 0.23  
 33   
χ − φ
0.78   
43   
 2.1   
 64   
φ − χ
9.0    
71   
17     
100   
χ − β
0.018  
 3.7 
 0.11  
  6.4 
β − χ
1.7    
16   
 3.4   
 24   
χ − θ
0.18   
31   
 0.56  
 43   
θ − χ
0.87   
23   
 1.9   
 32   
χ − μ
0.022  
 0.56
 0.11  
  0.91
μ − χ
0.31   
 1.2 
 0.86  
  2.0 
ξ − φ
0.015  
39   
 0.086 
 57   
φ − ξ
0.34   
53   
 1.1   
 75   
ξ − β
0.00042
 6.3 
 0.0039
 10   
β − ξ
0.040  
10   
 0.15  
 15   
ξ − θ
0.28   
28   
 0.75  
 38   
θ − ξ
0.040  
23   
 0.11  
 33   
ξ − μ
0.015  
 0.79
 0.058 
  1.5 
μ − ξ
0.0043 
 0.54
 0.018 
  1.1 
ξ − χ
0.60   
 1.9 
 1.5   
  3.6 
χ − ξ
0.023  
 0.53
 0.079 
  0.92
\if SKIP 0 beta phi ,0.0060!,28!!!,!0.035!,!41!!! 1 phi beta ,0.0060!,28!!!,!0.035!,!41!!! 2 theta phi ,2.9!!!!,82!!!,!6.0!!!,120!!! 3 phi theta,2.9!!!!,82!!!,!6.0!!!,120!!! 4 theta beta ,0.0060!,28!!!,!0.035!,!41!!! 5 beta theta,0.0060!,28!!!,!0.035!,!41!!! 6 mu phi ,0.037!!,41!!!,!0.18!!,!60!!! 7 phi mu ,0.98!!!,59!!!,!2.3!!!,!84!!! 8 mu beta ,0.00069,!5.8!,!0.0024,!!9.6! 9 beta mu ,0.13!!!,12!!!,!0.35!!,!19!!! 10 mu theta,0.24!!!,30!!!,!0.67!!,!40!!! 11 theta mu ,0.099!!,23!!!,!0.23!!,!33!!! 12 chi phi ,0.78!!!,43!!!,!2.1!!!,!64!!! 13 phi chi ,9.0!!!!,71!!!,17!!!!!,100!!! 14 chi beta ,0.018!!,!3.7!,!0.11!!,!!6.4! 15 beta chi ,1.7!!!!,16!!!,!3.4!!!,!24!!! 16 chi theta,0.18!!!,31!!!,!0.56!!,!43!!! 17 theta chi ,0.87!!!,23!!!,!1.9!!!,!32!!! 18 chi mu ,0.022!!,!0.56,!0.11!!,!!0.91 19 mu chi ,0.31!!!,!1.2!,!0.86!!,!!2.0! 20 xi phi ,0.015!!,39!!!,!0.086!,!57!!! 21 phi xi ,0.34!!!,53!!!,!1.1!!!,!75!!! 22 xi beta ,0.00042,!6.3!,!0.0039,!10!!! 23 beta xi ,0.040!!,10!!!,!0.15!!,!15!!! 24 xi theta,0.28!!!,28!!!,!0.75!!,!38!!! 25 theta xi ,0.040!!,23!!!,!0.11!!,!33!!! 26 xi mu ,0.015!!,!0.79,!0.058!,!!1.5! 27 mu xi ,0.0043!,!0.54,!0.018!,!!1.1! 28 xi chi ,0.60!!!,!1.9!,!1.5!!!,!!3.6! 29 chi xi ,0.023!!,!0.53,!0.079!,!!0.92 \endif The 2nd and 3rd columns show the results for the SRMmax ellipsoid, \e f = 1/150, retaining 6th order terms in the series expansion. The 4th and 5th columns show the results for the International ellipsoid, \e f = 1/297, retaining 5th order terms in the series expansion. The 2nd and 4th columns give the errors for the series expansions in terms of \e n given in this section (appropriately truncated). The 3rd and 5th columns give the errors when the series are reexpanded in terms of e2 = 4\e n/(1 + \e n)2 and truncated retaining the e12 and e10 terms respectively. Some observations: - For production use, the 6th order series in \e n are recommended. For \e f = 1/150, the resulting errors are close to the round-off limit. The errors in the 6th order series scale as f7; so the errors with \e f = 1/297 are about 120 times smaller. - It's inadvisable to use the 5th order series in \e n; this order is barely acceptable for \e f = 1/297 and the errors grow as f6 as \e f is increased. - In all cases, the expansions in terms of e2 are considerably less accurate than the corresponding series in \e n. - For every series converting between φ and any of θ, μ, χ, or ξ, the series where β is substituted for φ is more accurate. Considering that the transformation between φ and β is so simple, tanβ = (1 - \e f) tanφ, it sometimes makes sense to use β internally as the basic measure of latitude. (This is the case with geodesic calculations.)
Back to \ref geocentric. Forward to \ref highprec. Up to \ref contents.
**********************************************************************/ /** \page highprec Support for high precision arithmetic
Back to \ref auxlat. Forward to \ref changes. Up to \ref contents.
One of the goals with the algorithms in GeographicLib is to deliver accuracy close to the limits for double precision. In order to develop such algorithms it is very useful to be have accurate test data. For this purpose, I used Maxima's bfloat capability, which support arbitrary precision floating point arithmetic. As of version 1.37, such high-precision test data can be generated directly by GeographicLib by compiling it with GEOGRAPHICLIB_PRECISION equal to 4 or 5. Here's what you should know: - This is mainly for use for algorithm developers. It's not recommended for installation for all users on a system. - Configuring with -D GEOGRAPHICLIB_PRECISION=4 gives quad precision (113-bit precision) via boost::multiprecision::float128; this requires: - Boost, version 1.64 or later, - the quadmath library (the package names are libquadmath and libquadmath-devel), - the use of g++. - Configuring with -D GEOGRAPHICLIB_PRECISION=5 gives arbitrary precision via mpfr::mpreal; this requires: - MPFR, version 3.0 or later, - MPFR C++ (version 3.6.5, dated 2016-12-19, or later), - a compiler which supports the explicit cast operator (e.g., g++ 4.5 or later, Visual Studio 12 2013 or later). - MPFR, MPFR C++, and Boost all come with their own licenses. Be sure to respect these. - The indicated precision is used for all floating point arithmetic. Thus, you can't compare the results of different precisions within a single invocation of a program. Instead, you can create a file of accurate test data at a high precision and use this to test the algorithms at double precision. - With MPFR, the precision should be set (using Utility::set_digits) just once before any other GeographicLib routines are called. Calling this function after other GeographicLib routines will lead to inconsistent results (because the precision of some constants like Math::pi() is set when the functions are first called). - All the \ref utilities call Utility::set_digits() (with no arguments). This causes the precision (in bits) to be determined by the GEOGRAPHICLIB_DIGITS environment variable. If this is not defined the precision is set to 256 bits (about 77 decimal digits). - The accuracy of most calculations should increase as the precision increases (and typically only a few bits of accuracy should be lost). We can distinguish 4 sources of error: - Round-off errors; these are reliably reduced when the precision is increased. For the most part, the algorithms used by GeographicLib are carefully tuned to minimize round-off errors, so that only a few bits of accuracy are lost. - Convergence errors due to not iterating certain algorithms to convergence. However, all iterative methods used by GeographicLib converge quadratically (the number of correct digits doubles on each iteration) so that full convergence is obtained for "reasonable" precisions (no more than, say, 100 decimal digits or about 340 bits). An exception is thrown if the convergence criterion is not met when using high precision arithmetic. - Truncation errors. Some classes (namely, Geodesic and TransverseMercator) use series expansion to approximate the true solution. Additional terms in the series are used for high precision, however there's always a finite truncation error which varies as some power of the flattening. On the other hand, GeodesicExact and TransverseMercatorExact are somewhat slower classes offering the same functionality implemented with EllipticFunction. These classes provide arbitrary accuracy. (However, a caveat is that the evaluation of the area in GeodesicExact still uses a series (albeit of considerably higher order). So the area calculations are always have a finite truncation error.) - Quantization errors. Geoid, GravityModel, and MagneticModel all depend on external data files. The coefficient files for GravityModel and MagneticModel store the coefficients as IEEE doubles (and perhaps these coefficients can be regarded as exact). However, with Geoid, the data files for the geoid heights are quantized at 3mm leading to an irreducible ±1.5mm quantization error. On the other hand, all the physical constants used by GeographicLib, e.g., the flattening of the WGS84 ellipsoid, are evaluated as exact decimal numbers. - Where might high accuracy be important? - checking the truncation error of series approximations; - checking for excessive round-off errors (typically due to subtraction); - checking the round-off error in computing areas of many-sided polygons; - checking the summation of high order spherical harmonic expansions (where underflow and overflow may also be a problem). - Because only a tiny number of people will be interested in using this facility: - the cmake support for the required libraries is rudimentary; - however geographiclib-config.cmake does export GEOGRAPHICLIB_PRECISION and GEOGRAPHICLIB_HIGHPREC_LIBRARIES, the libraries providing the support for high-precision arithmetic; - support for the C++11 mathematical functions and the explicit cast operator is required; - quad precision is only available on Linux; - mpfr has been mostly tested on Linux (but it works on Windows with Visual Studio 12 and MacOS too). The following steps needed to be taken - Phase 1, make sure you can switch easily between double, float, and long double. - use \#include <cmath> instead of \#include <math.h>; - use, e.g., std::sqrt instead of sqrt in header files (similarly for sin, cos, atan2, etc.); - use using namespace std; and plain sqrt, etc., in code files; - express all convergence criteria in terms of\code numeric_limits::epsilon() \endcode etc., instead of using "magic constants", such as 1.0e-15; - use typedef double real; and replace all occurrences of double by real; - write all literals by, e.g., real(0.5). Some constants might need the L suffix, e.g., real f = 1/real(298.257223563L) (but see below); - Change the typedef of real to float or long double, compile, and test. In this way, the library can be run with any of the three basic floating point types. - If you want to run the library with multiple floating point types within a single executable, then make all your classes take a template parameter specifying the floating-point type and instantiate your classes with the floating-point types that you plan to use. I did not take this approach with GeographicLib because double precision is suitable for the vast majority of applications and turning all the classes into templates classes would end up needlessly complicating (and bloating) the library. - Phase 2, changes to support arbitrary, but fixed, precision - Use, e.g., \code typedef boost::multiprecision::float128 real; \endcode - Change std::sqrt(...), etc. to \code using std::sqrt; sqrt(...) \endcode (but note that std::max can stay). It's only necessary to do this in header files (code files already have using namespace std;). - In the case of boost's multiprecision numbers, the C++11 mathematical functions need special treatment, see Math.hpp. - If necessary, use series with additional terms to improve the accuracy. - Replace slowly converging root finding methods with rapidly converging methods. In particular, the simple iterative method to determine the flattening from the dynamical form factor in NormalGravity converged too slowly; this was replaced by Newton's method. - If necessary, increase the maximum allowed iteration count in root finding loops. Also throw an exception of the maximum iteration count is exceeded. - Write literal constants in a way that works for any precision, e.g., \code real f = 1/( real(298257223563LL) / 1000000000 ); \endcode [Note that \code real f = 1/( 298 + real(257223563) / 1000000000 ); \endcode and 1/real(298.257223563L) are susceptible to double rounding errors. We normally want to avoid such errors when real is a double.] - For arbitrary constants, you might have to resort to macros \code #if GEOGRAPHICLIB_PRECISION == 1 #define REAL(x) x##F #elif GEOGRAPHICLIB_PRECISION == 2 #define REAL(x) x #elif GEOGRAPHICLIB_PRECISION == 3 #define REAL(x) x##L #elif GEOGRAPHICLIB_PRECISION == 4 #define REAL(x) x##Q #else #define REAL(x) real(#x) #endif \endcode and then use \code real f = 1/REAL(298.257223563); \endcode - Perhaps use local static declarations to avoid the overhead of reevaluating constants, e.g., \code static inline real pi() { using std::atan2; // pi is computed just once static const real pi = atan2(real(0), real(-1)); return pi; } \endcode This is not necessary for built-in floating point types, since the atan2 function will be evaluated at compile time. - In Utility::readarray and Utility::writearray, arrays of reals were treated as plain old data. This assumption now no longer holds and these functions needed special treatment. - volatile declarations don't apply. - Phase 3, changes to support arbitrary precision which can be set at runtime. - The big change now is that the precision is not known at compile time. All static initializations which involve floating point numbers need to be eliminated. - Some static variables (e.g., tolerances which are expressed in terms of numeric_limits<double>\::epsilon()) were made member variables and so initialized when the constructor was called. - Some simple static real arrays (e.g., the interpolating stencils for Geoid) were changed into integer arrays. - Some static variables where converted to static functions similar to the definition of pi() above. - All the static instances of classes where converted as follows \code // declaration static const Geodesic WGS84; // definition const Geodesic Geodesic::WGS84(Constants::WGS84_a(), Constants::WGS84_f()); // use const Geodesic& geod = Geodesic::WGS84; \endcode becomes \code // declaration static const Geodesic& WGS84(); // definition const Geodesic& Geodesic::WGS84() { static const Geodesic wgs84(Constants::WGS84_a(), Constants::WGS84_f()); return wgs84; static const Geodesic& WGS84(); } // use const Geodesic& geod = Geodesic::WGS84(); \endcode This is the so-called "construct on first use idiom". This is the most disruptive of the changes since it requires a different calling convention in user code. However the old static initializations were invoked every time a code linking to GeographicLib was started, even if the objects were not subsequently used. The new method only initializes the static objects if they are used. . - numeric_limits<double>\::digits is no longer a compile-time constant. It becomes numeric_limits<double>\::digits(). - Depending on the precision cos(π/2) might be negative. Similarly atan(tan(π/2)) may evaluate to −π/2. GeographicLib already handled this, because this happens with long doubles (64 bits in the fraction). - The precision needs to be set in each thread in a multi-processing applications (for an example, see examples/GeoidToGTX.cpp). - Passing numbers to functions by value incurs a substantially higher overhead than with doubles. This could be avoided by passing such arguments by reference. This was not done here because it would junk up the code to benefit a narrow application. - The constants in GeodesicExact, e.g., 831281402884796906843926125, can't be specified as long doubles nor long longs (since they have more than 64 significant bits): - first tried macro which expanded to a string (see the macro REAL above); - now use inline function to combine two long long ints each with at most 52 significant bits; - also needed to simplify one routine in GeodesicExact which took inordinately long (15 minutes) to compile using g++; - but Visual Studio 12 then complained (with an internal compiler error presumably due to overly aggressive whole-file optimization); fixed by splitting one function into a separate file.
Back to \ref auxlat. Forward to \ref changes. Up to \ref contents.
**********************************************************************/ /** \page changes Change log
Back to \ref highprec. Up to \ref contents.
List of versions in reverse chronological order together with a brief list of changes. (Note: Old versions of the library use a year-month style of numbering. Now, the library uses a major and minor version number.) Recent versions of GeographicLib are available at https://sourceforge.net/projects/geographiclib/files/distrib/. Older versions are in https://sourceforge.net/projects/geographiclib/files/distrib/archive/. The corresponding documentation for these versions is obtained by clicking on the “Version m.nn” links below. Some of the links in the documentation of older versions may be out of date (in particular the links for the source code will not work if the code has been migrated to the archive subdirectory). All the releases are available as tags “rm.nn” in the the "release" branch of the git repository for GeographicLib. \if SKIP - TODO: Planned updates - Change templating in PolygonArea so that the AddPoint and AddEdge methods are templated instead of the class itself. This would allow a polygon to contain a mixture of geodesic and rhumb-line edges. - Generalize Geoid, UTMUPS, MGRS, GeoCoords to handle non-WGS84 ellipsoids. - Add GreatEllipse class. - Implement Geodesic + TM + PolarStereographic on Jets. - Template versions of Gnomonic and AzimuthalEquidistant so that they can use either Geodesic and GeodesicExact. Use typedefs so that Geodesic::Line points to GeodesicLine. - Split DMS stuff from main JavaScript package. Also move 'use strict' into functions (to make jshint happy). - Add C++ tests not dependent on utility programs. - Add information on radius of convergence for aux latitude series. - Require C++11 and C99(?) compiler support. Mark Math::hypot et al. deprecated. - Check Geocentric::Reverse for accuracy for extreme ellipsoids, \e e > 1/sqrt(2). \endif - Version 1.50.1 (released 2019-12-13) - Add the World Magnetic Model 2020, wmm2020, covering the period 2020--2025. This is now the model returned by MagneticModel::DefaultMagneticName and is default magnetic model for MagneticField (replacing wmm2015v2 which is only valid thru the end of 2019). - Include float instantiations of those templated Math functions which migrated to Math.cpp in version 1.50. - WARNING: The next version of GeographicLib will require a C++11 compliant compiler. This means that the minimum version of Visual Studio will be Visual Studio 12 2013. (This repeats the warning given with version 1.50. It didn't apply to this version because this is a minor update.) - Version 1.50 (released 2019-09-24) - BUG fixes: - Java + JavaScript implementations of PolygonArea::TestEdge counted the pole encirclings wrong. - Fix typo in JavaScript implementation which affected unsigned areas. - Adding edges to a polygon counted pole encirclings inconsistent with the way the adding point counted them. This might have caused an incorrect result if a polygon vertex had longitude = 0. This affected all implementations except Fortran and MATLAB). - GARS::Forward: fix BUG in handling of longitude = ±180°. - Fix bug in Rhumb class and RhumbSolve(1) utiity which caused incorrect area to be reported if an endpoint is at a pole. Thanks to Natalia Sabourova for reporting this. - Fix bug in MATLAB routine mgrs_inv which resulted in incorrect results for UPS zones with prec = −1. - In geodreckon.m geoddistance.m, suppress (innocuous) "warning: division by zero" messages from Octave. - In python implementation, work around problems caused by sin(inf) and fmod(inf) raising exceptions. - Geoid class, fix the use of streamoff. - The PolygonArea class, the Planimeter utility, and their equivalents in C, Fortran, MATLAB, Java, JavaScript, Python, and Maxima can now handle arbitrarily complex polygons. In the case of self-intersecting polygons the area is accumulated "algebraically", e.g., the areas of the 2 loops in a figure-8 polygon will partially cancel. - Changes in gravity and magnetic model handling - SphericalEngine::coeff::readcoeffs takes new optional argument \e truncate. - The constructors for GravityModel and MagneticModel allow the maximum degree and order to be specified. The array of coefficients will then be truncated if necessary. - GravityModel::Degree(), GravityModel::Order(), MagneticModel::Degree(), MagneticModel::Order() return the maximum degree and order of all the components of a GravityModel or MagneticModel. - Gravity and MagneticField utilities accept -N and -M options to to allow the maximum degree and order to be specified. - The GeodSolve allows fractional distances to be entered as fractions (with the -F flag). - MajorRadius() methods are now called EquatorialRadius() for the C++, Java, and .NET libraries. "Equatorial" is more descriptive in the case of prolate ellipsoids. MajorRadius() is retained for backward compatibility for C++ and Java but is deprecated. - Minimum version updates: - CMake = 3.1.0, released 2014-12-15. - Minimum g++ version = 4.8.0, released 2013-03-22. - Visual Studio 10 2010 (haven't been able to check Visual Studio 2008 for a long time). - WARNING: The next version of GeographicLib will require a C++11 compliant compiler. This means that the minimum version of Visual Studio will be Visual Studio 12 2013. - Minimum boost version = 1.64 needed for GEOGRAPHICLIB_PRECISION = 4. - Java = 1.6; this allows the removal of epsilon, min, hypot, log1p, copysign, cbrt from GeoMath. - CMake updates: - Fine tune Visual Studio compatibility check in find_package(GeographicLib); this allows GeographicLib compiled with Visual Studio 14 2015 to be used with a project compiled with Visual Studio 15 2017 and 16 2019. - Suppress warnings with dotnet build. - Change CMake target names and add an interface library (thanks to Matthew Woehlke). - Remove pre-3.1.0 cruft and update the documentation to remove the need to call include_dirctories. - Add _d suffix to example and test programs. - Changer installation path for binary installer to the Windows default. - Add support for Intel compiler (for C++, C, Fortran). This entails supplying the -fp-model precise flag to prevent the compiler from incorrectly simplying (a + b) + c and 0.0 + x. - Add version 2 of the World Magnetic Model 2015, wmm2015v2. This is now the default magnetic model for MagneticField (replacing wmm2015 which is now deprecated). Coming in 2019-12: the wmm2020 model. - The -f flag in the scripts geographiclib-get-geoids, geographiclib-get-gravity, and geographiclib-get-magnetic, allows you to load new models (not yet in the set defined by "all"). This is in addition to its original role of allowing you to overwrite existing models. - Changes in math function support: - Move some of the functionality from Math.hpp to Math.cpp to make compilation of package which depend on GeographicLib less sensitive to the current compiler environment. - Add Math::remainder, Math::remquo, Math::round, and Math::lround. Also add implementations of remainder, remquo to C implementation. - Math::cbrt, Math::atanh, and Math::asinh now preserve the sign of −0. (Also: C, Java, JavaScript, Python, MATLAB. Not necessary: Fortran because sign is a built-in function.) - JavaScript: fall back to Math.hypot, Math.cbrt, Math.log1p, Math.atanh if they are available. - When parsing DMS strings ignore various non-breaking spaces (C++ and JavaScript). - Improve code coverage in the tests of geodesic algorithms (C++, C, Java, JavaScript, Python, MATLAB, Fortran). - Old deprecated NormalGravity::NormalGravity constructor removed. - Additions to the documentation: - add documentation links to ge{distance,reckon}.m; - clarify which solution is returned for Geocentric::Reverse. - Version 1.49 (released 2017-10-05) - Add the Enhanced Magnetic Model 2017, emm2017. This is valid for 2000 thru the end of 2021. - Avoid potential problems with the order of initializations in DMS, GARS, Geohash, Georef, MGRS, OSGB, SphericalEngine; this only would have been an issue if GeographicLib objects were instantiated globally. Now no GeographicLib initialization code should be run prior to the entry of main(). - To support the previous fix, add an overload, Utility::lookup(const char* s, char c). - NearestNeighbor::Search throws an error if \e pts is the wrong size (instead of merely returning no results). - Use complex arithmetic for Clenshaw sums in TransverseMercator and tranmerc_{fwd,inv}.m. - Changes in cmake support: - fix compiler flags for GEOGRAPHICLIB_PRECISION = 4; - add CONVERT_WARNINGS_TO_ERRORS option (default OFF), if ON then compiler warnings are treated as errors. - Fix warnings about implicit conversions of doubles to bools in C++, C, and JavaScript packages. - Binary installers for Windows now use Visual Studio 14 2015. - Version 1.48 (released 2017-04-09) - The "official" URL for GeographicLib is now https://geographiclib.sourceforge.io (instead of http://geographiclib.sourceforge.net). - The default range for longitude and azimuth is now (−180°, 180°], instead of [−180°, 180°). This was already the case for the C++ library; now the change has been made to the other implementations (C, Fortran, Java, JavaScript, Python, MATLAB, and Maxima). - Changes to NearestNeighbor: - fix BUG in reading a NearestNeighbor object from a stream which sometimes incorrectly caused a "Bad index" exception to be thrown; - add NearestNeighbor::operator<<, NearestNeighbor::operator>>, NearestNeighbor::swap, std::swap(GeographicLib::NearestNeighbor&, GeographicLib::NearestNeighbor&); - Additions to the documentation: - add documentation on \ref nearest; - \ref normalgravity documentation is now on its own page and now has an illustrative figure; - document the \ref auxlaterror in the series for auxiliary latitudes. - Fix BUGS in MATLAB function geodreckon with mixed scalar and array arguments. - Workaround bug in math.fmod for Python 2.7 on 32-bit Windows machines. - Changes in cmake support: - add USE_BOOST_FOR_EXAMPLES option (default OFF), if ON search for Boost libraries for building examples; - add APPLE_MULTIPLE_ARCHITECTURES option (default OFF), if ON build for both i386 and x86_64 on Mac OS X systems; - don't add flag for C++11 for g++ 6.0 (since it's not needed). - Fix compiler warnings with Visual Studio 2017 and for the C library. - Version 1.47 (released 2017-02-15) - Add NearestNeighbor class. - Improve accuracy of area calculation (fixing a flaw introduced in version 1.46); fix applied in Geodesic, GeodesicExact, and the implementations in C, Fortran, Java, JavaScript, Python, MATLAB, and Maxima. - Generalize NormalGravity to allow oblate and prolate ellipsoids. As a consequence a new form of constructor, NormalGravity::NormalGravity, has been introduced and the old form is now deprecated (and because the signatures of the two constructors are similar, the compiler will warn about the use of the old one). - Changes in Math class: - Math::sincosd, Math::sind, Math::cosd only return −0 for the case sin(−0); - Math::atan2d and Math::AngNormalize return results in (−180°, 180°]; this may affect the longitudes and azimuth returned by several other functions. - Add Utility::trim() and Utility::val(); Utility::num() is now deprecated. - Changes in cmake support: - remove support of PACKAGE_PATH and INSTALL_PATH in cmake configuration; - fix to FindGeographicLib.cmake to make it work on Debian systems; - use $ (cmake version ≥ 3.1); - use NAMESPACE for exported targets; - geographiclib-config.cmake exports GEOGRAPHICLIB_DATA, GEOGRAPHICLIB_PRECISION, and GeographicLib_HIGHPREC_LIBRARIES. - Add pkg-config support for cmake and autoconf builds. - Minor fixes: - fix the order of declarations in C library, incorporating the patches in version 1.46.1; - fix the packaging of the Python library, incorporating the patches in version 1.46.3; - restrict junit dependency in the Java package to testing scope (thanks to Mick Killianey); - various behind-the-scenes fixes to EllipticFunction; - fix documentation and default install location for Windows binary installers; - fix clang compiler warnings in GeodesicExactC4 and TransverseMercator. - Version 1.46 (released 2016-02-15) - The following BUGS have been fixed: - the -w flag to Planimeter(1) was being ignored; - in the Java package, the wrong longitude was being returned with direct geodesic calculation with a negative distance when starting point was at a pole (this bug was introduced in version 1.44); - in the JavaScript package, PolygonArea.TestEdge contained a misspelling of a variable name and other typos (problem found by threepointone). - INCOMPATIBLE CHANGES: - make the -w flag (to swap the default order of latitude and longitude) a toggle for all \ref utilities; - the -a option to GeodSolve(1) now toggles (instead of sets) arc mode; - swap order \e coslon and \e sinlon arguments in CircularEngine class. - Remove deprecated functionality: - remove gradient calculation from the Geoid class and GeoidEval(1) (this was inaccurate and of dubious utility); - remove reciprocal flattening functions, InverseFlattening in many classes and Constants::WGS84_r(); stop treating flattening > 1 as the reciprocal flattening in constructors; - remove DMS::Decode(string), DMS::DecodeFraction, EllipticFunction:m, EllipticFunction:m1, Math::extradigits, Math::AngNormalize2, PolygonArea::TestCompute; - stop treating LONG_NOWRAP as an alias for LONG_UNROLL in Geodesic (and related classes) and Rhumb; - stop treating full/schmidt as aliases for FULL/SCHMIDT in SphericalEngine (and related classes); - remove qmake project file src/GeographicLib.pro because QtCreator can handle cmake projects now; - remove deprecated Visual Studio 2005 project and solution files. - Changes to GeodesicLine and GeodesicLineExact classes; these changes (1) simplify the process of computing waypoints on a geodesic given two endpoints and (2) allow a GeodesicLine to be defined which is consistent with the solution of the inverse problem (in particular Geodesic::InverseLine the specification of south-going lines which pass the poles in a westerly direction by setting sin α1 = −0): - the class stores the distance \e s13 and arc length \e a13 to a reference point 3; by default these quantities are NaNs; - GeodesicLine::SetDistance (and GeodesicLine::SetArc) specify the distance (and arc length) to point 3; - GeodesicLine::Distance (and GeodesicLine::Arc) return the distance (and arc length) to point 3; - new methods Geodesic::InverseLine and Geodesic::DirectLine return a GeodesicLine with the reference point 3 defined as point 2 of the corresponding geodesic calculation; - these changes are also included in the C, Java, JavaScript, and Python packages. - Other changes to the geodesic routines: - more accurate solution of the inverse problem when longitude difference is close to 180° (also in C, Fortran, Java, JavaScript, Python, MATLAB, and Maxima packages); - more accurate calculation of lon2 in the inverse calculation with LONG_UNROLL (also in Java, JavaScript, Python packages). - Changes to GeodSolve(1) utility: - the -I and -D options now specify geodesic line calculation via the standard inverse or direct geodesic problems; - rename -l flag to -L to parallel the new -I and -D flags (-l is is retained for backward compatibility but is deprecated), and similarly for RhumbSolve(1); - the -F flag (in conjunction with the -I or -D flags) specifies that distances read on standard input are fractions of \e s13 or \e a13; - the -a option now toggles arc mode (noted above); - the -w option now toggles longitude first mode (noted above). - Changes to Math class: - Math::copysign added; - add overloaded version of Math::AngDiff which returns the error in the difference. This allows a more accurate treatment of inverse geodesic problem when \e lon12 is close to 180°; - Math::AngRound now converts tiny negative numbers to −0 (instead of +0), however −0 is still converted to +0. - Add -S and -T options to GeoConvert(1). - Add Sphinx documentation for Python package. - Samples of wrapping the C++ library, so it's accessible in other languages, are given in wrapper/C, wrapper/python, and wrapper/matlab. - Binary installers for Windows now use Visual Studio 12 2013. - Remove top-level pom.xml from release (it was specific to SRI). - A reminder: because of the JavaScript changes introduced in version 1.45, you should remove the following installation directories from your system: - Windows: ${CMAKE_INSTALL_PREFIX}/doc/scripts - Others: ${CMAKE_INSTALL_PREFIX}/share/doc/GeographicLib/scripts - Version 1.45 (released 2015-09-30) - Fix BUG in solution of inverse geodesic caused by misbehavior of some versions of Visual Studio on Windows (fmod(−0.0, 360.0) returns +0.0 instead of −0.0) and Octave (sind(−0.0) returns +0.0 instead of −0.0). These bugs were exposed because max(−0.0, +0.0) returns −0.0 for some languages. - Geodesic::Inverse now correctly returns NaNs if one of the latitudes is a NaN. - Changes to JavaScript package: - thanks to help from Yurij Mikhalevich, it is a now a node package that can be installed with npm; - make install now installs the node package in lib/node_modules/geographiclib; - add unit tests using mocha; - add documentation via JSDoc; - fix bug Geodesic.GenInverse (this bug, introduced in version 1.44, resulted in the wrong azimuth being reported for points at the pole). - Changes to Java package: - add implementation of ellipsoidal Gnomonic projection (courtesy of Sebastian Mattheis); - add unit tests using JUnit; - Math.toRadians and Math.toDegrees are used instead of GeoMath.degree (which is now removed), as a result… - Java version 1.2 (released 1998-12) or later is now required. - Changes to Python package: - add unit tests using the unittest framework; - fixed bug in normalization of the area. - Changes to MATLAB package: - fix array size mismatch in geoddistance by avoiding calls to subfunctions with zero-length arrays; - fix tranmerc_{fwd,inv} so that they work with arrays and mixed array/scalar arguments; - work around Octave problem which causes mgrs_fwd to return garbage with prec = 10 or 11; - add geographiclib_test.m to run a test suite. - Behavior of substituting 1/\e f for \e f if \e f > 1 is now deprecated. This behavior has been removed from the JavaScript, C, and Python implementations (it was never documented). Maxima, MATLAB, and Fortran implementations never included this behavior. - Other changes: - fix bug, introduced in version 1.42, in the C++ implementation to the computation of area which causes NaNs to be returned in the case of a sphere; - fixed bug, introduced in version 1.44, in the detection of C++11 math functions in configure.ac; - throw error on non-convergence in Gnomonic::Reverse if GEOGRAPHICLIB_PRECISION > 3; - add geod_polygon_clear to C library; - turn illegal latitudes into NaNs for Fortran library; - add test suites for the C and Fortran libraries. - Version 1.44 (released 2015-08-14) - Various changes to improve accuracy, e.g., by minimizing round-off errors: - Add Math::sincosd, Math::sind, Math::cosd which take their arguments in degrees. These functions do exact range reduction and thus they obey exactly the elementary properties of the trigonometric functions, e.g., sin 9° = cos 81° = − sin 123456789°. - Math::AngNormalize now works for any angles, instead of angles in the range [−540°, 540°); the function Math::AngNormalize2 is now deprecated. - This means that there is now no restriction on longitudes and azimuths; any values can be used. - Improve the accuracy of Math::atan2d. - DMS::Decode avoids unnecessary round-off errors; thus 7:33:36 and 7.56 result in identical values. DMS::Encode rounds ties to even. These changes have also been made to DMS.js. - More accurate rounding in MGRS::Reverse and mgrs_inv.m; this change only makes a difference at sub-meter precisions. - With MGRS::Forward and mgrs_fwd.m, ensure that digits in lower precision results match those at higher precision; as a result, strings of trailing 9s are less likely to be generated. This change only makes a difference at sub-meter precisions. - Replace the series for A2 in the Geodesic class with one with smaller truncation errors. - Geodesic::Inverse sets \e s12 to zero for coincident points at pole (instead of returning a tiny quantity). - Math::LatFix returns its argument if it is in [−90°, 90°]; if not, it returns NaN. - Using Math::LatFix, routines which don't check their arguments now interpret a latitude outside the legal range of [−90°, 90°] as a NaN; such routines will return NaNs instead of finite but incorrect results; caution: code that (dangerously) relied on the "reasonable" results being returned for values of the latitude outside the allowed range will now malfunction. - All the \ref utilities accept the -w option to swap the latitude-longitude order on input and output (and where appropriate on the command-line arguments). CartConvert now accepts the -p option to set the precision; now all of the utilities except GeoidEval accept -p. - Add classes for GARS, the Global Area Reference System, and for Georef, the World Geographic Reference System. - Changes to DMS::Decode and DMS.js: - tighten up the rules: - 30:70.0 and 30:60 are illegal (minutes and second must be strictly less than 60), however - 30:60.0 and 30:60. are legal (floating point 60 is OK, since it might have been generated by rounding 59.99…); - generalize a+b concept, introduced in version 1.42, to any number of pieces; thus 8+0:40-0:0:10 is interpreted as 8:39:50. - Documentation fixes: - update man pages to refer to GeoConvert(1) on handling of geographic coordinates; - document limitations of the series used for TransverseMercator; - hide the documentation of the computation of the gradient of the geoid height (now deprecated) in the Geoid class; - warn about the possible misinterpretation of 7.0E+1 by DMS::Decode; - \e swaplatlong optional argument of DMS::DecodeLatLon and various functions in the GeoCoords class is now called \e longfirst; - require Doxygen 1.8.7 or later. - More systematic treatment of version numbers: - Python: \__init\__.py defines \__version\__ and \__version_info\__; - JavaScript: - Math.js defines Constants.version and Constants.version_string; - version number included as comment in packed script geographiclib.js; - geod-calc.html and geod-google.html report the version number; - https://geographiclib.sourceforge.io/scripts/ gives access to earlier versions of geographiclib.js as geographiclib-m.nn.js; - Fortran: add geover subroutine to return version numbers; - Maxima: geodesic.mac defines geod_version; - CGI scripts: these report the version numbers of the utilities. - BUG FIXES: - NormalGravity now works properly for a sphere (\e omega = \e f = \e J2 = 0), instead of returning NaNs (problem found by htallon); - CassiniSoldner::Forward and cassini_fwd.m now returns the correct azimuth for points at the pole. - MATLAB-specific fixes: - mgrs_fwd now treats treats prec > 11 as prec = 11; - illegal letter combinations are now correctly detected by mgrs_inv; - fixed bug where mgrs_inv returned the wrong results for prec = 0 strings and center = 0; - mgrs_inv now decodes prec = 11 strings properly; - routines now return array results with the right shape; - routines now properly handle mixed scalar and array arguments. - Add Accumulator::operator*=(T y). - Geohash uses "invalid" instead of "nan" when the latitude or longitude is a nan. - Version 1.43 (released 2015-05-23) - Add the Enhanced Magnetic Model 2015, emm2015. This is valid for 2000 thru the end of 2019. This required some changes in the MagneticModel and MagneticCircle classes; so this model cannot be used with versions of GeographicLib prior to 1.43. - Fix BLUNDER in PolarStereographic constructor introduced in version 1.42. This affected UTMUPS conversions for UPS which could be incorrect by up to 0.5 km. - Changes in the LONG_NOWRAP option (added in version 1.39) in the Geodesic and GeodesicLine classes: - The option is now called LONG_UNROLL (a less negative sounding term); the original name, LONG_NOWRAP, is retained for backwards compatibility. - There were two bad BUGS in the implementation of this capability: (a) it gave incorrect results for west-going geodesics; (b) the option was ignored if used directly via the GeodesicLine class. The first bug affected the implementations in all languages. The second affected the implementation in C++ (GeodesicLine and GeodesicLineExact), JavaScript, Java, C, Python. These bugs have now been FIXED. - The GeodSolve utility now accepts a -u option, which turns on the LONG_UNROLL treatment. With this option lon1 is reported as entered and lon2 is given such that lon2lon1 indicates how often and in what sense the geodesic has encircled the earth. (This option also affects the value of longitude reported when an inverse calculation is run with the -f option.) - The inverse calculation with the JavaScript and Python libraries similarly sets lon1 and lon2 in output dictionary respecting the LONG_UNROLL flag. - The online version of GeodSolve now offers an option to unroll the longitude. - To support these changes DMS::DecodeLatLon no longer reduces the longitude to the range [−180°, 180°) and Math::AngRound now coverts −0 to +0. - Add Math::polyval (also to C, Java, JavaScript, Fortran, Python versions of the library; this is a built-in function for MATLAB/Octave). This evaluates a polynomial using Horner's method. The Maxima-generated code fragments for the evaluation of series in the Geodesic, TransverseMercator, and Rhumb classes and MATLAB routines for great ellipses have been replaced by Maxima-generated arrays of polynomial coefficients which are used as input to Math::polyval. - Add MGRS::Check() to verify that \e a, \e f, kUTM, and kUPS are consistent with the assumptions in the UTMUPS and MGRS classes. This is invoked with GeoConvert \--version. (This function was added to document and check the assumptions used in the UTMUPS and MGRS classes in case they are extended to deal with ellipsoids other than WS84.) - MATLAB function mgrs_inv now takes an optional \e center argument and strips white space from both beginning and end of the string. - Minor internal changes: - GeodSolve sets the geodesic mask so that unnecessary calculations are avoided; - some routines have migrated into a math class for the Python, Java, and JavaScript libraries. - A reminder: because of changes in the installation directories for non-Windows systems introduced in version 1.42, you should remove the following directories from your system: - ${CMAKE_INSTALL_PREFIX}/share/cmake/GeographicLib* - ${CMAKE_INSTALL_PREFIX}/libexec/GeographicLib/matlab - Version 1.42 (released 2015-04-28) - DMS::Decode allows a single addition or subtraction operation, e.g., 70W+0:0:15. This affects the GeoCoords class and the utilities (which use the DMS class for reading coordinates). - Add Math::norm, Math::AngRound, Math::tand, Math::atan2d, Math::eatanhe, Math::taupf, Math::tauf, Math::fma and remove duplicated (but private) functionality from other classes. - On non-Windows systems, the cmake config-style find_package files are now installed under ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} instead of ${CMAKE_INSTALL_PREFIX}/share, because the files are architecture-specific. This change will let 32-bit and 64-bit versions coexist on the same machine (in lib and lib64). You should remove the versions in the old "share" location. - MATLAB changes: - provide native MATLAB implementations for compiled interface functions, see \ref matlab; - the compiled MATLAB interface is now deprecated and so the MATLAB_COMPILER option in the cmake build has been removed; - reorganize directories, so that - matlab/geographiclib contains the native matlab code; - matlab/geographiclib-legacy contains wrapper functions to mimic the previous compiled functionality; - the installed MATLAB code mirrors this layout, but the parent installation directory on non-Windows systems is ${CMAKE_INSTALL_PREFIX}/share (instead of ${CMAKE_INSTALL_PREFIX}/libexec), because the files are now architecture independent; - matlab/geographiclib is now packaged and distributed as MATLAB File Exchange package 50605 (this supersedes three earlier MATLAB packages); - point fix for geodarea.m to correct bug in area of polygons which encircle a pole multiple times (released as version 1.41.1 of MATLAB File Exchange package 39108, 2014-04-22). - artifactId for Java package changed from GeographicLib to GeographicLib-Java and the package is now deployed to Maven Central (thanks to Chris Bennight for help on this). - Fix autoconf mismatch of version numbers (which were inconsistent in versions 1.40 and 1.41). - Mark the computation of the gradient of the geoid height in the Geoid class and the GeoidEval utility as deprecated. - Work around the boost-quadmath bug with setprecision(0). - Deprecate use of Visual Studio 2005 "-vc8" project files in the windows directory. - Version 1.41 (released 2015-03-09) - Fix bug in Rhumb::Inverse (with \e exact = true) and related functions which causes the wrong distance to be reported if one of the end points is at a pole. Thanks to Thomas Murray for reporting this. - Add International Geomagnetic Reference Field (12th generation), which approximates the main magnetic field of the earth for the period 1900--2020. - Split information about \ref jacobi to a separate section and include more material. - Version 1.40 (released 2014-12-18) - Add the World Magnetic Model 2015, wmm2015. This is now the default magnetic model for MagneticField (replacing wmm2010 which is valid thru the end of 2014). - Geodesic::Inverse didn't return NaN if one of the longitudes was a NaN (bug introduced in version 1.25). Fixed in the C++, Java, JavaScript, C, Fortran, and Python implementations of the geodesic routines. This bug was not present in the MATLAB version. - Fix bug in Utility::readarray and Utility::writearray which caused an exception in debug mode with zero-sized arrays. - Fix BLUNDER in OSGB::GridReference (found by kalderami) where the wrong result was returned if the easting or northing was negative. - OSGB::GridReference now returns "INVALID" if either coordinate is NaN. Similarly a grid reference starting with "IN" results in NaNs for the coordinates. - Default constructor for GeoCoords corresponds to an undefined position (latitude and longitude = NaN), instead of the north pole. - Add an online version of RhumbSolve at https://geographiclib.sourceforge.io/cgi-bin/RhumbSolve. - Additions to the documentation: - documentation on \ref triaxial-conformal; - a page on \ref auxlat (actually, this was added in version 1.39); - document the use of two single quotes to stand for a double quote in DMS (this feature was introduced in version 1.13). - The MATLAB function, geographiclibinterface, which compiles the wrapper routines for MATLAB now works with MATLAB on a Mac. - Version 1.39 (released 2014-11-11) - GeographicLib usually normalizes longitudes to the range [−180°, 180°). However, when solving the direct geodesic and rhumb line problems, it is sometimes necessary to know how many lines the line encircled the earth by returning the longitude "unwrapped". So the following changes have been made: - add a LONG_NOWRAP flag to \e mask enums for the \e outmask arguments for Geodesic, GeodesicLine, Rhumb, and RhumbLine; - similar changes have been made to the Python, JavaScript, and Java implementations of the geodesic routines; - for the C, Fortran, and MATLAB implementations the \e arcmode argument to the routines was generalized to allow a combination of ARCMODE and LONG_NOWRAP bits; - the Maxima version now returns the longitude unwrapped. . These changes were necessary to fix the PolygonAreaT::AddEdge (see the next item). - Changes in area calculations: - fix BUG in PolygonAreaT::AddEdge (also in C, Java, JavaScript, and Python implementations) which sometimes causes the wrong area to be returned if the edge spanned more than 180°; - add area calculation to the Rhumb and RhumbLine classes and the RhumbSolve utility (see \ref rhumbarea); - add PolygonAreaRhumb typedef for PolygonAreaT; - add -R option to Planimeter to use PolygonAreaRhumb (and -G option for the default geodesic polygon); - fix BLUNDER in area calculation in MATLAB routine geodreckon; - add area calculation to MATLAB/Octave routines for great ellipses (see \ref gearea). - Fix bad BUG in Geohash::Reverse; this was introduced in version 1.37 and affected all platforms where unsigned longs are 32-bits. Thanks to Christian Csar for reporting and diagnosing this. - Binary installers for Windows are now built with Visual Studio 11 2012 (instead of Visual Studio 10 2010). Compiled MATLAB support still with version 2013a (64-bit). - Update GeographicLib.pro for builds with qmake to include all the source files. - Cmake updates: - include cross-compiling checks in cmake config file; - improve the way unsuitable versions are reported; - include_directories (${GeographicLib_INCLUDE_DIRS}) is no longer necessary with cmake 2.8.11 or later. - legacy/Fortran now includes drop-in replacements for the geodesic utilities from the NGS. - geographiclib-get-{geoids,gravity,magnetic} with no arguments now print the usage instead of loading the minimal sets. - Utility::date(const std::string&, int&, int&, int&) and hence the MagneticField utility accepts the string "now" as a legal time (meaning today). - Version 1.38 (released 2014-10-02) - On MacOSX, the installed package is relocatable (for cmake version 2.8.12 and later). - On Mac OSX, GeographicLib can be installed using homebrew. - In cmake builds under Windows, set the output directories so that binaries and shared libraries are together. - Accept the minus sign as a synonym for - in DMS.{cpp,js}. - The cmake configuration file geographiclib-depends.cmake has been renamed to geographiclib-targets.cmake. - MATLAB/Octave routines for great ellipses added; see \ref greatellipse. - Provide man pages for geographiclib-get-{geoids,gravity,magnetic}. - Version 1.37 (released 2014-08-08) - Add \ref highprec. - INCOMPATIBLE CHANGE: the static instantiations of various classes for the WGS84 ellipsoid have been changed to a "construct on first use idiom". This avoids a lot of wasteful initialization before the user's code starts. Unfortunately it means that existing source code that relies on any of the following static variables will need to be changed to a function call: - AlbersEqualArea::AzimuthalEqualAreaNorth - AlbersEqualArea::AzimuthalEqualAreaSouth - AlbersEqualArea::CylindricalEqualArea - Ellipsoid::WGS84 - Geocentric::WGS84 - Geodesic::WGS84 - GeodesicExact::WGS84 - LambertConformalConic::Mercator - NormalGravity::GRS80 - NormalGravity::WGS84 - PolarStereographic::UPS - TransverseMercator::UTM - TransverseMercatorExact::UTM . Thus, occurrences of, for example, \code const Geodesic& geod = Geodesic::WGS84; // version 1.36 and earlier \endcode need to be changed to \code const Geodesic& geod = Geodesic::WGS84(); // version 1.37 and later \endcode (note the parentheses!); alternatively use \code // works with all versions const Geodesic geod(Constants::WGS84_a(), Constants::WGS84_a()); \endcode - Incompatible change: the environment variables {GEOID,GRAVITY,MAGNETIC}_{NAME,PATH} are now prefixed with GEOGRAPHICLIB_. - Incompatible change for Windows XP: retire the Windows XP common data path. If you're still using Windows XP, then you might have to move the folder C:\\Documents and Settings\\All Users\\Application Data\\GeographicLib to C:\\ProgramData\\GeographicLib. - All macro names affecting the compilation now start with GEOGRAPHICLIB_; this applies to GEOID_DEFAULT_NAME, GRAVITY_DEFAULT_NAME, MAGNETIC_DEFAULT_NAME, PGM_PIXEL_WIDTH, HAVE_LONG_DOUBLE, STATIC_ASSERT, WORDS_BIGENDIAN. - Changes to PolygonArea: - introduce PolygonAreaT which takes a geodesic class as a parameter; - PolygonArea and PolygonAreaExact are typedef'ed to PolygonAreaT and PolygonAreaT; - add -E option to Planimeter to use PolygonAreaExact; - add -Q option to Planimeter to calculate the area on the authalic sphere. - Add -p option to Planimeter, ConicProj, GeodesicProj, TransverseMercatorProj. - Add Rhumb and RhumbLine classes and the RhumbSolve utility; see \ref rhumb for more information. - Minor changes to NormalGravity: - add NormalGravity::J2ToFlattening and NormalGravity::FlatteningToJ2; - use Newton's method to determine \e f from \e J2; - in constructor, allow \e omega = 0 (i.e., treat the spherical case). - Add grs80 GravityModel, see \ref gravity. - Make geographiclib-get-{geoids,gravity,magnetic} scripts work on MacOS. - Minor changes: - simplify cross-platform support for C++11 mathematical functions; - change way area coefficients are given in GeodesicExact to improve compile times; - enable searching the online documentation; - add macros GEOGRAPHICLIB_VERSION and GEOGRAPHICLIB_VERSION_NUM; - add solution and project files for Visual Studio Express 2010. - Version 1.36 (released 2014-05-13) - Changes to comply with NGA's prohibition of the use of the upper-case letters N/S to designate the hemisphere when displaying UTM/UPS coordinates: - UTMUPS::DecodeZone allows north/south as hemisphere designators (in addition to n/s); - UTMUPS::EncodeZone now encodes the hemisphere in lower case (to distinguish this use from a grid zone designator); - UTMUPS::EncodeZone takes an optional parameter \e abbrev to indicate whether to use n/s or north/south as the hemisphere designator; - GeoCoords::UTMUPSRepresentation and GeoCoords::AltUTMUPSRepresentation similarly accept the \e abbrev parameter; - GeoConvert uses the flags -a and -l to govern whether UTM/UPS output uses n/s (the -a flag) or north/south (the -l flag) to denote the hemisphere; - Fixed a bug what allowed +3N to be accepted as an alternative UTM zone designation (instead of 3N). . WARNING: The use of lower case n/s for the hemisphere might cause compatibility problems. However DecodeZone has always accepted either case; so the issue will only arise with other software reading the zone information. To avoid possible misinterpretation of the zone designator, consider calling EncodeZone with \e abbrev = false and GeoConvert with -l, so that north/south are used to denote the hemisphere. - MGRS::Forward with \e prec = −1 will produce a grid zone designation. Similarly MGRS::Reverse will decode a grid zone designation (and return \e prec = −1). - Stop using the throw() declaration specification which is deprecated in C++11. - Add missing std:: qualifications to copy in LocalCartesion and Geocentric headers (bug found by Clemens). - Version 1.35 (released 2014-03-13) - Fix blunder in UTMUPS::EncodeEPSG (found by Ben Adler). - MATLAB wrapper routines geodesic{direct,inverse,line} switch to "exact" routes if |f| > 0.02. - GeodSolve.cgi allows ellipsoid to be set (and uses the -E option for GeodSolve). - Set title in HTML versions of man pages for the \ref utilities. - Changes in cmake support: - add _d to names of executables in debug mode of Visual Studio; - add support for Android (cmake-only), thanks to Pullan Yu; - check CPACK version numbers supplied on command line; - configured version of project-config.cmake.in is project-config.cmake (instead of geographiclib-config.cmake), to prevent find_package incorrectly using this file; - fix tests with multi-line output; - this release includes a file, pom.xml, which is used by an experimental build system (based on maven) at SRI. - Version 1.34 (released 2013-12-11) - Many changes in cmake support: - minimum version of cmake needed increased to 2.8.4 (which was released in 2011-02); - allow building both shared and static libraries with -D GEOGRAPHICLIB_LIB_TYPE=BOTH; - both shared and static libraries (Release plus Debug) included in binary installer; - find_package uses COMPONENTS and GeographicLib_USE_STATIC_LIBS to select the library to use; - find_package version checking allows nmake and Visual Studio generators to interoperate on Windows; - find_package (GeographicLib …) requires that GeographicLib be capitalized correctly; - on Unix/Linux, don't include the version number in directory for the cmake configuration files; - defaults for GEOGRAPHICLIB_DOCUMENTATION and BUILD_NETGEOGRAPHICLIB are now OFF; - the GEOGRAPHICLIB_EXAMPLES configuration parameter is no longer used; cmake always configures to build the examples, but they are not built by default (instead build targets: exampleprograms and netexamples); - matlab-all target renamed to matlabinterface; - the configuration parameters PACKAGE_PATH and INSTALL_PATH are now deprecated (use CMAKE_INSTALL_PREFIX instead); - on Linux, the installed package is relocatable; - on MacOSX, the installed utilities can find the shared library. - Use a more precise value for OSGB::CentralScale(). - Add Arc routines to Python interface. - The Geod utility has been removed; the same functionality lives on with GeodSolve (introduced in version 1.30). - Version 1.33 (released 2013-10-08) - Add NETGeographic .NET wrapper library (courtesy of Scott Heiman). - Make inspector functions in Ellipsoid const. - Add Accumulator.cpp to instantiate Accumulator. - Defer some of the initialization of OSGB to when it is first called. - Fix bug in autoconf builds under MacOS. - Version 1.32 (released 2013-07-12) - Generalize C interface for polygon areas to allow vertices to be specified incrementally. - Fix way flags for C++11 support are determined. - Version 1.31 (released 2013-07-01) - Changes breaking binary compatibility (source compatibility is maintained): - overloaded versions of DMS::Encode, EllipticFunction::EllipticFunction, and GeoCoords::DMSRepresentation, have been eliminated by the use of optional arguments; - correct the declaration of first arg to UTMUPS::DecodeEPSG. - FIX BUG in GravityCircle constructor (found by Mathieu Peyréga) which caused bogus results for the gravity disturbance and gravity anomaly vectors. (This only affected calculations using GravityCircle. GravityModel calculations did not suffer from this bug.) - Improvements to the build: - add macros GEOGRAPHICLIB_VERSION_{MAJOR,MINOR,PATCH} to Config.h; - fix documentation for new version of perlpod; - improving setting of runtime path for Unix-like systems with cmake; - install PDB files when compiling with Visual Studio to aid debugging; - Windows binary release now uses MATLAB R2013a (64-bit) and uses the -largeArrayDims option. - fixes to the way the MATLAB interface routines are built (thanks to Phil Miller and Chris F.). - Changes to the geodesic routines: - add \ref java of the geodesic routines (thanks to Skip Breidbach for the maven support); - FIX BUG: avoid altering input args in Fortran implementation; - more systematic treatment of very short geodesic; - fixes to Python port so that they work with version 3.x, in addition to 2.x (courtesy of Amato); - accumulate the perimeter and area of polygons via a double-wide accumulator in Fortran, C, and MATLAB implementations (this is already included in the other implementations); - port PolygonArea::AddEdge and PolygonArea::TestEdge to JavaScript and Python interfaces; - include documentation on \ref geodshort. - Unix scripts for downloading datasets, geographiclib-get-{geoids,gravity,magnetic}, skip already download models by default, unless the -f flag is given. - FIX BUGS: meridian convergence and scale returned by TransverseMercatorExact was wrong at a pole. - Improve efficiency of MGRS::Forward by avoiding the calculation of the latitude if possible (adapting an idea of Craig Rollins). - Fixes to the way the MATLAB interface routines are built (thanks to Phil Miller and Chris F.). - Version 1.30 (released 2013-02-27) - Changes to geodesic routines: - FIX BUG in fail-safe mechanisms in Geodesic::Inverse; - the command line utility Geod is now called GeodSolve; - allow addition of polygon edges in PolygonArea; - add full Maxima implementation of geodesic algorithms. - Version 1.29 (released 2013-01-16) - Changes to allow compilation with libc++ (courtesy of Kal Conley). - Add description of \ref triaxial to documentation. - Update journal reference for "Algorithms for geodesics". - Version 1.28 (released 2012-12-11) - Changes to geodesic routines: - compute longitude difference exactly; - hence FIX BUG in area calculations for polygons with vertices very close to the prime meridian; - FIX BUG is geoddistance.m where the value of m12 was wrong for meridional geodesics; - add MATLAB implementations of the geodesic projections; - remove unneeded special code for geodesics which start at a pole; - include polygon area routine in C and Fortran implementations; - add doxygen documentation for C and Fortran libraries. - Version 1.27 (released 2012-11-29) - Changes to geodesic routines: - add native MATLAB implementations: geoddistance.m, geodreckon.m, geodarea.m; - add C and Fortran implementations; - improve the solution of the direct problem so that the series solution is accurate to round off for |f| < 1/50; - tighten up the convergence criteria for solution of the inverse problem; - no longer signal failures of convergence with NaNs (a slightly less accurate answer is returned instead). - Fix DMS::Decode double rounding BUG. - On MacOSX platforms with the cmake configuration, universal binaries are built. - Version 1.26 (released 2012-10-22) - Replace the series used for geodesic areas by one with better convergence (this only makes an appreciable difference if |f| > 1/150). - Version 1.25 (released 2012-10-16) - Changes to geodesic calculations: - restart Newton's method in Geodesic::Inverse when it goes awry; - back up Newton's method with the bisection method; - Geodesic::Inverse now converges for any value of \e f; - add GeodesicExact and GeodesicLineExact which are formulated in terms of elliptic integrals and thus yield accurate results even for very eccentric ellipsoids; - the -E option to Geod invokes these exact classes. - Add functionality to EllipticFunction: - add all the traditional elliptic integrals; - remove restrictions on argument range for incomplete elliptic integrals; - allow imaginary modulus for elliptic integrals and elliptic functions; - make interface to the symmetric elliptic integrals public. - Allow Ellipsoid to be copied. - Changes to the build tools: - cmake uses folders in Visual Studio to reduce clutter; - allow precision of reals to be set in cmake; - fail gracefully in the absence of pod documentation tools; - remove support for maintainer tasks in Makefile.mk; - upgrade to automake 1.11.6 to fix the "make distcheck" security vulnerability; see https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-3386 - Version 1.24 (released 2012-09-22) - Allow the specification of the hemisphere in UTM coordinates in order to provide continuity across the equator: - add UTMUPS::Transfer; - add GeoCoords::UTMUPSRepresentation(bool, int) and GeoCoords::AltUTMUPSRepresentation(bool, int); - use the hemisphere letter in, e.g., GeoConvert -u -z 31n. - Add UTMUPS::DecodeEPSG and UTMUPS::EncodeEPSG. - cmake changes: - restore support for cmake 2.4.x; - explicitly check version of doxygen. - Fix building under cygwin. - Document restrictions on \e f in \ref intro. - Fix Python interface to work with version 2.6.x. - Version 1.23 (released 2012-07-17) - Documentation changes: - remove html documentation from distribution and use web links if doxygen is not available; - use doxygen tags to document exceptions; - begin migrating the documentation to using Greek letters where appropriate (requires doxygen 1.8.1.2 or later). - Add Math::AngNormalize and Math::AngNormalize2; the allowed range for longitudes and azimuths widened to [−540°, 540°). - DMS::Decode understands more unicode symbols. - Geohash uses geohash code "nan" to stand for not a number. - Add Ellipsoid::NormalCurvatureRadius. - Various fixes in LambertConformalConic, TransverseMercator, PolarStereographic, and Ellipsoid to handle reverse projections of points near infinity. - Fix programming blunder in LambertConformalConic::Forward (incorrect results were returned if the tangent latitude was negative). - Version 1.22 (released 2012-05-27) - Add Geohash and Ellipsoid classes. - FIX BUG in AlbersEqualArea for very prolate ellipsoids (b2 > 2 a2). - cmake changes: - optionally use PACKAGE_PATH and INSTALL_PATH to determine CMAKE_INSTALL_PREFIX; - use COMMON_INSTALL_PATH to determine layout of installation directories; - as a consequence, the installation paths for the documentation, and Python and MATLAB interfaces are shortened for Windows; - zip source distribution now uses DOS line endings; - the tests work in debug mode for Windows; - default setting of GEOGRAPHICLIB_DATA does not depend on CMAKE_INSTALL_PREFIX; - add a cmake configuration for build tree. - Version 1.21 (released 2012-04-25) - Support colon-separated DMS output: - DMS::Encode and GeoCoords::DMSRepresentation generalized; - GeoConvert and Geod now accept a -: option. - GeoidEval does not print the gradient of the geoid height by default (because it's subject to large errors); give the -g option to get the gradient printed. - Work around optimization BUG in Geodesic::Inverse with tdm mingw g++ version 4.6.1. - autoconf fixed to ensure that that out-of-sources builds work; document this as the preferred method of using autoconf. - cmake tweaks: - simplify the configuration of doxygen; - allow the MATLAB compiler to be specified with the MATLAB_COMPILER option. - Version 1.20 (released 2012-03-23) - cmake tweaks: - improve find_package's matching of compiler versions; - CMAKE_INSTALL_PREFIX set from CMAKE_PREFIX_PATH if available; - add "x64" to the package name for the 64-bit binary installer; - fix cmake warning with Visual Studio Express. - Fix SphericalEngine to deal with aggressive iterator checking by Visual Studio. - Fix transcription BUG is Geodesic.js. - Version 1.19 (released 2012-03-13) - Slight improvement in Geodesic::Inverse for very short lines. - Fix argument checking tests in MGRS::Forward. - Add \--comment-delimiter and \--line-separator options to the \ref utilities. - Add installer for 64-bit Windows; the compiled MATLAB interface is supplied with the Windows 64-bit installer only. - Version 1.18 (released 2012-02-18) - Improve documentation on configuration with cmake. - cmake's find_package ensures that the compiler versions match on Windows. - Improve documentation on compiling MATLAB interface. - Binary installer for Windows installs under C:/pkg-vc10 by default. - Version 1.17 (released 2012-01-21) - Work around optimization BUG in Geodesic::Inverse with g++ version 4.4.0 (mingw). - Fix BUG in argument checking with OSGB::GridReference. - Fix missing include file in SphericalHarmonic2. - Add simple examples of usage for each class. - Add internal documentation to the cmake configuration files. - Version 1.16 (released 2011-12-07) - Add calculation of the earth's gravitational field: - add NormalGravity GravityModel and GravityCircle classes; - add command line utility Gravity; - add \ref gravity; - add Constants::WGS84_GM(), Constants::WGS84_omega(), and similarly for GRS80. - Build uses GEOGRAPHICLIB_DATA to specify a common parent directory for geoid, gravity, and magnetic data (instead of GEOGRAPHICLIB_GEOID_PATH, etc.); similarly, GeoidEval, Gravity, and MagneticField, look at the environment variable GEOGRAPHICLIB_DATA to locate the data. - Spherical harmonic software changes: - capitalize enums SphericalHarmonic::FULL and SphericalHarmonic::SCHMIDT (the lower case names are retained but deprecated); - optimize the sum by using a static table of square roots which is updated by SphericalEngine::RootTable; - avoid overflow for high degree models. - Magnetic software fixes: - fix documentation BUG in MagneticModel::Circle; - make MagneticModel constructor explicit; - provide default MagneticCircle constructor; - add additional inspector functions to MagneticCircle; - add -c option to MagneticField; - default height to zero in MagneticField. - Version 1.15 (released 2011-11-08) - Add calculation of the earth's magnetic field: - add MagneticModel and MagneticCircle classes; - add command line utility MagneticField; - add \ref magnetic; - add \ref magneticinst; - add \ref magneticformat; - add classes SphericalEngine, CircularEngine, SphericalHarmonic, SphericalHarmonic1, and SphericalHarmonic2. which sum spherical harmonic series. - Add Utility class to support I/O and date manipulation. - Cmake configuration includes a _d suffix on the library built in debug mode. - For the Python package, include manifest and readme files; don't install setup.py for non-Windows systems. - Include Doxygen tag file in distribution as doc/html/Geographic.tag. - Version 1.14 (released 2011-09-30) - Ensure that geographiclib-config.cmake is relocatable. - Allow more unicode symbols to be used in DMS::Decode. - Modify GeoidEval so that it can be used to convert the height datum for LIDAR data. - Modest speed-up of Geodesic::Inverse. - Changes in Python interface: - FIX BUG in transcription of Geodesic::Inverse; - include setup.py for easy installation; - Python only distribution is available at https://pypi.python.org/pypi/geographiclib - Supply a minimal Qt qmake project file for library src/Geographic.pro. - Version 1.13 (released 2011-08-13) - Changes to I/O: - allow : (colon) to be used as a DMS separator in DMS::Decode(const std::string&, flag&); - also accept Unicode symbols for degrees, minutes, and seconds (coded as UTF-8); - provide optional \e swaplatlong argument to various DMS and GeoCoords functions to make longitude precede latitude; - GeoConvert now has a -w option to make longitude precede latitude on input and output; - include a JavaScript version of DMS. - Slight improvement in starting guess for solution of geographic latitude in terms of conformal latitude in TransverseMercator, TransverseMercatorExact, and LambertConformalConic. - For most classes, get rid of const member variables so that the default copy assignment works. - Put Math and Accumulator in their own header files. - Remove unused "fast" Accumulator method. - Reorganize the \ref python. - Withdraw some deprecated routines. - cmake changes: - include FindGeographic.cmake in distribution; - building with cmake creates and installs geographiclib-config.cmake; - better support for building a shared library under Windows. - Version 1.12 (released 2011-07-21) - Change license to MIT/X11. - Add PolygonArea class and equivalent MATLAB function. - Provide JavaScript and Python implementations of geodesic routines. - Fix Windows installer to include runtime dlls for MATLAB. - Fix (innocuous) unassigned variable in Geodesic::GenInverse. - Geodesic routines in MATLAB return a12 as first column of aux return value (incompatible change). - A couple of code changes to enable compilation with Visual Studio 2003. - Version 1.11 (released 2011-06-27) - Changes to Planimeter: - add -l flag to Planimeter for polyline calculations; - trim precision of area to 3 decimal places; - FIX BUG with pole crossing edges (due to compiler optimization). - Geod no longer reports the reduced length by default; however the -f flag still reports this and in addition gives the geodesic scales and the geodesic area. - FIX BUGS (compiler-specific) in inverse geodesic calculations. - FIX BUG: accommodate tellg() returning −1 at end of string. - Change way flattening of the ellipsoid is specified: - constructors take \e f argument which is taken to be the flattening if \e f < 1 and the inverse flattening otherwise (this is a compatible change for spheres and oblate ellipsoids, but it is an INCOMPATIBLE change for prolate ellipsoids); - the -e arguments to the \ref utilities are handled similarly; in addition, simple fractions, e.g., 1/297, can be used for the flattening; - introduce Constants::WGS84_f() for the WGS84 flattening (and deprecate Constants::WGS84_r() for the inverse flattening); - most classes have a Flattening() member function; - InverseFlattening() has been deprecated (and now returns inf for a sphere, instead of 0). - Version 1.10 (released 2011-06-11) - Improvements to MATLAB/Octave interface: - add {geocentric,localcartesian}{forward,reverse}; - make geographiclibinterface more general; - install the source for the interface; - cmake compiles the interface if ENABLE_MATLAB=ON; - include compiled interface with Windows binary installer. - Fix various configuration issues - autoconf did not install Config.h; - cmake installed in man/man1 instead of share/man/man1; - cmake did not set the rpath on the tools. - Version 1.9 (released 2011-05-28) - FIX BUG in area returned by Planimeter for pole encircling polygons. - FIX BUG in error message reported when DMS::Decode reads the string "5d.". - FIX BUG in AlbersEqualArea::Reverse (lon0 not being used). - Ensure that all exceptions thrown in the \ref utilities are caught. - Avoid using catch within DMS. - Move Accumulator class from Planimeter.cpp to Constants.hpp. - Add Math::sq. - Simplify \ref geoidinst - add geographiclib-get-geoids for Unix-like systems; - add installers for Windows. - Provide cmake support: - build binary installer for Windows; - include regression tests; - add \--input-string, \--input-file, \--output-file options to the \ref utilities to support tests. - Rename utility EquidistantTest as GeodesicProj and TransverseMercatorTest as TransverseMercatorProj. - Add ConicProj. - Reverse the initial sense of the -s option for Planimeter. - Migrate source from subversion to git. - Version 1.8 (released 2011-02-22) - Optionally return rotation matrix from Geocentric and LocalCartesian. - For the \ref utilities, supply man pages, -h prints the synopsis, \--help prints the man page, \--version prints the version. - Use accurate summation in Planimeter. - Add 64-bit targets for Visual Studio 2010. - Use templates for defining math functions and some constants. - Geoid updates - Add Geoid::DefaultGeoidPath and Geoid::DefaultGeoidName; - GeoidEval uses environment variable GEOGRAPHICLIB_GEOID_NAME as the default geoid; - Add \--msltohae and \--haetomsl as GeoidEval options (and don't document the single hyphen versions). - Remove documentation that duplicates papers on transverse Mercator and geodesics. - Version 1.7 (released 2010-12-21) - FIX BUG in scale returned by LambertConformalConic::Reverse. - Add AlbersEqualArea projection. - Library created by Visual Studio is Geographic.lib instead of GeographicLib.lib (compatible with makefiles). - Make classes NaN aware. - Use cell arrays for MGRS strings in MATLAB. - Add solution/project files for Visual Studio 2010 (32-bit only). - Use C++11 static_assert and math functions, if available. - Version 1.6 (released 2010-11-23) - FIX BUG introduced in Geoid in version 1.5 (found by Dave Edwards). - Version 1.5 (released 2010-11-19) - Improve area calculations for small polygons. - Add -s and -r flags to Planimeter. - Improve the accuracy of LambertConformalConic using divided differences. - FIX BUG in meridian convergence returned by LambertConformalConic::Forward. - Add optional threadsafe parameter to Geoid constructor. WARNING: This changes may break binary compatibility with previous versions of GeographicLib. However, the library is source compatible. - Add OSGB. - MATLAB and Octave interfaces to UTMUPS, MGRS, Geoid, Geodesic provided. - Minor changes - explicitly turn on optimization in Visual Studio 2008 projects; - add missing dependencies in some Makefiles; - move pi() and degree() from Constants to Math; - introduce Math::extended type to aid testing; - add Math::epi() and Math::edegree(). - fixes to compile under cygwin; - tweak expression used to find latitude from conformal latitude. - Version 1.4 (released 2010-09-12) - Changes to Geodesic and GeodesicLine: - FIX BUG in Geodesic::Inverse with prolate ellipsoids; - add area computations to Geodesic::Direct and Geodesic::Inverse; - add geodesic areas to geodesic test set; - make GeodesicLine constructor public; - change longitude series in Geodesic into Helmert-like form; - ensure that equatorial geodesics have cos(alpha0) = 0 identically; - generalize interface for Geodesic and GeodesicLine; - split GeodesicLine and Geodesic into different files; - signal convergence failure in Geodesic::Inverse with NaNs; - deprecate one function in Geodesic and two functions in GeodesicLine; - deprecate -n option for Geod. . WARNING: These changes may break binary compatibility with previous versions of GeographicLib. However, the library is source compatible (with the proviso that GeographicLib/GeodesicLine.hpp may now need to be included). - Add the Planimeter utility for computing the areas of geodesic polygons. - Improve iterative solution of Gnomonic::Reverse. - Add Geoid::ConvertHeight. - Add -msltohae, -haetomsl, and -z options to GeoidEval. - Constructors check that minor radius is positive. - Add overloaded Forward and Reverse functions to the projection classes which don't return the convergence (or azimuth) and scale. - Document function parameters and return values consistently. - Version 1.3 (released 2010-07-21) - Add Gnomonic, the ellipsoid generalization of the gnomonic projection. - Add -g and -e options to EquidistantTest. - Use fixed-point notation for output from CartConvert, EquidistantTest, TransverseMercatorTest. - PolarStereographic: - Improved conversion to conformal coordinates; - Fix bug with scale at opposite pole; - Complain if latitude out of range in SetScale. - Add Math::NaN(). - Add long double version of hypot for Windows. - Add EllipticFunction::E(real). - Update references to Geotrans in MGRS documentation. - Speed up tmseries.mac. - Version 1.2 (released 2010-05-21) - FIX BUGS in Geodesic, - wrong azimuth returned by Direct if point 2 is on a pole; - Inverse sometimes fails with very close points. - Improve calculation of scale in CassiniSoldner, - add GeodesicLine::Scale, GeodesicLine::EquatorialAzimuth, and GeodesicLine::EquatorialArc; - break friend connection between CassiniSoldner and Geodesic. - Add DMS::DecodeAngle and DMS::DecodeAzimuth. Extend DMS::Decode and DMS::Encode to deal with distances. - Code and documentation changes in Geodesic and Geocentric for consistency with the forthcoming paper on geodesics. - Increase order of series using in Geodesic to 6 (full accuracy maintained for ellipsoid flattening < 0.01). - Macro __NO_LONG_DOUBLE_MATH to disable use of long double. - Correct declaration of Math::isfinite to return a bool. - Changes in the \ref utilities, - improve error reporting when parsing command line arguments; - accept latitudes and longitudes in decimal degrees or degrees, minutes, and seconds, with optional hemisphere designators; - GeoConvert -z accepts zone or zone+hemisphere; - GeoidEval accepts any of the input formats used by GeoConvert; - CartConvert allows the ellipsoid to be specified with -e. - Version 1.1 (released 2010-02-09) - FIX BUG (introduced in 2009-03) in EllipticFunction::E(sn,cn,dn). - Increase accuracy of scale calculation in TransverseMercator and TransverseMercatorExact. - Code and documentation changes for consistency with arXiv:1002.1417 - Version 1.0 (released 2010-01-07) - Add autoconf configuration files. - BUG FIX: Improve initial guess for Newton's method in PolarStereographic::Reverse. (Previously this failed to converge when the co-latitude exceeded about 130 deg.) - Constructors for TransverseMercator, TransverseMercatorExact, PolarStereographic, Geocentric, and Geodesic now check for obvious problems with their arguments and throw an exception if necessary. - Most classes now include inspector functions such as MajorRadius() so that you can determine how instances were constructed. - Add LambertConformalConic class. - Add PolarStereographic::SetScale to allow the latitude of true scale to be specified. - Add solution and project files for Visual Studio 2008. - Add GeographicErr for exceptions. - Geoid changes: - BUG FIX: fix typo in Geoid::Cache which could cause a segmentation fault in some cases when the cached area spanned the prime meridian. - Include sufficient edge data to allow heights to be returned for cached area without disk reads; - Add inspector functions to query the extent of the cache. - Version 2009-11 (released 2009-11-03) - Allow specification of "closest UTM zone" in UTMUPS and GeoConvert (via -t option). - Utilities now complain is there are too many tokens on input lines. - Include real-to-real versions of DMS::Decode and DMS::Encode. - More house-cleaning changes: - Ensure that functions which return results through reference arguments do not alter the arguments when an exception is thrown. - Improve accuracy of MGRS::Forward. - Include more information in some error messages. - Improve accuracy of inverse hyperbolic functions. - Fix the way Math functions handle different precisions. - Version 2009-10 (released 2009-10-18) - Change web site to https://geographiclib.sourceforge.io - Several house-cleaning changes: - Change from the a flat directory structure to a more easily maintained one. - Introduce Math class for common mathematical functions (in Constants.hpp). - Use Math::real as the type for all real quantities. By default this is typedef'ed to double; and the library should be installed this way. - Eliminate const reference members of AzimuthalEquidistant, CassiniSoldner and LocalCartesian so that they may be copied. - Make several constructors explicit. Disallow some constructors. Disallow copy constructor/assignment for Geoid. - Document least squares formulas in Geoid.cpp. - Use unsigned long long for files positions of geoid files in Geoid. - Introduce optional mgrslimits argument in UTMUPS::Forward and UTMUPS::Reverse to enforce stricter MGRS limits on eastings and northings. - Add 64-bit targets in Visual Studio project files. - Version 2009-09 (released 2009-09-01) - Add Geoid and GeoidEval utility. - Version 2009-08 (released 2009-08-14) - Add CassiniSoldner class and EquidistantTest utility. - Fix bug in Geodesic::Inverse where NaNs were sometimes returned. - INCOMPATIBLE CHANGE: AzimuthalEquidistant now returns the reciprocal of the azimuthal scale instead of the reduced length. - Add -n option to GeoConvert. - Version 2009-07 (released 2009-07-16) - Speed up the series inversion code in tmseries.mac and geod.mac. - Reference Borkowski in section on \ref geocentric. - Version 2009-06 (released 2009-06-01) - Add routines to decode and encode zone+hemisphere to UTMUPS. - Clean up code in Geodesic. - Version 2009-05 (released 2009-05-01) - Improvements to Geodesic: - more economical series expansions, - return reduced length (as does the Geod utility), - improved calculation of starting point for inverse method, - use reduced length to give derivative for Newton's method. - Add AzimuthalEquidistant class. - Make Geocentric, TransverseMercator, and PolarStereographic classes work with prolate ellipsoids. - CartConvert checks its inputs more carefully. - Remove reference to defunct Constants.cpp from GeographicLib.vcproj. - Version 2009-04 (released 2009-04-01) - Use compile-time constants to select the order of series in TransverseMercator. - 2x unroll of Clenshaw summation to avoid data shuffling. - Simplification of EllipticFunction::E. - Use STATIC_ASSERT for compile-time checking of constants. - Improvements to Geodesic: - compile-time option to change order of series used, - post Maxima code for generating the series, - tune the order of series for double, - improvements in the selection of starting points for Newton's method, - accept and return spherical arc lengths, - works with both oblate and prolate ellipsoids, - add -a, -e, -b options to the Geod utility. - Version 2009-03 (released 2009-03-01) - Add Geodesic and the Geod utility. - Declare when no exceptions are thrown by functions. - Minor changes to DMS class. - Use invf = 0 to mean a sphere in constructors to some classes. - The makefile creates a library and includes an install target. - Rename ECEF to Geocentric, ECEFConvert to CartConvert. - Use inline functions to define constant doubles in Constants.hpp. - Version 2009-02 (released 2009-01-30) - Fix documentation of constructors (flattening → inverse flattening). - Use std versions of math functions. - Add ECEF and LocalCartesian classes and the ECEFConvert utility. - Gather the documentation on the \ref utilities onto one page. - Version 2009-01 (released 2009-01-12) - First proper release of library. - More robust TransverseMercatorExact: - Introduce \e extendp version of constructor, - Test against extended test data, - Optimize starting positions for Newton's method, - Fix behavior near all singularities, - Fix order dependence in C++ start-up code, - Improved method of computing scale and convergence. - Documentation on transverse Mercator projection. - Add MGRS, UTMUPS, etc. - Version 2008-09 - Ad hoc posting of information on the transverse Mercator projection.
Back to \ref highprec. Up to \ref contents.
**********************************************************************/ }