ADD: new track message, Entity class and Position class

This commit is contained in:
Henry Winkel
2022-12-20 17:20:35 +01:00
parent 469ecfb099
commit 98ebb563a8
2114 changed files with 482360 additions and 24 deletions

9
libs/geographiclib/.gitattributes vendored Normal file
View File

@@ -0,0 +1,9 @@
[Mm]akefile* eol=lf
*.ac eol=lf
*.am eol=lf
*.sh eol=lf
*.eps -text
*.pdf -text
*.png -text
*.gif -text
*.kmz -text

71
libs/geographiclib/.gitignore vendored Normal file
View File

@@ -0,0 +1,71 @@
BUILD*/
*~
.#*
\#*#
*-core
*.[oa]
*.BAK
*.bak
*.exe
*.gz
*.so
*.so.*
*.tmp
*.zip
*.tgz
*.bz2
*.la
*.lo
*.log
*.ncb
*.suo
.nfs*
.DS_Store
TAGS
/archive/
/autom4te.cache/
/data-distrib/
/data-installer/
/scratch/
stamp-h1
/mpfr_mpir_x86_x64_msvc2010/
CMakeCache.txt
CMakeFiles
CPackConfig.cmake
CPackSourceConfig.cmake
Debug
Debug64
Makefile
Makefile.in
Release
Release64
SWIGTYPE_p_namespace.cs
UpgradeLog.XML
UpgradeLog2.XML
_CPack_Packages
_UpgradeReport_Files
aclocal.m4
cmake_install.cmake
compile
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
depcomp
doc.log
geodesic.gie
geodesic.gie-2.0
html
install-sh
install_manifest.txt
libtool
ltmain.sh
m4
make.exe.stackdump
missing
srcL
workspace
x64

View File

@@ -0,0 +1,14 @@
Charles Karney <charles@karney.com>
Francesco Paolo Lovergine <frankie@debian.org> (autoconfiscation)
Mathieu Peyréga <mathieu.peyrega@gmail.com> (help with gravity models)
Andrew MacIntyre <Andrew.MacIntyre@acma.gov.au> (python/setup.py)
Skip Breidbach <skip@waywally.com> (maven support for Java)
Scott Heiman <mrmtdew2@outlook.com> (.NET wrappers + C# examples)
Chris Bennight <chris@bennight.com> (deploying Java library)
Sebastian Mattheis <Sebastian.Mattheis@bmw.de> (gnomonic projection in Java)
Yurij Mikhalevich <yurij@mikhalevi.ch> (node.js port)
Phil Miller <phillip.miller@sri.com> (putting tests into python/setup.py)
Jonathan Takahashi <jtakahashi@gmail.com> (boost-python sample)
William Wall <wallw@users.sourceforge.net> (Javascript wrapper doc)
Thomas Warner <warnerta@gmail.com> (Excel wrapper)
Mark Borgerding <mark@borgerding.net> (KISS FFT)

View File

@@ -0,0 +1,589 @@
cmake_minimum_required (VERSION 3.13.0)
project (GeographicLib)
# Version information
set (PROJECT_VERSION_MAJOR 2)
set (PROJECT_VERSION_MINOR 1)
set (PROJECT_VERSION_PATCH 2)
set (PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
if (PROJECT_VERSION_PATCH GREATER 0)
set (PROJECT_VERSION "${PROJECT_VERSION}.${PROJECT_VERSION_PATCH}")
endif ()
set (PROJECT_VERSION_SUFFIX "")
set (PROJECT_FULLVERSION ${PROJECT_VERSION}${PROJECT_VERSION_SUFFIX})
if (DEFINED CPACK_PACKAGE_VERSION_COUNT)
# majic (version 0.1.9 and later) invokes cmake defining, e.g.,
# -D CPACK_PACKAGE_VERSION=1.37-001-SNAPSHOT
# -D CPACK_PACKAGE_VERSION_COUNT=2
# -D CPACK_PACKAGE_VERSION_MAJOR=1
# -D CPACK_PACKAGE_VERSION_MINOR=36
# -D CPACK_PACKAGE_VERSION_SUFFIX=-001-SNAPSHOT
# Check that the version numbers are consistent.
if (CPACK_PACKAGE_VERSION_COUNT EQUAL 2)
set (CPACK_PACKAGE_VERSION_PATCH 0)
elseif (CPACK_PACKAGE_VERSION_COUNT LESS 2)
message (FATAL_ERROR "CPACK_PACKAGE_VERSION_COUNT must be 2 or more")
endif ()
if (NOT (
CPACK_PACKAGE_VERSION_MAJOR EQUAL PROJECT_VERSION_MAJOR AND
CPACK_PACKAGE_VERSION_MINOR EQUAL PROJECT_VERSION_MINOR AND
CPACK_PACKAGE_VERSION_PATCH EQUAL PROJECT_VERSION_PATCH))
message (FATAL_ERROR "Inconsistency in CPACK and PROJECT version numbers")
endif ()
set (PROJECT_VERSION ${CPACK_PACKAGE_VERSION})
else ()
set (CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set (CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set (CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set (CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set (CPACK_PACKAGE_VERSION_SUFFIX ${PROJECT_VERSION_SUFFIX})
endif ()
set (PACKAGE_DIR "${PROJECT_NAME}-${PROJECT_VERSION}")
set (PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_FULLVERSION}")
# The library version tracks the numbering given by libtool in the
# autoconf set up.
set (LIBVERSION_API 23)
set (LIBVERSION_BUILD 23.1.0)
string (TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER)
string (TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER)
if (EXISTS ${PROJECT_SOURCE_DIR}/VERSION)
# If the file, VERSION, exists then this is a released version of
# GeographicLib and the processed man pages are available in the
# source tree
set (RELEASE ON)
else ()
set (RELEASE OFF)
endif ()
# User-settable variables
# (1) Where to look for data files. Various classes look in the geoids,
# gravity, magnetic, subdirectories of ${GEOGRAPHICLIB_DATA}.
if (WIN32)
# The binary installers for the data files for Windows are created
# with Inno Setup which uses {commonappdata} which (since Windows
# Vista) is C:/ProgramData.
set (GEOGRAPHICLIB_DATA
"C:/ProgramData/${PROJECT_NAME}"
CACHE PATH "Location for data for GeographicLib")
else ()
set (GEOGRAPHICLIB_DATA
"/usr/local/share/${PROJECT_NAME}"
CACHE PATH "Location for data for GeographicLib")
endif ()
# (2) Build which libraries?
option (BUILD_SHARED_LIBS "Build as a shared library" ON)
# Ignore BUILD_SHARED_LIBS and build both shared and static libraries.
# (This replaces the variable GEOGRAPHICLIB_LIB_TYPE in earlier
# versions.)
option (BUILD_BOTH_LIBS "Build both shared and static libraries" OFF)
# (3) What sort of build?
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
# Set a default build type for single-configuration cmake generators
# if no build type is set.
set (CMAKE_BUILD_TYPE "Release")
endif ()
# (4) Create the documentation? This depends on whether doxygen can be
# found. If this is OFF, then links will be provided to the online
# documentation on Sourceforge.
option (BUILD_DOCUMENTATION "Use doxygen to create the documentation" OFF)
# (5) Set the default "real" precision. This should probably be left
# at 2 (double).
set (GEOGRAPHICLIB_PRECISION 2 CACHE STRING
"Precision: 1 = float, 2 = double, 3 = extended, 4 = quadruple, 5 = variable")
set_property (CACHE GEOGRAPHICLIB_PRECISION PROPERTY STRINGS 1 2 3 4 5)
# (6) Try to link against boost when building the examples. The
# NearestNeighbor example optionally uses the Boost library. Set to ON,
# if you want to exercise this functionality. Default is OFF, so that
# cmake configuration isn't slowed down looking for Boost.
option (USE_BOOST_FOR_EXAMPLES
"Look for Boost library when compiling examples" OFF)
# (7) On Mac OS X, build multiple architectures? Set to ON to build
# i386 and x86_64. Default is OFF, meaning build for default
# architecture.
option (APPLE_MULTIPLE_ARCHITECTURES
"Build multiple architectures for Apple systems" OFF)
# (8) Convert warnings into errors? Default is OFF if RELEASE, else ON.
if (RELEASE)
option (CONVERT_WARNINGS_TO_ERRORS "Convert warnings into errors?" OFF)
# BUILD_MANPAGES is ignored in RELEASE mode
option (BUILD_MANPAGES "Convert pod files to manpages" OFF)
else ()
option (CONVERT_WARNINGS_TO_ERRORS "Convert warnings into errors?" ON)
# Convert pod files to man pages. This only necessary with a
# non-release tree.
option (BUILD_MANPAGES "Convert pod files to manpages" ON)
endif ()
# (9) When making a binary package, should we include the debug version
# of the library? This applies to MSVC only, because that's the
# platform where debug and release compilations do not inter-operate.
# It requires building as follows:
# cmake --build . --config Debug --target ALL_BUILD
# cmake --build . --config Release --target ALL_BUILD
# cmake --build . --config Release --target PACKAGE
option (PACKAGE_DEBUG_LIBS
"Include debug versions of library in binary package" OFF)
# Figure out which libraries to build and set GEOGRAPHICLIB_LIB_TYPE_VAL
# (used to initialize GEOGRAPHICLIB_SHARED_LIB in
# include/GeographicLib/Config.h.in)
if (BUILD_BOTH_LIBS)
set (GEOGRAPHICLIB_SHARED_LIB ON)
set (GEOGRAPHICLIB_STATIC_LIB ON)
set (GEOGRAPHICLIB_LIB_TYPE_VAL 2)
elseif (BUILD_SHARED_LIBS)
set (GEOGRAPHICLIB_SHARED_LIB ON)
set (GEOGRAPHICLIB_STATIC_LIB OFF)
set (GEOGRAPHICLIB_LIB_TYPE_VAL 1)
else ()
set (GEOGRAPHICLIB_SHARED_LIB OFF)
set (GEOGRAPHICLIB_STATIC_LIB ON)
set (GEOGRAPHICLIB_LIB_TYPE_VAL 0)
endif ()
if (GEOGRAPHICLIB_STATIC_LIB)
set (PROJECT_STATIC_LIBRARIES GeographicLib_STATIC)
set (PROJECT_STATIC_DEFINITIONS -DGEOGRAPHICLIB_SHARED_LIB=0)
else ()
set (PROJECT_STATIC_LIBRARIES)
set (PROJECT_STATIC_DEFINITIONS)
endif ()
if (GEOGRAPHICLIB_SHARED_LIB)
set (PROJECT_SHARED_LIBRARIES GeographicLib_SHARED)
set (PROJECT_LIBRARIES ${PROJECT_SHARED_LIBRARIES})
set (PROJECT_SHARED_DEFINITIONS -DGEOGRAPHICLIB_SHARED_LIB=1)
set (PROJECT_DEFINITIONS ${PROJECT_SHARED_DEFINITIONS})
else ()
set (PROJECT_SHARED_LIBRARIES)
set (PROJECT_LIBRARIES ${PROJECT_STATIC_LIBRARIES})
set (PROJECT_SHARED_DEFINITIONS)
set (PROJECT_DEFINITIONS ${PROJECT_STATIC_DEFINITIONS})
endif ()
set (PROJECT_INTERFACE_LIBRARIES GeographicLib)
set (PROJECT_ALL_LIBRARIES
${PROJECT_STATIC_LIBRARIES}
${PROJECT_SHARED_LIBRARIES}
${PROJECT_INTERFACE_LIBRARIES})
if (MSVC OR CMAKE_CONFIGURATION_TYPES)
# For multi-config systems and for Visual Studio, the debug version of
# the library is called Geographic_d.
set (CMAKE_DEBUG_POSTFIX "_d" CACHE STRING "The suffix for debug objects")
else ()
set (CMAKE_DEBUG_POSTFIX "" CACHE STRING "The suffix for debug objects")
endif ()
# Installation directories. An empty string or "OFF" disables
# installation of that component. These are all relative to
# CMAKE_INSTALL_PREFIX.
# Installation is to ${INCDIR}/GeographicLib
set (INCDIR "include" CACHE STRING "Where to install header files")
set (BINDIR "bin" CACHE STRING "Where to install tools")
if (WIN32)
set (SBINDIR "" CACHE STRING "Where to install admin tools")
else ()
set (SBINDIR "sbin" CACHE STRING "Where to install admin tools")
endif ()
if (CMAKE_INSTALL_LIBDIR)
# If it's defined, use this GNUInstallDirs path to support lib, lib64,
# and lib/<muliarch-tuple> variants
set (LIBDIR "${CMAKE_INSTALL_LIBDIR}"
CACHE STRING "Where to install libraries")
else ()
set (LIBDIR "lib" CACHE STRING "Where to install libraries")
endif ()
set (DLLDIR "bin" CACHE STRING "Where to install dlls")
# Installation is to ${MANDIR}/man1 and ${MANDIR}/man8
set (MANDIR "share/man" CACHE STRING "Where to install the man pages")
set (CMAKEDIR "lib/cmake/${PROJECT_NAME}"
CACHE STRING "Where to install cmake configs")
set (PKGDIR "lib/pkgconfig" CACHE STRING "Where to install package config")
set (DOCDIR "share/doc/${PROJECT_NAME}"
CACHE STRING "Where to install documentation")
set (EXAMPLEDIR "share/doc/${PROJECT_NAME}-dev"
CACHE STRING "Where to install examples")
# The relative path to library directory from the bin directory
if (LIBDIR AND BINDIR)
file (RELATIVE_PATH RELATIVE_LIBDIR
"${CMAKE_INSTALL_PREFIX}/${BINDIR}" "${CMAKE_INSTALL_PREFIX}/${LIBDIR}")
else ()
set (RELATIVE_LIBDIR "")
endif ()
set (LIBNAME "GeographicLib")
if (NOT MSVC)
# Set the run time path for shared libraries for non-Windows machines.
# (1) include link path for external packages (not needed with
# GeographicLib because there are no external packages). This only
# makes sense for native builds.
if (NOT CMAKE_CROSSCOMPILING)
set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif ()
# (2) include installed path for GeographicLib.
if (NOT APPLE AND RELATIVE_LIBDIR)
# Use relative path so that package is relocatable
set (CMAKE_INSTALL_RPATH "\$ORIGIN/${RELATIVE_LIBDIR}")
else ()
# cmake 2.8.12 introduced a way to make the package relocatable.
# See also INSTALL_RPATH property on the tools.
set (CMAKE_MACOSX_RPATH ON)
endif ()
endif ()
include (CheckTypeSize)
check_type_size ("long double" LONG_DOUBLE BUILTIN_TYPES_ONLY)
check_type_size ("double" DOUBLE BUILTIN_TYPES_ONLY)
if (HAVE_LONG_DOUBLE AND (LONG_DOUBLE GREATER DOUBLE))
set (GEOGRAPHICLIB_HAVE_LONG_DOUBLE TRUE)
else ()
set (GEOGRAPHICLIB_HAVE_LONG_DOUBLE FALSE)
endif ()
include (TestBigEndian)
test_big_endian (GEOGRAPHICLIB_WORDS_BIGENDIAN)
# We require C++11
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
if (GEOGRAPHICLIB_PRECISION EQUAL 4)
set (CMAKE_CXX_EXTENSIONS ON) # Need gnu++11 for quadmath
else ()
set (CMAKE_CXX_EXTENSIONS OFF) # Otherwise stick with the standard
endif ()
# Make the compiler more picky.
include (CheckCXXCompilerFlag)
if (MSVC)
string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
# Turn on parallel builds for Visual Studio
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /std:c++latest /MP")
else ()
set (FLOAT_CONVERSION_FLAG "-Wfloat-conversion")
check_cxx_compiler_flag (${FLOAT_CONVERSION_FLAG} FLOAT_CONVERSION)
if (NOT FLOAT_CONVERSION)
set (FLOAT_CONVERSION_FLAG)
endif ()
set (CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -Wall -Wextra ${FLOAT_CONVERSION_FLAG}")
endif ()
if (CONVERT_WARNINGS_TO_ERRORS)
if (MSVC)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX")
set (CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /WX")
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /WX")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /WX")
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif ()
endif ()
# Tell Intel compiler to do arithmetic accurately. This is needed to
# stop the compiler from ignoring parentheses in expressions like
# (a + b) + c and from simplifying 0.0 + x to x (which is wrong if
# x = -0.0).
if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
if (MSVC)
set (CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} /fp:precise /Qdiag-disable:11074,11076")
else ()
set (CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fp-model precise -diag-disable=11074,11076")
endif ()
endif ()
# Include directories are specified via target_include_directories in src.
set (HIGHPREC_LIBRARIES)
if (GEOGRAPHICLIB_PRECISION EQUAL 1)
message (WARNING "Compiling with floats which results in poor accuracy")
elseif (GEOGRAPHICLIB_PRECISION EQUAL 2)
# This is the default
elseif (GEOGRAPHICLIB_PRECISION EQUAL 3)
if (WIN32)
message (WARNING
"Cannot support long double on Windows, switching to double")
set (GEOGRAPHICLIB_PRECISION 2)
endif ()
elseif (GEOGRAPHICLIB_PRECISION EQUAL 4)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
find_package (Boost 1.64)
if (Boost_FOUND)
set (HIGHPREC_LIBRARIES quadmath)
endif ()
endif ()
if (NOT HIGHPREC_LIBRARIES)
message (WARNING "Cannot support quad precision, switching to double")
set (GEOGRAPHICLIB_PRECISION 2)
endif ()
elseif (GEOGRAPHICLIB_PRECISION EQUAL 5)
# Install MPFR C++ version 3.6.9 (2022-01-18) or later from
# https://github.com/advanpix/mpreal and install mpreal.h in the
# include directory. NOTE: MPFR C++ is covered by the GPL; be sure
# to abide by the terms of this license.
#
# For Linux, use system versions of mpfr and gmp. This is routinely
# used only on Linux. It can be made to work on Apple and Windows
# systems. However, the following notes are likely out of data...
#
# For Apple, use
# brew install mpfr. Recent versions of mpfr (3.0 or later) work
# fine.
#
# For Windows, download MPFR-MPIR-x86-x64-MSVC2010.zip from
# the MPFR C++ site and unpack in the top-level directory. The
# Windows build only works with static libraries.
# NOTE: The Windows build hasn't been tested for a long time.
# NOTE: mpfr, gmp, and mpir are covered by the LGPL; be sure to
# abide by the terms of this license.
if (WIN32)
if (MSVC AND NOT MSVC_VERSION LESS 1800)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set (_ARCH x64)
else ()
set (_ARCH Win32)
endif ()
include_directories (mpfr_mpir_x86_x64_msvc2010/mpfr
mpfr_mpir_x86_x64_msvc2010/mpir/dll/${_ARCH}/Release)
# These are C libraries so it's OK to use release versions for
# debug builds. Also these work for later versions of Visual
# Studio (specifically version 12).
link_directories (mpfr_mpir_x86_x64_msvc2010/mpfr/dll/${_ARCH}/Release
mpfr_mpir_x86_x64_msvc2010/mpir/dll/${_ARCH}/Release)
set (HIGHPREC_LIBRARIES mpfr mpir)
# Suppress the myriad of "conditional expression is constant"
# warnings
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4127")
endif ()
else ()
if (APPLE)
include_directories (/usr/local/include)
link_directories (/usr/local/lib)
endif ()
# g++ before 4.5 doesn't work (no explicit cast operator)
if (NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND
CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5))
set (HIGHPREC_LIBRARIES mpfr gmp)
endif ()
endif ()
if (NOT HIGHPREC_LIBRARIES)
message (WARNING "Cannot support mpfr, switching to double")
set (GEOGRAPHICLIB_PRECISION 2)
endif ()
endif ()
if (APPLE AND APPLE_MULTIPLE_ARCHITECTURES)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "i.86" OR
CMAKE_SYSTEM_PROCESSOR MATCHES "amd64" OR
CMAKE_SYSTEM_PROCESSOR MATCHES "x86")
set (CMAKE_OSX_ARCHITECTURES "i386;x86_64")
endif ()
endif ()
# Create a Config.h to expose system information to the compiler
configure_file (
include/GeographicLib/Config.h.in
include/GeographicLib/Config.h
@ONLY)
# The documentation depends on doxygen.
if (BUILD_DOCUMENTATION)
set (DOXYGEN_SKIP_DOT ON)
# Version 1.8.7 or later needed for &hellip;
find_package (Doxygen 1.8.7)
if (NOT DOXYGEN_FOUND)
message (WARNING "Doxygen not found, not building the documentation")
set (BUILD_DOCUMENTATION OFF)
endif ()
endif ()
# The man pages are written as pod files and converted to nroff format,
# C++ code, and html. Because this require tools that may not be
# available on an end-user's system, the creation of the final
# documentation is therefore only done in "MAINTAINER" mode. The
# maintainer runs "make distrib-man" which installs the transformed
# documentation files into the source tree. Skip Apple here because
# man/makeusage.sh uses "head --lines -4" to drop the last 4 lines of a
# file and there's no simple equivalent for MacOSX. MAINTAINER mode
# also supported (a) running autogen.sh to configure the autoconf
# builds, and (b) running git ls-files to run some sanity checks.
# MAINTAINTER mode is not set in RELEASE mode.
if (NOT RELEASE AND BUILD_MANPAGES AND NOT WIN32 AND NOT APPLE)
find_program (POD2MAN pod2man)
find_program (POD2HTML pod2html)
find_program (COL col)
endif ()
if (POD2MAN AND POD2HTML AND COL AND IS_DIRECTORY ${PROJECT_SOURCE_DIR}/.git)
set (MAINTAINER ON)
find_program (RSYNC rsync)
else ()
set (MAINTAINER OFF)
endif ()
# Set output directories for Windows so that executables and dlls are
# put in the same place
if (WIN32)
# static libaries
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
# shared libraries
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
# executables and dlls
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
endif ()
# The list of tools (to be installed into, e.g., /usr/local/bin)
set (TOOLS CartConvert ConicProj GeodesicProj GeoConvert GeodSolve
GeoidEval Gravity MagneticField Planimeter RhumbSolve TransverseMercatorProj)
# The list of scripts (to be installed into, e.g., /usr/local/sbin)
set (SCRIPTS geographiclib-get-geoids geographiclib-get-gravity
geographiclib-get-magnetic)
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
# The list of subdirectories to process
add_subdirectory (src)
add_subdirectory (include/GeographicLib)
add_subdirectory (tools)
add_subdirectory (man)
add_subdirectory (doc)
if (EXAMPLEDIR)
set (CALLED_FROM_TOPLEVEL ON)
add_subdirectory (examples) # This just installs the examples
endif ()
add_subdirectory (cmake)
enable_testing ()
add_subdirectory (tests)
if (NOT RELEASE)
add_subdirectory (develop)
endif ()
# make exampleprograms does a fresh cmake configuration and so uses
# find_package to find the just-built version og GeographicLib (via the
# GeographicLib_DIR option to cmake).
if (CMAKE_GENERATOR_PLATFORM)
set (PLATFORM_FLAG "-A")
endif ()
add_custom_target (exampleprograms
COMMAND ${CMAKE_COMMAND}
-G ${CMAKE_GENERATOR} ${PLATFORM_FLAG} ${CMAKE_GENERATOR_PLATFORM}
-B exampleprograms -S ${PROJECT_SOURCE_DIR}/examples
-D USE_BOOST_FOR_EXAMPLES=${USE_BOOST_FOR_EXAMPLES}
-D ${PROJECT_NAME}_DIR=${PROJECT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} --build exampleprograms --parallel 8)
add_dependencies (exampleprograms ${PROJECT_LIBRARIES})
# Packaging support; we deal with
# (1) a source distribution: cmake make a tar.gz file and the zip file
# is created from this. Only the maintainer can do this, because of
# the need to generate additional documentation files.
# (2) a binary distribution: code is included for Linux, Apple, and
# Windows, but only the Windows distribution has been exercised.
# Need to ensure that system dlls get included in a binary distribution
if (NOT DEFINED CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
# Visual Studio Express does include redistributable components so
# squelch the warning.
set (CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON)
endif ()
set (CMAKE_INSTALL_DEBUG_LIBRARIES ON)
include (InstallRequiredSystemLibraries)
# The configuration of CPack is via variables that need to be set before
# the include (CPack).
set (CPACK_PACKAGE_CONTACT charles@karney.com)
set (CPACK_PACKAGE_VENDOR "GeographicLib")
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY
"GeographicLib library, utilities, and documentation")
# The list of files to be excluded from the source distribution.
set (CPACK_SOURCE_IGNORE_FILES
"#"
"~\$"
"/\\\\.git"
"${PROJECT_SOURCE_DIR}/BUILD"
"${PROJECT_SOURCE_DIR}/man/(.*\\\\.pod|makeusage\\\\.sh|dummy\\\\..*)\$"
"${PROJECT_SOURCE_DIR}/cmake/maintainer-.*\\\\.cmake\$"
"${PROJECT_SOURCE_DIR}/(develop|cgi-bin|.*\\\\.cache)/"
"${PROJECT_SOURCE_DIR}/(data-distrib|data-installer)/"
"${PROJECT_SOURCE_DIR}/(archive|scratch|mpfr_mpir_x86_x64_msvc2010)/"
"${PROJECT_SOURCE_DIR}/.*\\\\.(zip|tar\\\\.gz|bak|lsp)\$"
"${PROJECT_SOURCE_DIR}/(autogen|biblio)\\\\.sh\$"
"${PROJECT_SOURCE_DIR}/(pom.xml|makefile-admin|HOWTO-RELEASE.txt)\$")
set (CPACK_SOURCE_GENERATOR "TGZ;ZIP")
set (CPACK_RESOURCE_FILE_LICENSE ${PROJECT_SOURCE_DIR}/LICENSE.txt)
set (CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE_DIR}")
set (CPACK_PACKAGE_INSTALL_DIRECTORY "${PACKAGE_DIR}")
if (WIN32)
# The Windows binary packager is NSIS. Set the necessary variables
# for this.
set (CPACK_NSIS_CONTACT "charles@karney.com")
set (CPACK_NSIS_URL_INFO_ABOUT "https://geographiclib.sourceforge.io")
set (CPACK_NSIS_HELP_LINK "mailto:charles@karney.com")
# No provision for accommodating different compiler versions. However
# the Visual Studio 14 2015 build works also with Visual Studio 15
# 2017, Visual Studio 16 2019, and Visual Studio 17 2022.
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set (CPACK_NSIS_INSTALL_ROOT "C:\\\\Program Files")
set (CPACK_PACKAGE_FILE_NAME "${PACKAGE_NAME}-win64")
set (CPACK_NSIS_PACKAGE_NAME "${PROJECT_NAME} x64 ${PROJECT_VERSION}")
set (CPACK_PACKAGE_INSTALL_REGISTRY_KEY
"${PROJECT_NAME}-x64-${PROJECT_VERSION}")
else ()
set (CPACK_NSIS_INSTALL_ROOT "C:\\\\Program Files (x86)")
set (CPACK_PACKAGE_FILE_NAME "${PACKAGE_NAME}-win32")
set (CPACK_NSIS_PACKAGE_NAME "${PROJECT_NAME} win32 ${PROJECT_VERSION}")
set (CPACK_PACKAGE_INSTALL_REGISTRY_KEY
"${PROJECT_NAME}-win32-${PROJECT_VERSION}")
endif ()
set (CPACK_NSIS_DISPLAY_NAME ${CPACK_NSIS_PACKAGE_NAME})
set (CPACK_NSIS_MENU_LINKS
"https://geographiclib.sourceforge.io/C++/${PROJECT_VERSION}/index.html"
"Library documentation"
"https://geographiclib.sourceforge.io/C++/${PROJECT_VERSION}/utilities.html"
"Utilities documentation"
"https://geographiclib.sourceforge.io" "GeographicLib home page"
"https://sourceforge.net/projects/geographiclib/" "Main project page")
set (CPACK_NSIS_MODIFY_PATH ON)
elseif (APPLE)
# Not tested
set (CPACK_GENERATOR Bundle)
set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}-darwin")
else ()
# Not tested
set (CPACK_GENERATOR TGZ)
endif ()
include (CPack)
# If MAINTAINER, then prepare the source distribution for RELEASE mode.
# "make dist" does the following:
# "make package_source" to call the CPack source generator
# remove stray files which aren't in git
# runs autogen.sh in the package source directory
# creates the processing man documentation and installs it too
# creates a file VERSION to signal that this is a RELEASE source
# create .tar.gz and .zip archives of the results
if (MAINTAINER)
include (cmake/maintainer-top.cmake)
endif ()

View File

@@ -0,0 +1,202 @@
Updating version
pom.xml include -SNAPSHOT in version
CMakeLists.txt set PROJECT_VERSION_SUFFIX to "-alpha" + LIBVERSION_{API,BUILD}
configure.ac AC_INIT + GEOGRAPHICLIB_VERSION_* + LT_{CURRENT,REVISION,AGE}
devel/test-distribution VERSION, SUFFIX, BRANCH
doc/GeographicLib.dox.in set date to mm-dd start new change log entry
CMake configuration
How this proceeds depends on whether you're building from a release
package or not. A release package (marked by a file named VERSION at
the top level) has preprocessed man pages and so can be built without
the extra tools needed for processing the pod-style man pages; in
addition, the release package has a configure script (created by
autogen.sh) for autoconf-style builds.
CMake options and variables: see CMakeLists.txt for information
BUILD_SHARED_LIBS ON
BUILD_BOTH_LIBS OFF
BUILD_DOCUMENTATION OFF
USE_BOOST_FOR_EXAMPLES OFF
CONVERT_WARNINGS_TO_ERRORS OFF (ON in non-RELEASE mode)
BUILD_MANPAGES OFF (ON in non-release mode)
GEOGRAPHICLIB_DATA /usr/local/share/GeographicLib or C:/ProgramData/GeographicLib
GEOGRAPHICLIB_PRECISION 2
1 = float
2 = double
3 = extended
4 = quadruple (boost float128)
5 = variable (mpreal)
Where things get installed. Use an empty string to disable that installation
CMAKE_INSTALL_PREFIX
INCDIR "include" "Where to install header files"
BINDIR "bin" "Where to install tools"
SBINDIR "sbin" "Where to install admin tools" ("" for Windows)
LIBDIR "lib" "Where to install libraries"
this is set to ${CMAKE_INSTALL_LIBDIR} if that's defined
DLLDIR "bin" "Where to install dlls"
MANDIR "share/man" "Where to install the man pages"
CMAKEDIR "lib/cmake/GeographicLib "Where to install cmake configs"
PKGDIR "lib/pkgconfig" "Where to install package config"
DOCDIR "share/doc/GeographicLib" "Where to install documentation"
EXAMPLEDIR "share/doc/GeographicLib-dev" "Where to install examples"
CMAKE_DEBUG_POSTFIX "The suffix for debug objects" "_d"
Windows only
PACKAGE_DEBUG_LIBS "Include debug versions of library in binary package" OFF
CMake targets
release mode
all test
sanitize hygiene check on source files (trailing blanks, etc)
exampleprograms compile example programs (this is separate cmake config)
package make binary package for Windows
package_source make source package
maintainer
doc (if BUILD_DOCUMENTATION and doxygen found)
prep-source prep source distribute prior to making release package
distrib-man create extra versions of man pages
distrib-all distrib-man + run autogen for autoconf builds
dist Package release into a tar.gz + zip files
stage-doc copy documenation to staging area
stage-dist copy source distribution to data-distrib
deploy-doc deploy documentation from staging area to sourceforge
deploy-dist deploy source distributions from data-distrib to staging
area and then to sourceforge
deploy-data deploy geoid data etc
develprograms build experimental stuff
Version update checks
Add PROJECT_VERSION_SUFFIX = "-alpha" to
tar package of source
Do not add PROJECT_VERSION_SUFFIX to
unpack directory for tar package
documentation
Debian maintainers
Francesco Paolo Lovergine (QA Page)
Bas Couwenberg (QA Page)
Fedora maintainer
rmattes, smani
binaries for cgi scripts
run compile.sh (copy in cgi-bin)
When ready for switch over, do
cd /home/project-web/geographiclib
rm bin
ln -s bin-$VERSION bin
make -f makefile-admin distrib-cgi
update binaries for cgi applications
Release checklist:
Merge all changes to main
test-distribution.sh: set SUFFIX= and BRANCH=main
CMakeLists.txt set PROJECT_VERSION_SUFFIX suffix to ""
pom.xml keeps SNAPSHOT for now
Update NEWS
Set date in NEWS and GeographicLib.dox.in
run develop/test-distribution.sh
run windows build
copy windows installers to data-distrib/distrib-C++
fix permissions on installers
remove alpha/rc versions of installers
switch C++/doc link to latest version
make stage-{doc,dist}
make deploy-{doc,dist}
checkin and tag release branch & push
tag main branch
trigger build on build-open
update binaries for cgi applications
make stage-cgi deploy-cgi
ssh -t karney,geographiclib@shell.sourceforge.net create
update VERSION in compile.sh and compile
Local install
sudo make -C $TEMP/relc/GeographicLib-$VERSION/BUILD-system install
set default downloads for distrib-C++ on sourceforge
post changes on sourceforge news + email to geographiclib-announce@lists.sourceforge.net
VERSION=2.1.2
Brew...
brew update
cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula
git checkout master; git pull?
edit geographiclib.rb
changing url and sha256
brew uninstall geographiclib
brew install --build-from-source geographiclib
brew reinstall --build-from-source geographiclib
brew test geographiclib
brew audit --strict geographiclib
brew style geographiclib
git checkout -b geographiclib/$VERSION
git add geographiclib.rb
git commit -m "geographiclib $VERSION"
git push --set-upstream cffk geographiclib/$VERSION
trigger a PR
conda-forge...
geographiclib-cpp-feedstock
edit recipe/bld.bat recipe/build.sh recipe/meta.yaml
conda remove -y -n build --all
conda create -y -n build
conda activate build
conda install -y conda-build conda-verify conda-forge-pinning
conda build recipe --variant-config-file $CONDA_PREFIX/conda_build_config.yaml
Package in ~/miniconda3/envs/build/conda-bld/linux-64/geographiclib-cpp-$VERSION-*.tar.bz2
conda deactivate
conda remove -y -n geog-test --all
conda create -y -n geog-test ~/miniconda3/envs/build/conda-bld/linux-64/geographiclib-cpp-$VERSION-*.tar.bz2
conda activate geog-test
type GeoConvert
git checkout -b v$VERSION
conda install -c conda-forge conda-smithy
conda smithy rerender
commit changes
git push --set-upstream cffk v$VERSION
vcpkg...
git pull
git branch -b geographiclib/$VERSION
update ports/geographiclib
./vcpkg remove geographiclib
./vcpkg install 'geographiclib[tools]'
binaries in installed/x64-linux/tools/geographiclib
libs in installed/x64-linux/{include,lib,debug/lib}
commit changes
# ./vcpkg x-add-version geographiclib
./vcpkg x-add-version --all
commit again
commit message = [geographiclib] Update to version $VERSION
git push --set-upstream cffk geographiclib/$VERSION

View File

@@ -0,0 +1,23 @@
The MIT License (MIT).
Copyright (c) 2008-2022, Charles Karney
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,48 @@
#
# Makefile.am
#
# Copyright (C) 2009, Francesco P. Lovergine <frankie@debian.org>
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src man tools doc include cmake examples tests
EXTRA_DIST = AUTHORS LICENSE.txt NEWS README.md \
CMakeLists.txt maxima doc wrapper
# Install the pkg-config file; the directory is set using
# PKG_INSTALLDIR in configure.ac.
pkgconfig_DATA = cmake/geographiclib.pc
dist-hook:
rm -rf $(distdir)/doc/html $(distdir)/doc/manpages \
$(distdir)/doc/GeographicLib.dox \
$(distdir)/include/GeographicLib/Config.h
find $(distdir)/maxima -type f -name '*.lsp' | xargs rm -rf
find $(distdir)/wrapper -mindepth 2 -type d | xargs rm -rf
find $(distdir)/wrapper -type f -name '*.o' -o -name '*.mex*' | \
xargs rm -f
find $(distdir) \
\( -name '.git*' -o -name Makefile -o -name '*~' -o \
-name '*#*' -o -name 'CMakeFiles' -o -name '*.log' -o \
-name '*.tmp' -o -name '*.bak' -o -name '*.BAK' \) | \
xargs rm -rf
echo $(VERSION) > $(distdir)/VERSION
# Custom rules
all-local: man doc
install-data-local: install-doc
doc: man
$(MAKE) -C doc doc
install-doc:
$(MAKE) -C doc install-doc
man:
$(MAKE) -C man man
.PHONY: doc install-doc man

1983
libs/geographiclib/NEWS Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
# GeographicLib
GeographicLib is a small C++ library for
* geodesic and rhumb line calculations;
* conversions between geographic, UTM, UPS, MGRS, geocentric, and local
cartesian coordinates;
* gravity (e.g., EGM2008) and geomagnetic field (e.g., WMM2020)
calculations.
It is licensed under the MIT License; see
[LICENSE.txt](https://geographiclib.sourceforge.io/LICENSE.txt).
## Links:
* Library documentation: https://geographiclib.sourceforge.io/C++/doc
* Change log: https://geographiclib.sourceforge.io/C++/doc/changes.html
* Git repository: https://github.com/geographiclib/geographiclib
* Releases are on the [`release`](../../release) branch, and specific
releases are tagged as, e.g., [`r1.52`](../../tree/r1.52),
[`r2.0`](../../tree/r2.0), etc. This is the appropriate branch
for most *users* of GeographicLib.
* The main branch is [`main`](../..) and most development is done on
the [`devel`](../../tree/devel) branch. These branches are for the
*developers* of GeographicLib. Tags [`v1.52`](../../tree/v1.52),
[`v2.0`](../../tree/v2.0), etc., are aligned with the
corresponding release tags `r1.52`, `r2.0`, etc.
* Source distribution:
https://sourceforge.net/projects/geographiclib/files/distrib-C++
* GeographicLib: https://geographiclib.sourceforge.io
* GeographicLib in various languages:
https://geographiclib.sourceforge.io/doc/library.html#languages
* Author: Charles Karney, <charles@karney.com>

30
libs/geographiclib/autogen.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/bin/sh
#
# A simple script to add/reset autotools support
# This requires that autoconf and autoconf-archive are installed
run ()
{
echo "Running: $*"
eval $*
if test $? != 0 ; then
echo "Error: while running '$*'"
exit 1
fi
}
mv m4/pkg.m4 ./
rm -rf autom4te.cache m4
mkdir m4
mv pkg.m4 m4/
run aclocal
run autoheader
LIBTOOLIZE=libtoolize
type $LIBTOOLIZE > /dev/null 2>&1 || LIBTOOLIZE=g$LIBTOOLIZE
run $LIBTOOLIZE --force --copy
run automake --add-missing --copy --force-missing --foreign
run autoconf
run autoreconf
rm -rf autom4te.cache configure~

View File

@@ -0,0 +1,248 @@
#! /bin/sh
#
# GeoConvert.cgi
# cgi script for geographic coordinate conversion
#
# Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and
# licensed under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
. ./utils.sh
OPTION=`lookupkey "$QUERY_STRING" option`
if test "$OPTION" = Reset; then
INPUT=
else
INPUT=`lookupcheckkey "$QUERY_STRING" input`
ZONE=`lookupkey "$QUERY_STRING" zone`
PREC=`lookupkey "$QUERY_STRING" prec`
fi
test "$ZONE" || ZONE=-3
test "$PREC" || PREC=0
INPUTENC=`encodevalue "$INPUT"`
EXECDIR=../bin
COMMAND="GeoConvert"
VERSION=`$EXECDIR/$COMMAND --version | cut -f4 -d" "`
F='<font color="Blue">'
G='</font>'
test $PREC = 0 || COMMAND="$COMMAND -p $PREC"
LOCG=
LOCD=
LOCU=
LOCM=
GEOH=
set -o pipefail
if test "$INPUT"; then
LOCG=`echo $INPUT | $EXECDIR/$COMMAND | head -1`
if test $? -eq 0; then
GEOH=`echo $INPUT | $EXECDIR/$COMMAND -p 1 | head -1`
LOCG=`geohack $GEOH $LOCG Blue`
LOCD=\(`echo $INPUT | $EXECDIR/$COMMAND -d | head -1`\)
case $ZONE in
-3 ) ;;
-2 ) COMMAND="$COMMAND -t";;
-1 ) COMMAND="$COMMAND -s";;
* ) COMMAND="$COMMAND -z $ZONE"
esac
LOCU=`echo $INPUT | $EXECDIR/$COMMAND -u | head -1`
LOCM=`echo $INPUT | $EXECDIR/$COMMAND -m | head -1`
fi
# echo `date +"%F %T"` "$COMMAND: $INPUT" >> ../persistent/utilities.log
fi
echo Content-type: text/html
echo
cat <<EOF
<html>
<head>
<title>
Online geographic coordinate converter
</title>
<meta name="description"
content="Online geographic coordinate converter" />
<meta name="author" content="Charles F. F. Karney" />
<meta name="keywords"
content="geographic coordinate conversions,
geographic coordinates,
latitude and longitude,
degrees minutes seconds,
universal transverse Mercator, UTM,
easting northing and zone,
universal polar sterographic, UPS,
military grid reference system, MGRS,
online calculator,
WGS84 ellipsoid,
GeographicLib" />
</head>
<body>
<h3>
Online geographic coordinate conversions using the
<a href="https://geographiclib.sourceforge.io/C++/doc/GeoConvert.1.html">
GeoConvert</a> utility
</h3>
<form action="/cgi-bin/GeoConvert" method="get">
<p>
Location
(ex. &laquo;<tt>33.33 44.4</tt>&raquo;,
&laquo;<tt>33d19'47"N 44d23.9'E</tt>&raquo;,
&laquo;<tt>38SMB4488</tt>&raquo;,
&laquo;<tt>38n 444000 3688000</tt>&raquo;):<br>
&nbsp;&nbsp;&nbsp;
<input type=text name="input" size=40 value="$INPUTENC">
</p>
<table>
<tr>
<td>
&nbsp;&nbsp;&nbsp;
Output zone:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<select name="zone" size=1>
EOF
(
cat <<EOF
-3 Match input or standard
-1 Standard UPS/UTM zone
0 UPS
-2 Standard UTM zone
EOF
) | while read z name; do
SELECTED=
test "$z" = "$ZONE" && SELECTED=SELECTED
echo "<option $SELECTED value=\"$z\">$name</option>"
done
for ((z=1; z<=60; ++z)); do
SELECTED=
test "$z" = "$ZONE" && SELECTED=SELECTED
name="UTM zone $z"
echo "<option $SELECTED value=\"$z\">$name</option>"
done
cat <<EOF
</select>
</td>
<td>
&nbsp;&nbsp;&nbsp;
Output precision:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<select name="prec" size=1>
EOF
(
cat <<EOF
-5 100km 1d
-4 10km 0.1d
-3 1km 0.01d 1'
-2 100m 0.001d 0.1'
-1 10m 0.0001d 1"
0 1m 0.00001d 0.1"
1 100mm 0.01"
2 10mm 0.001"
3 1mm 0.0001"
4 100um 0.00001"
5 10um 0.000001"
6 1um 0.0000001"
7 100nm 0.00000001"
8 10nm 0.000000001"
9 1nm 0.0000000001"
10 0.00000000001"
EOF
) | while read p desc; do
SELECTED=
test "$p" = "$PREC" && SELECTED=SELECTED
echo "<option $SELECTED value=\"$p\">$desc</option>"
done
cat <<EOF
</select>
</td>
</tr>
</table>
<p>
Select action:<br>
&nbsp;&nbsp;&nbsp;
<input type="submit" name="option" value="Submit">
<input type="submit" name="option" value="Reset">
</p>
<p>
Results:
<font size="4"><pre>
input = `encodevalue "$INPUT"`
lat lon = $F$LOCG `convertdeg "$LOCD"`$G
<a href="https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system">UTM</a>/<a href="https://en.wikipedia.org/wiki/Universal_Polar_Stereographic">UPS</a> = $F`encodevalue "$LOCU"`$G
<a href="https://en.wikipedia.org/wiki/Military_grid_reference_system">MGRS</a> = $F`encodevalue "$LOCM"`$G</pre></font>
</p>
</form>
<hr>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/GeoConvert.1.html">
GeoConvert (version $VERSION)</a>
converts between geographic (latitude and longitude) coordinates,
<a href="https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system">
universal transverse Mercator (UTM)</a> or
<a href="https://en.wikipedia.org/wiki/Universal_Polar_Stereographic">
universal polar stereographic (UPS)</a> coordinates, and the
<a href="https://en.wikipedia.org/wiki/Military_grid_reference_system">
military grid reference system (MGRS)</a>.
Examples of legal geographic locations are (these all refer to roughly
the same place, Cape Morris Jesup on the northern tip of Greenland):
<pre>
Latitude and longitude: MGRS:
83.627 -32.664 24XWT783908
W32d40 N83d37.6 YUB17770380
83&deg;37'39"N 32&deg;39'52"W UTM:
83:37:39 32:39:52W 25n 504158 9286521
32:39.9W 83:37.6N 430000 9290000 26n
32:40W+0:0:6 83:37.6 UPS:
32:40W+0:0:6 83:38-0:0.4 n 1617772 1403805</pre>
<b>Notes:</b>
<ul>
<li>
The letter in following the zone number in the UTM position is
a hemisphere designator (n or s) and <em>not</em> the MGRS
latitude band letter. "north" or "south" can also be used,
e.g., 25north.
<li>
MGRS coordinates are taken to refer to <em>grid squares</em>
(<em>not</em> to the intersections of grid lines). Thus in UTM
zone 38n, the square area with easting in [444 km, 445 km) and
northing in [3688 km, 3689 km) corresponds to the MGRS square
38SMB4488 (at 1 km precision).
<ul>
<li>
When an MGRS coordinate is read, a representative point
within the grid square, namely, the <em>center</em>, is
returned.
<li>
The MGRS easting and northing are obtained
by <em>truncation</em> to the requested precision
(<em>not</em> rounding).
</ul>
<li>
Usually <em>Output zone</em> should be <em>Match input or
standard</em>. If the latitude and longitude are given, the
standard UPS and UTM zone rules are applied; otherwise the
UPS/UTM selection and the UTM zone match the input. The other
choices let you override this selection.
</ul>
</p>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/GeoConvert.1.html">
GeoConvert</a>,
which is a simple wrapper of the
<a href="https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1GeoCoords.html">
GeographicLib::GeoCoords</a> class,
is one of the utilities provided
with <a href="https://geographiclib.sourceforge.io/">
GeographicLib</a>.
This web interface illustrates a subset of its capabilities. If
you wish to use GeoConvert directly,
<a href="https://sourceforge.net/projects/geographiclib/files/distrib-C++">
download</a>
and compile GeographicLib.
</p>
<hr>
<address>Charles Karney
<a href="mailto:charles@karney.com">&lt;charles@karney.com&gt;</a>
(2022-04-10)</address>
<a href="https://geographiclib.sourceforge.io">
GeographicLib home
</a>
</body>
</html>
EOF

View File

@@ -0,0 +1,35 @@
#! /bin/sh
#
# Geod.cgi (redirect to GeodSolve.cgi)
#
# Copyright (c) Charles Karney (2013) <charles@karney.com> and licensed
# under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
cat <<EOF
Content-type: text/html
<html>
<head>
<title>Online geodesic calculator</title>
<meta HTTP-EQUIV="Refresh"
CONTENT="5; URL=https://geographiclib.sourceforge.io/cgi-bin/GeodSolve">
</head>
<body topmargin=10 leftmargin=10>
<h3>
<blockquote>
<em>
The Geod calculator has been renamed GeodSolve which is available at
<center>
<a href="https://geographiclib.sourceforge.io/cgi-bin/GeodSolve">
https://geographiclib.sourceforge.io/cgi-bin/GeodSolve</a>.
</center>
<br>
You will be redirected there. Click on the link to go there
directly.
</em>
</blockquote>
</h3>
</body>
</html>
EOF

View File

@@ -0,0 +1,387 @@
#! /bin/sh
#
# GeodSolve.cgi
# cgi script for geodesic calculations
#
# Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and
# licensed under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
. ./utils.sh
DEFAULTRADIUS=6378137
DEFAULTFLATTENING=1/298.257223563
OPTION=`lookupkey "$QUERY_STRING" option`
if test "$OPTION" = Reset; then
INPUT=
RADIUS=
FLATTENING=
else
INPUT=`lookupcheckkey "$QUERY_STRING" input`
RADIUS=`lookupellipsoid "$QUERY_STRING" radius`
FLATTENING=`lookupellipsoid "$QUERY_STRING" flattening`
FORMAT=`lookupkey "$QUERY_STRING" format`
AZF2=`lookupkey "$QUERY_STRING" azi2`
UNROLL=`lookupkey "$QUERY_STRING" unroll`
PREC=`lookupkey "$QUERY_STRING" prec`
TYPE=`lookupkey "$QUERY_STRING" type`
fi
test "$RADIUS" || RADIUS=$DEFAULTRADIUS
test "$FLATTENING" || FLATTENING=$DEFAULTFLATTENING
test "$FORMAT" || FORMAT=g
test "$AZF2" || AZF2=f
test "$UNROLL" || UNROLL=r
test "$PREC" || PREC=3
test "$TYPE" || TYPE=I
AZIX="fazi2"
test "$AZF2" = b && AZIX="bazi2"
TAG=
if test "$RADIUS" = "$DEFAULTRADIUS" -a \
"$FLATTENING" = "$DEFAULTFLATTENING"; then
TAG=" (WGS84)"
fi
INPUTENC=`encodevalue "$INPUT"`
EXECDIR=../bin
COMMAND="GeodSolve -E -f"
VERSION=`$EXECDIR/$COMMAND --version | cut -f4 -d" "`
F='<font color="blue">'
G='</font>'
S=' '
test $TYPE = I && COMMAND="$COMMAND -i"
COMMANDX="$COMMAND -p 1"
test $FORMAT = d && COMMAND="$COMMAND -$FORMAT"
test $AZF2 = b && COMMAND="$COMMAND -$AZF2"
test $UNROLL = u && COMMAND="$COMMAND -$UNROLL"
test $PREC = 3 || COMMAND="$COMMAND -p $PREC"
STATUS=
POSITION1=
POSITION2=
DIST12=
a12=
m12=
M1221=
S12=
set -o pipefail
if test "$INPUT"; then
OUTPUT=`echo $INPUT | $EXECDIR/$COMMAND -e "$RADIUS" "$FLATTENING" 2>&1 |
head -1`
if test $? -eq 0; then
STATUS=OK
OUTPUTG=`echo $INPUT | $EXECDIR/$COMMANDX -e "$RADIUS" "$FLATTENING" |
head -1`
POS1="`echo $OUTPUT | cut -f1-2 -d' '`"
POS2="`echo $OUTPUT | cut -f4-5 -d' '`"
POSG1="`echo $OUTPUTG | cut -f1-2 -d' '`"
POSG2="`echo $OUTPUTG | cut -f4-5 -d' '`"
AZI1="`echo $OUTPUT | cut -f3 -d' '`"
AZI2="`echo $OUTPUT | cut -f6 -d' '`"
DIST12="`echo $OUTPUT | cut -f7 -d' '`"
a12="`echo $OUTPUT | cut -f8 -d' '`"
m12="`echo $OUTPUT | cut -f9 -d' '`"
M1221="`echo $OUTPUT | cut -f10-11 -d' '`"
S12="`echo $OUTPUT | cut -f12 -d' '`"
if test "$TYPE" = D; then
POSITION1=$(geohack $POSG1 $POS1 Black)\ $(convertdeg "$AZI1")
POSITION2=$F$(geohack $POSG2 $POS2 Blue)\ $(convertdeg "$AZI2")$G
DIST12=$(encodevalue "$DIST12")
else
POSITION1=$(geohack $POSG1 $POS1 Black)\ $F$(convertdeg "$AZI1")$G
POSITION2=$(geohack $POSG2 $POS2 Black)\ $F$(convertdeg "$AZI2")$G
DIST12=$F$(encodevalue "$DIST12")$G
fi
else
STATUS="$OUTPUT"
fi
# echo `date +"%F %T"` "$COMMAND: $INPUT" >> ../persistent/utilities.log
fi
echo Content-type: text/html
echo
cat <<EOF
<html>
<head>
<title>
Online geodesic calculator
</title>
<meta name="description" content="Online geodesic calculator" />
<meta name="author" content="Charles F. F. Karney" />
<meta name="keywords"
content="geodesics,
geodesic distance,
geographic distance,
shortest path,
direct geodesic problem,
inverse geodesic problem,
distance and azimuth,
distance and heading,
range and bearing,
spheroidal triangle,
latitude and longitude,
online calculator,
WGS84 ellipsoid,
GeographicLib" />
</head>
<body>
<h3>
Online geodesic calculations using the
<a href="https://geographiclib.sourceforge.io/C++/doc/GeodSolve.1.html">
GeodSolve</a> utility
</h3>
<form action="/cgi-bin/GeodSolve" method="get">
<p>
Geodesic calculation:
<table>
<tr>
<td valign='baseline'>
&nbsp;&nbsp;&nbsp;
<label for='I'>
<input type="radio" name="type" value="I" id='I'
`test "$TYPE" = I && echo CHECKED`>
&nbsp;Inverse:&nbsp;
</label>
</td>
<td valign='baseline'>
<em>lat1 lon1 lat2 lon2</em>
</td>
<td valign='baseline'>
&rarr; <em>azi1 azi2 s12</em>
</td>
</tr>
<tr>
<td valign='baseline'>
&nbsp;&nbsp;&nbsp;
<label for='D'>
<input type="radio" name="type" value="D" id='D'
`test "$TYPE" = D && echo CHECKED`>
&nbsp;Direct:&nbsp;
</label>
</td>
<td valign='baseline'>
<em>lat1 lon1 azi1 s12</em>
</td>
<td valign='baseline'>
&rarr; <em>lat2 lon2 azi2</em>
</td>
</tr>
</table>
</p>
<p>
Input (ex. &laquo;<tt>40.6 -73.8 49&deg;01'N 2&deg;33'E</tt>&raquo;
[inverse],
&laquo;<tt>40d38'23"N 073d46'44"W 53d30' 5850e3</tt>&raquo;
[direct]):
<br>
&nbsp;&nbsp;&nbsp;
<input type=text name="input" size=72 value="$INPUTENC">
</p>
<p>
<table>
<tr>
<td>
Output format:
</td>
EOF
while read c desc; do
CHECKED=
test "$c" = "$FORMAT" && CHECKED=CHECKED
echo "<td>&nbsp;<label for='$c'>"
echo "<input type='radio' name='format' value='$c' id='$c' $CHECKED>"
echo "$desc</label></td>"
done <<EOF
g decimal degrees
d degrees minutes seconds
EOF
cat <<EOF
</tr>
<tr>
<td>
Heading at point 2:
</td>
EOF
while read c desc; do
CHECKED=
test "$c" = "$AZF2" && CHECKED=CHECKED
echo "<td>&nbsp;<label for='$c'>"
echo "<input type='radio' name='azi2' value='$c' id='$c' $CHECKED>"
echo "$desc</label></td>"
done <<EOF
f forward azimuth
b back azimuth
EOF
cat <<EOF
</tr>
<tr>
<td>
Longitude:
</td>
EOF
while read c desc; do
CHECKED=
test "$c" = "$UNROLL" && CHECKED=CHECKED
echo "<td>&nbsp;<label for='$c'>"
echo "<input type='radio' name='unroll' value='$c' id='$c' $CHECKED>"
echo "$desc</label></td>"
done <<EOF
r reduce to [&minus;180&deg;,180&deg;]
u unroll
EOF
cat <<EOF
</tr>
<tr>
<td>
Output precision:
</td>
<td colspan="2">&nbsp;
<select name="prec" size=1>
EOF
while read p desc; do
SELECTED=
test "$p" = "$PREC" && SELECTED=SELECTED
echo "<option $SELECTED value='$p'> $desc</option>"
done <<EOF
0 1m 0.00001d 0.1"
1 100mm 0.01"
2 10mm 0.001"
3 1mm 0.0001"
4 100&mu;m 0.00001"
5 10&mu;m 0.000001"
6 1&mu;m 0.0000001"
7 100nm 0.00000001"
8 10nm 0.000000001"
9 1nm 0.0000000001"
EOF
cat <<EOF
</select>
</td>
</tr>
<tr>
<td>Equatorial radius:</td>
<td>
<input type=text name="radius" size=20 value="$RADIUS">
</td>
<td>meters</td>
</tr>
<tr>
<td>Flattening:</td>
<td>
<input type=text name="flattening" size=20 value="$FLATTENING">
</td>
</tr>
</table>
</p>
<p>
Select action:<br>
&nbsp;&nbsp;&nbsp;
<input type="submit" name="option" value="Submit">
<input type="submit" name="option" value="Reset">
</p>
<p>
Geodesic (input in black, output in ${F}blue${G}):<br>
<font size="4"><pre>
ellipsoid (a f)$S= `encodevalue "$RADIUS"` `encodevalue "$FLATTENING"`$TAG
status $S= `encodevalue "$STATUS"`
lat1 lon1 fazi1 (&deg;) = $POSITION1
lat2 lon2 $AZIX (&deg;) = $POSITION2
s12 (m) = $DIST12
a12 (&deg;) = $F$a12$G
m12 (m) = $F$m12$G
M12 M21 = $F$M1221$G
S12 (m^2) = $F$S12$G</pre></font>
</p>
</form>
<hr>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/GeodSolve.1.html">
GeodSolve (version $VERSION)</a>
performs geodesic calculations for an arbitrary ellipsoid of
revolution. The shortest path between two points on the ellipsoid
at (<em>lat1</em>, <em>lon1</em>) and (<em>lat2</em>,
<em>lon2</em>) is called the <em>geodesic</em>; its length
is <em>s12</em> and the geodesic from point 1 to point 2 has
azimuths <em>azi1</em> and <em>azi2</em> at the two end points.
There are two standard geodesic problems:
<ul>
<li> Direct: &nbsp; given [<em>lat1 lon1 azi1 s12</em>], find
[<em>lat2 lon2 azi2</em>];
<li> Inverse: given [<em>lat1 lon1 lat2 lon2</em>], find
[<em>azi1 azi2 s12</em>].
</ul>
Latitudes and longitudes can be given in various formats, for
example (these all refer to the position of Timbuktu):
<pre>
16.776 -3.009
16d47' -3d1'
W3&deg;0'34" N16&deg;46'33"
3:0:34W 16:46:33N</pre>
Azimuths are given in degrees clockwise from north. The
distance <em>s12</em> is in meters.
</p>
<p>
The additional quantities computed are:
<ul>
<li> <em>a12</em>, the arc length on the auxiliary sphere (&deg;),
<li> <em>m12</em>, the reduced length (m),
<li> <em>M12</em> and <em>M21</em>, the geodesic scales,
<li> <em>S12</em>, the area between the geodesic
and the equator (m<sup>2</sup>).
</ul>
</p>
<p>
The ellipsoid is specified by its equatorial radius, <em>a</em>,
and its flattening,
<em>f</em>&nbsp;=
(<em>a</em>&nbsp;&minus;&nbsp;<em>b</em>)/<em>a</em>,
where <em>b</em> is the polar semi-axis. The default values for
these parameters correspond to the WGS84 ellipsoid. The method is
accurate for &minus;99&nbsp;&le; <em>f</em>&nbsp;&le; 0.99
(corresponding to 0.01&nbsp;&le; <em>b</em>/<em>a</em>&nbsp;&le;
100). Note that <em>f</em> is negative for a prolate ellipsoid
(<em>b</em>&nbsp;&gt; <em>a</em>) and that it can be entered as a
fraction, e.g., 1/297.
</p>
<p>
GeodSolve is accurate to about 15&nbsp;nanometers (for the WGS84
ellipsoid) and gives solutions for the inverse problem for any
pair of points.
</p>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/GeodSolve.1.html">
GeodSolve</a>,
which is a simple wrapper of the
<a href="https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1Geodesic.html">
GeographicLib::Geodesic</a> class,
is one of the utilities provided
with <a href="https://geographiclib.sourceforge.io/">
GeographicLib</a>.
Geodesics can also be computed using JavaScript; see the
<a href="../scripts/geod-calc.html">JavaScript geodesic
calculator</a> and
<a href="../scripts/geod-google.html">geodesics on Google
maps</a>. If you wish to use GeodSolve directly,
<a href="https://sourceforge.net/projects/geographiclib/files/distrib-C++">
download</a>
and compile GeographicLib. The algorithms are described
in C. F. F. Karney,
<a href="https://doi.org/10.1007/s00190-012-0578-z"><i>Algorithms for
geodesics</i></a>,
J. Geodesy <b>87</b>, 43&ndash;55 (2013); DOI:
<a href="https://doi.org/10.1007/s00190-012-0578-z">
10.1007/s00190-012-0578-z</a>;
addenda:
<a href="https://geographiclib.sourceforge.io/geod-addenda.html">
geod-addenda.html</a>. See also the Wikipedia page,
<a href="https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid">
Geodesics on an ellipsoid</a>.
</p>
<hr>
<address>Charles Karney
<a href="mailto:charles@karney.com">&lt;charles@karney.com&gt;</a>
(2022-04-10)</address>
<a href="https://geographiclib.sourceforge.io">
GeographicLib home
</a>
</body>
</html>
EOF

View File

@@ -0,0 +1,166 @@
#! /bin/sh
#
# GeoidEval.cgi
# cgi script for geoid height evaluations
#
# Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and
# licensed under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
. ./utils.sh
OPTION=`lookupkey "$QUERY_STRING" option`
if test "$OPTION" = Reset; then
INPUT=
else
INPUT=`lookupcheckkey "$QUERY_STRING" input`
fi
INPUTENC=`encodevalue "$INPUT"`
EXECDIR=../bin
COMMAND="GeoidEval"
VERSION=`$EXECDIR/$COMMAND --version | cut -f4 -d" "`
export GEOGRAPHICLIB_DATA=..
F='<font color="blue">'
G='</font>'
POSITION1=
POSITION2=
HEIGHT96=
HEIGHT84=
HEIGHT2008=
set -o pipefail
if test "$INPUT"; then
HEIGHT96=`echo $INPUT |
$EXECDIR/$COMMAND -n egm96-5 | head -1`
if test $? -eq 0; then
POSITION1=`echo $INPUT | $EXECDIR/GeoConvert | head -1`
POSITION1=`geohack $POSITION1 $POSITION1 Black`
POSITION2=\(`echo $INPUT | $EXECDIR/GeoConvert -d -p -1 | head -1`\)
HEIGHT2008=`echo $INPUT |
$EXECDIR/$COMMAND -n egm2008-1 | head -1`
HEIGHT84=`echo $INPUT |
$EXECDIR/$COMMAND -n egm84-15 | head -1`
else
POSITION1=`encodevalue "$HEIGHT96"`
HEIGHT96=
fi
# echo `date +"%F %T"` "$COMMAND: $INPUT" >> ../persistent/utilities.log
fi
echo Content-type: text/html
echo
cat <<EOF
<html>
<head>
<title>
Online geoid calculator
</title>
<meta name="description" content="Online geoid calculator" />
<meta name="author" content="Charles F. F. Karney" />
<meta name="keywords"
content="geoid height,
orthometric height,
earth gravity model,
EGM84, EGM96, EGM2008,
mean sea level, MSL,
height above ellipsoid, HAE,
vertical datum,
latitude and longitude,
online calculator,
WGS84 ellipsoid,
GeographicLib" />
</head>
<body>
<h3>
Online geoid calculations using the
<a href="https://geographiclib.sourceforge.io/C++/doc/GeoidEval.1.html">
GeoidEval</a> utility
</h3>
<form action="/cgi-bin/GeoidEval" method="get">
<p>
Position
(ex. &laquo;<tt>16.78 -3.01</tt>&raquo;,
&laquo;<tt>16d46'33"N 3d0.6'W</tt>&raquo;):<br>
&nbsp;&nbsp;&nbsp;
<input type=text name="input" size=30 value="$INPUTENC">
</p>
<p>
Select action:<br>
&nbsp;&nbsp;&nbsp;
<input type="submit" name="option" value="Submit">
<input type="submit" name="option" value="Reset">
</p>
<p>
Geoid height:
<font size="4"><pre>
lat lon = $POSITION1 `convertdeg "$POSITION2"`
geoid heights (m)
<a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm2008">EGM2008</a> = $F`encodevalue "$HEIGHT2008"`$G
<a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm96">EGM96</a> = $F`encodevalue "$HEIGHT96"`$G
<a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm84">EGM84</a> = $F`encodevalue "$HEIGHT84"`$G</pre></font>
</p>
</form>
<hr>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/GeoidEval.1.html">
GeoidEval (version $VERSION)</a>
computes the height of the geoid above the WGS84 ellipsoid
using interpolation in a grid of values for the earth
gravity models,
<a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm84">
EGM84</a>, or
<a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm96">
EGM96</a>,
<a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm2008">
EGM2008</a>.
The RMS error in the interpolated height is about 1&nbsp;mm.
Give the position in terms of latitude and longitude, for example
(these all refer to the position of Timbuktu):
<pre>
16.776 -3.009
16d47' -3d1'
W3&deg;0'34" N16&deg;46'33"
3:0:34W 16:46:33N</pre>
The coordinates can also be given in UTM, UPS, or MGRS coordinates (see
the documentation on the
<a href="https://geographiclib.sourceforge.io/C++/doc/GeoConvert.1.html">
GeoConvert</a> utility).
</p>
<p>
The height of the geoid above the ellipsoid, <i>N</i>, is
sometimes called the geoid undulation. It can be used to convert
a height above the ellipsoid, <i>h</i>, to the corresponding
height above the geoid (the orthometric height, roughly the height
above mean sea level), <i>H</i>, using the relations
<blockquote>
<i>h</i> = <i>N</i> + <i>H</i>;
&nbsp;&nbsp;<i>H</i> = &minus;<i>N</i> + <i>h</i>.
</blockquote>
</p>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/GeoidEval.1.html">
GeoidEval</a>,
which is a simple wrapper of the
<a href="https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1Geoid.html">
GeographicLib::Geoid</a> class,
is one of the utilities provided
with <a href="https://geographiclib.sourceforge.io/">
GeographicLib</a>.
This web interface illustrates a subset of its capabilities. If
you wish to use GeoidEval directly,
<a href="https://sourceforge.net/projects/geographiclib/files/distrib-C++">
download</a>
and compile GeographicLib. A description of the methods is given
<a href="https://geographiclib.sourceforge.io/C++/doc/geoid.html">
here</a>.
</p>
<p>
</p>
<hr>
<address>Charles Karney
<a href="mailto:charles@karney.com">&lt;charles@karney.com&gt;</a>
(2022-04-10)</address>
<a href="https://geographiclib.sourceforge.io">
GeographicLib home
</a>
</body>
</html>
EOF

View File

@@ -0,0 +1,230 @@
#! /bin/sh
#
# Planimeter.cgi
# cgi script for measuring the area of geodesic polygons
#
# Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and
# licensed under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
. ./utils.sh
OPTION=`lookupkey "$QUERY_STRING" option`
if test "$OPTION" = Reset; then
INPUT=
else
INPUT=`lookupcheckkey "$QUERY_STRING" input`
NORM=`lookupkey "$QUERY_STRING" norm`
TYPE=`lookupkey "$QUERY_STRING" type`
RHUMB=`lookupkey "$QUERY_STRING" rhumb`
fi
env > /tmp/env
INPUTENC=`encodevalue "$INPUT"`
if test "$TYPE" = "polyline"; then
LINEFLAG=-l
else
LINEFLAG=
fi
if test "$RHUMB" = "rhumb"; then
RHUMBFLAG=-R
else
RHUMBFLAG=
fi
EXECDIR=../bin
# Don't add -E flag since this utility only treats the WGS84 ellipsoid
COMMAND="Planimeter"
VERSION=`$EXECDIR/$COMMAND --version | cut -f4 -d" "`
STATUS=
NUM=
LEN=
AREA=
if test "$INPUT"; then
STATUS=`echo "$INPUT" | head -1 | $EXECDIR/GeoConvert`
if test $? -eq 0; then
STATUS=OK
OUTPUT=`echo "$INPUT" | $EXECDIR/$COMMAND $LINEFLAG $RHUMBFLAG |
head -1`
NUM="`echo $OUTPUT | cut -f1 -d' '`"
LEN="`echo $OUTPUT | cut -f2 -d' '`"
AREA="`echo $OUTPUT | cut -f3 -d' '`"
if test "$NORM"; then
TRANSFORMEDINPUT=`echo "$INPUT" | $EXECDIR/GeoConvert -p 20 |
sed '/^ERROR/,$d'`
INPUTENC=`encodevalue "$TRANSFORMEDINPUT"`
fi
fi
# echo `date +"%F %T"` "$COMMAND: $INPUT" >> ../persistent/utilities.log
fi
echo Content-type: text/html
echo
cat <<EOF
<html>
<head>
<title>
Online geodesic planimeter
</title>
<meta name="description" content="Online geodesic planimeter" />
<meta name="author" content="Charles F. F. Karney" />
<meta name="keywords"
content="geodesics,
geodesic distance,
geodesic area,
geographic distance,
geographic area,
geodesic polygon,
shortest path,
spheroidal triangle,
latitude and longitude,
rhumb lines,
online calculator,
WGS84 ellipsoid,
GeographicLib" />
</head>
<body>
<h3>
Online geodesic polygon calculations using the
<a href="https://geographiclib.sourceforge.io/C++/doc/Planimeter.1.html">
Planimeter</a> utility
</h3>
<form action="/cgi-bin/Planimeter" method="get">
<p>
<table>
<tr>
<td>
Closed/open:
</td>
<td>&nbsp;<label for="c">
<input type="radio" name="type" value="polygon" id="c"
`test "$LINEFLAG" || echo CHECKED`>
Polygon</label>
</td>
<td>&nbsp;<label for="o">
<input type="radio" name="type" value="polyline" id="o"
`test "$LINEFLAG" && echo CHECKED`>
Polyline</label>
</td>
</tr>
<tr>
<td>
Edge type:
</td>
<td>&nbsp;<label for="g">
<input type="radio" name="rhumb" value="geodesic" id="g"
`test "$RHUMBFLAG" || echo CHECKED`>
Geodesic</label>
</td>
<td>&nbsp;<label for="r">
<input type="radio" name="rhumb" value="rhumb" id="r"
`test "$RHUMBFLAG" && echo CHECKED`>
Rhumb line</label>
</td>
</tr>
</table>
</p>
<p>
Enter the vertices as latitude longitude pairs, one per line:
<br>
&nbsp;&nbsp;&nbsp;
<textarea cols=45 rows=15 name="input">$INPUTENC</textarea>
</p>
<p>
<input type="checkbox" name="norm" value="decdegrees"
`test "$NORM" && echo CHECKED` />
Convert vertices to decimal degrees
</p>
<p>
Select action:<br>
&nbsp;&nbsp;&nbsp;
<input type="submit" name="option" value="Submit">
<input type="submit" name="option" value="Reset">
</p>
<p>
Results:<br>
<font size="4"><pre>
STATUS = $STATUS
number of vertices = $NUM
Perimeter (m) = $LEN
area (m^2) = $AREA</pre></font>
</p>
</form>
<hr>
<p>
In polygon mode,
<a href="https://geographiclib.sourceforge.io/C++/doc/Planimeter.1.html">
Planimeter (version $VERSION)</a>
calculates the perimeter and area of a polygon whose edges are
either geodesics or rhumb lines on the WGS84 ellipsoid.
</p>
<p>
The edges of the polygon are given by the <i>shortest</i> geodesic
or rhumb line between consecutive vertices. In certain cases,
there may be two or many such shortest paths, and in that case,
the polygon is not uniquely specified by its vertices. In such
cases, insert an additional vertex near the middle of the long
edge to define the boundary of the polygon.
</p>
<p>
Counter-clockwise traversal of a polygon results in a positive
area. Arbitrarily complex polygons are allowed. In the case of
self-intersecting polygons the area is accumulated
"algebraically", i.e., the areas of the 2 loops in a figure-8
polygon will partially cancel. There is no need to close the
polygon. Polygons may include one or both poles. In polyline
mode,
<a href="https://geographiclib.sourceforge.io/C++/doc/Planimeter.1.html">
Planimeter</a>
calculates the length of the geodesic path joining the points.
</p>
<p>
Give the vertices in terms of latitude and longitude, for example
(these all refer to the position of Timbuktu):
<pre>
16.776 -3.009
16d47' -3d1'
W3&deg;0'34" N16&deg;46'33"
3:0:34W 16:46:33N</pre>
A blank line or a coordinate which cannot be understood
causes the reading of vertices to be stopped.
</p>
<p>
For moderately complex polygons, the perimeter is accurate to
about 200&nbsp;nm and the area is accurate to about
0.1&nbsp;m<sup>2</sup>.
</p>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/Planimeter.1.html">
Planimeter</a>,
which is a simple wrapper of the
<a href="https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1PolygonAreaT.html">
GeographicLib::PolygonAreaT</a> class,
is one of the utilities provided
with <a href="https://geographiclib.sourceforge.io/">
GeographicLib</a>.
Geodesic areas can also be computed using JavaScript; see the
<a href="../scripts/geod-calc.html">JavaScript geodesic
calculator</a>.
If you wish to use Planimeter directly,
<a href="https://sourceforge.net/projects/geographiclib/files/distrib-C++">
download</a>
and compile GeographicLib. The algorithms are described
in C. F. F. Karney,
<a href="https://doi.org/10.1007/s00190-012-0578-z"><i>Algorithms for
geodesics</i></a>,
J. Geodesy <b>87</b>, 43&ndash;55 (2013); DOI:
<a href="https://doi.org/10.1007/s00190-012-0578-z">
10.1007/s00190-012-0578-z</a>;
addenda:
<a href="https://geographiclib.sourceforge.io/geod-addenda.html">
geod-addenda.html</a>.
</p>
<hr>
<address>Charles Karney
<a href="mailto:charles@karney.com">&lt;charles@karney.com&gt;</a>
(2022-04-10)</address>
<a href="https://geographiclib.sourceforge.io">
GeographicLib home
</a>
</body>
</html>
EOF

View File

@@ -0,0 +1,349 @@
#! /bin/sh
#
# RhumbSolve.cgi
# cgi script for rhumb line calculations
#
# Copyright (c) Charles Karney (2014-2022) <charles@karney.com> and
# licensed under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
. ./utils.sh
DEFAULTRADIUS=6378137
DEFAULTFLATTENING=1/298.257223563
OPTION=`lookupkey "$QUERY_STRING" option`
if test "$OPTION" = Reset; then
INPUT=
RADIUS=
FLATTENING=
else
INPUT=`lookupcheckkey "$QUERY_STRING" input`
RADIUS=`lookupellipsoid "$QUERY_STRING" radius`
FLATTENING=`lookupellipsoid "$QUERY_STRING" flattening`
FORMAT=`lookupkey "$QUERY_STRING" format`
PREC=`lookupkey "$QUERY_STRING" prec`
TYPE=`lookupkey "$QUERY_STRING" type`
fi
test "$RADIUS" || RADIUS=$DEFAULTRADIUS
test "$FLATTENING" || FLATTENING=$DEFAULTFLATTENING
test "$FORMAT" || FORMAT=g
test "$PREC" || PREC=3
test "$TYPE" || TYPE=I
TAG=
if test "$RADIUS" = "$DEFAULTRADIUS" -a \
"$FLATTENING" = "$DEFAULTFLATTENING"; then
TAG=" (WGS84)"
fi
INPUTENC=`encodevalue "$INPUT"`
EXECDIR=../bin
COMMAND="RhumbSolve"
VERSION=`$EXECDIR/$COMMAND --version | cut -f4 -d" "`
F='<font color="blue">'
G='</font>'
test $TYPE = D || COMMAND="$COMMAND -i"
COMMANDX="$COMMAND -p 1"
test $FORMAT = g || COMMAND="$COMMAND -$FORMAT"
test $PREC = 3 || COMMAND="$COMMAND -p $PREC"
GCOMMAND=`echo "$COMMAND" | sed "s/RhumbSolve/GeodSolve -f/"`
GCOMMANDX=`echo "$COMMANDX" | sed "s/RhumbSolve/GeodSolve -f/"`
STATUS=
POSITION1=
POSITION2=
DIST12=
S12=
set -o pipefail
if test "$INPUT"; then
OUTPUT=`echo $INPUT | $EXECDIR/$COMMAND -e "$RADIUS" "$FLATTENING" 2>&1 |
head -1`
if test $? -eq 0; then
STATUS=OK
GOUTPUT=`echo $INPUT | $EXECDIR/$GCOMMAND -e "$RADIUS" "$FLATTENING" |
head -1`
OUTPUTF=`echo $INPUT | $EXECDIR/$COMMANDX -e "$RADIUS" "$FLATTENING" |
head -1`
GOUTPUTF=`echo $INPUT |
$EXECDIR/$GCOMMANDX -e "$RADIUS" "$FLATTENING" |
head -1`
if test "$TYPE" = D; then
POS1="`echo $GOUTPUT | cut -f1-2 -d' '`"
POSG1="`echo $GOUTPUTF | cut -f1-2 -d' '`"
AZI12="`echo $GOUTPUT | cut -f3 -d' '`"
DIST12="`echo $GOUTPUT | cut -f7 -d' '`"
POS2="`echo $OUTPUT | cut -f1-2 -d' '`"
POSG2="`echo $OUTPUTF | cut -f1-2 -d' '`"
S12="`echo $OUTPUT | cut -f3 -d' '`"
POSITION1=$(geohack $POSG1 $POS1 Black)
POSITION2=$F$(geohack $POSG2 $POS2 Blue)$G
echo $POS2 | grep nan > /dev/null &&
POSITION2=$F$(convertdeg "$POS2")$G
AZIMUTH=$(convertdeg "$AZI12")
DIST12=$(encodevalue "$DIST12")
else
POS1="`echo $GOUTPUT | cut -f1-2 -d' '`"
POSG1="`echo $GOUTPUTF | cut -f1-2 -d' '`"
POS2="`echo $GOUTPUT | cut -f4-5 -d' '`"
POSG2="`echo $GOUTPUTF | cut -f4-5 -d' '`"
AZI12="`echo $OUTPUT | cut -f1 -d' '`"
DIST12="`echo $OUTPUT | cut -f2 -d' '`"
S12="`echo $OUTPUT | cut -f3 -d' '`"
POSITION1=$(geohack $POSG1 $POS1 Black)
POSITION2=$(geohack $POSG2 $POS2 Black)
AZIMUTH=$F$(convertdeg "$AZI12")$G
DIST12=$F$(encodevalue "$DIST12")$G
fi
else
STATUS="$OUTPUT"
fi
# echo `date +"%F %T"` "$COMMAND: $INPUT" >> ../persistent/utilities.log
fi
echo Content-type: text/html
echo
cat <<EOF
<html>
<head>
<title>
Online rhumb line calculator
</title>
<meta name="description" content="Online rhumb line calculator" />
<meta name="author" content="Charles F. F. Karney" />
<meta name="keywords"
content="rhumb line, loxodrome,
rhumb line distance,
geographic distance,
direct rhumb line problem,
inverse rhumb line problem,
distance and azimuth,
distance and heading,
range and bearing,
latitude and longitude,
online calculator,
WGS84 ellipsoid,
GeographicLib" />
</head>
<body>
<h3>
Online rhumb line calculations using the
<a href="https://geographiclib.sourceforge.io/C++/doc/RhumbSolve.1.html">
RhumbSolve</a> utility
</h3>
<form action="/cgi-bin/RhumbSolve" method="get">
<p>
Rhumb Line calculation:
<table>
<tr>
<td valign='baseline'>
&nbsp;&nbsp;&nbsp;
<label for='I'>
<input type="radio" name="type" value="I" id='I'
`test "$TYPE" = I && echo CHECKED`>
&nbsp;Inverse:&nbsp;
</label>
</td>
<td valign='baseline'>
<em>lat1 lon1 lat2 lon2</em>
</td>
<td valign='baseline'>
&rarr; <em>azi12 s12</em>
</td>
</tr>
<tr>
<td valign='baseline'>
&nbsp;&nbsp;&nbsp;
<label for='D'>
<input type="radio" name="type" value="D" id='D'
`test "$TYPE" = D && echo CHECKED`>
&nbsp;Direct:&nbsp;
</label>
</td>
<td valign='baseline'>
<em>lat1 lon1 azi12 s12</em>
</td>
<td valign='baseline'>
&rarr; <em>lat2 lon2</em>
</td>
</tr>
</table>
</p>
<p>
Input (ex. &laquo;<tt>40.6 -73.8 49&deg;01'N 2&deg;33'E</tt>&raquo;
[inverse],
&laquo;<tt>40d38'23"N 073d46'44"W 53d30' 5850e3</tt>&raquo;
[direct]):
<br>
&nbsp;&nbsp;&nbsp;
<input type=text name="input" size=72 value="$INPUTENC">
</p>
<p>
<table>
<tr>
<td>
Output format:
</td>
EOF
while read c desc; do
CHECKED=
test "$c" = "$FORMAT" && CHECKED=CHECKED
echo "<td>&nbsp;<label for='$c'>"
echo "<input type='radio' name='format' value='$c' id='$c' $CHECKED>"
echo "$desc</label>"
echo "</td>"
done <<EOF
g Decimal degrees
d Degrees minutes seconds
EOF
cat <<EOF
</tr>
<tr>
<td>
Output precision:
</td>
<td colspan="2">&nbsp;
<select name="prec" size=1>
EOF
while read p desc; do
SELECTED=
test "$p" = "$PREC" && SELECTED=SELECTED
echo "<option $SELECTED value='$p'> $desc</option>"
done <<EOF
0 1m 0.00001d 0.1"
1 100mm 0.01"
2 10mm 0.001"
3 1mm 0.0001"
4 100&mu;m 0.00001"
5 10&mu;m 0.000001"
6 1&mu;m 0.0000001"
7 100nm 0.00000001"
8 10nm 0.000000001"
9 1nm 0.0000000001"
EOF
cat <<EOF
</select>
</td>
</tr>
<tr>
<td>Equatorial radius:</td>
<td>
<input type=text name="radius" size=20 value="$RADIUS">
</td>
<td>meters</td>
</tr>
<tr>
<td>Flattening:</td>
<td>
<input type=text name="flattening" size=20 value="$FLATTENING">
</td>
</tr>
</table>
</p>
<p>
Select action:<br>
&nbsp;&nbsp;&nbsp;
<input type="submit" name="option" value="Submit">
<input type="submit" name="option" value="Reset">
</p>
<p>
Rhumb Line (input in black, output in ${F}blue${G}):<br>
<font size="4"><pre>
ellipsoid (a f) = `encodevalue "$RADIUS"` `encodevalue "$FLATTENING"`$TAG
status = `encodevalue "$STATUS"`
lat1 lon1 (&deg;) = $POSITION1
lat2 lon2 (&deg;) = $POSITION2
azi12 (&deg;) = $AZIMUTH
s12 (m) = $DIST12
S12 (m^2) = $F$S12$G</pre></font>
</p>
</form>
<hr>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/RhumbSolve.1.html">
RhumbSolve (version $VERSION)</a>
performs rhumb line calculations for an arbitrary ellipsoid of
revolution. The path with a constant heading between two points
on the ellipsoid at (<em>lat1</em>, <em>lon1</em>) and
(<em>lat2</em>, <em>lon2</em>) is called the <em>rhumb line</em>
(or <em>loxodrome</em>); its length is <em>s12</em> and the rhumb
line has a forward azimuth <em>azi12</em> along its
length. <b>NOTE:</b> the rhumb line is <em>not</em> the shortest
path between two points; that is the geodesic and it is calculated
by
<a href="https://geographiclib.sourceforge.io/cgi-bin/GeodSolve">
GeodSolve</a>.
</p>
<p>
There are two standard rhumb line problems:
<ul>
<li> Direct: &nbsp; given [<em>lat1 lon1 azi12 s12</em>], find
[<em>lat2 lon2</em>];
<li> Inverse: given [<em>lat1 lon1 lat2 lon2</em>], find
[<em>azi12 s12</em>].
</ul>
Latitudes and longitudes can be given in various formats, for
example (these all refer to the position of Timbuktu):
<pre>
16.776 -3.009
16d47' -3d1'
W3&deg;0'34" N16&deg;46'33"
3:0:34W 16:46:33N</pre>
Azimuths are given in degrees clockwise from north. The
distance <em>s12</em> is in meters.
</p>
<p>
The additional quantity computed is:
<ul>
<li> <em>S12</em>, the area between the rhumb line
and the equator (m<sup>2</sup>).
</ul>
</p>
<p>
A point at a pole is treated as a point a tiny distance away from
the pole on the given line of longitude. The longitude becomes
indeterminate when a rhumb line passes through a pole, and
RhumbSolve reports NaNs for the longitude and the area in this
case.
</p>
<p>
The ellipsoid is specified by its equatorial radius, <em>a</em>,
and its flattening, <em>f</em>&nbsp;=
(<em>a</em>&nbsp;&minus;&nbsp;<em>b</em>)/<em>a</em>,
where <em>b</em> is the polar semi-axis. The default values for
these parameters correspond to the WGS84 ellipsoid. The method is
accurate for &minus;99&nbsp;&le; <em>f</em>&nbsp;&le; 0.99
(corresponding to 0.01&nbsp;&le; <em>b</em>/<em>a</em>&nbsp;&le;
100). Note that <em>f</em> is negative for a prolate ellipsoid
(<em>b</em>&nbsp;&gt; <em>a</em>) and that it can be entered as a
fraction, e.g., 1/297.
</p>
<p>
RhumbSolve is accurate to about 15&nbsp;nanometers (for the WGS84
ellipsoid) and gives solutions for the inverse problem for any
pair of points. The longitude becomes indeterminate when a rhumb
line passes through a pole, and this tool reports NaNs (not a
number) for <em>lon2</em> and <em>S12</em> in this case.
</p>
<p>
<a href="https://geographiclib.sourceforge.io/C++/doc/RhumbSolve.1.html">
RhumbSolve</a>,
which is a simple wrapper of the
<a href="https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1Rhumb.html">
GeographicLib::Rhumb</a> class, is one of the utilities provided
with <a href="https://geographiclib.sourceforge.io/">
GeographicLib</a>. See also the section of the GeographicLib
documentation on
<a href="https://geographiclib.sourceforge.io/C++/doc/rhumb.html">
Rhumb lines</a> and the Wikipedia page,
<a href="https://en.wikipedia.org/wiki/Rhumb_line">
Rhumb line</a>.
</P>
<hr>
<address>Charles Karney
<a href="mailto:charles@karney.com">&lt;charles@karney.com&gt;</a>
(2022-04-10)</address>
<a href="https://geographiclib.sourceforge.io">
GeographicLib home page
</a>
</body>
</html>
EOF

View File

@@ -0,0 +1,37 @@
#! /bin/sh -ex
# This is the script to build the utilities for the cgi-bin scripts. Note:
# 0: To access the machine for running this command, use
# ssh -t karney,geographiclib@shell.sourceforge.net create
# Once logged in the following paths are available
# git: /home/git/p/geographiclib/code.git
WEB=/home/project-web/geographiclib
FRS=/home/frs/project/geographiclib
# 1: The utilities used long double (GEOGRAPHICLIB_PRECISION=3)
# 2: GeoidEval needs access to geoid data which is installed in
# $WEB/geoids. It find this with
# export GEOGRAPHICLIB_DATA=..
# 3: Static libraries are used so the utilities are self contained
# executables.
VERSION=2.0
FULLVERSION=$VERSION-alpha
rm -rf /tmp/GeographicLib-$VERSION /tmp/geog-$VERSION
tar xfpzC $FRS/distrib-C++/GeographicLib-$FULLVERSION.tar.gz /tmp
cd /tmp/GeographicLib-$VERSION
# N.B. $HOME/cmake/bin is in PATH for cmake
cmake \
-D CMAKE_INSTALL_PREFIX=/tmp/geog-$VERSION \
-D BUILD_SHARED_LIBS=OFF \
-D GEOGRAPHICLIB_PRECISION=3 \
-D EXAMPLEDIR= -B BUILD -S .
cd BUILD
make
make install
mkdir -p $WEB/bin-$VERSION
cd /tmp/geog-$VERSION/bin
install CartConvert ConicProj GeodesicProj GeoConvert GeodSolve GeoidEval Gravity MagneticField Planimeter RhumbSolve TransverseMercatorProj $WEB/bin-$VERSION/

View File

@@ -0,0 +1,26 @@
#! /bin/sh
#
# printlogs.cgi
# cgi script for printing error logs
#
# Copyright (c) Charles Karney (2011) <charles@karney.com> and licensed
# under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
echo Content-type: text/html
echo
cat <<EOF
<html>
<header>
<title>
GeographicLib web utilities log
</title>
</header>
<body>
<pre>
EOF
cat ../persistent/utilities.log
cat <<EOF
</pre>
</body>
</html>

View File

@@ -0,0 +1,132 @@
# Look up a key in a QUERY_STRING and return raw value
lookuprawkey () {
QUERY="$1"
KEY="$2"
echo "$QUERY" | tr '&' '\n' | grep "^$KEY=" | tail -1 | cut -f2- -d=
}
# Decode raw value translating + to space, changing CR-LF to LF,
# interpreting %XX, converting "," and TAB to spaces, and squeezing
# and trimming spaces.
decodevalue () {
echo "$1" | tr -s '+' ' ' | sed \
-e 's/\\/%5C/g' \
-e 's/%0[dD]%0[aA]/%0A/g' \
-e 's/%\([0-9a-fA-F][0-9a-fA-F]\)/\\x\1/g' -e s/%/%%/g |
xargs -d '\n' printf | tr -s ',\t' ' ' | sed -e 's/^ //' -e 's/ $//'
}
# Apply conversions for the various degree, minute, and second
# symbols, following conversions in DMS.cpp. Add left/right guillemot
# symbols (used to quote examples) to the list of removed symbols.
# Translate UTF-8 and &#nnn; sequences first, then single character
# replacements, then ' ' -> ". This is the same as the order in
# DMS.cpp except for the addition of the &#nnn; sequences and the
# removal of left/right guillemots.
translate () {
echo "$1" |
sed \
-e 's/%C2%B0/d/g' -e 's/%26%23176%3B/d/g' \
-e 's/%C2%BA/d/g' -e 's/%26%23186%3B/d/g' \
-e 's/%E2%81%B0/d/g' -e 's/%26%238304%3B/d/g' \
-e 's/%CB%9A/d/g' -e 's/%26%23730%3B/d/g' \
-e 's/%E2%88%98/d/g' -e 's/%26%238728%3B/d/g' \
\
-e 's/%E2%80%B2/%27/g' -e 's/%26%238242%3B/%27/g' \
-e 's/%E2%80%B5/%27/g' -e 's/%26%238245%3B/%27/g' \
-e 's/%C2%B4/%27/g' -e 's/%26%23180%3B/%27/g' \
-e 's/%E2%80%98/%27/g' -e 's/%26%238216%3B/%27/g' \
-e 's/%E2%80%99/%27/g' -e 's/%26%238217%3B/%27/g' \
-e 's/%E2%80%9B/%27/g' -e 's/%26%238219%3B/%27/g' \
-e 's/%CA%B9/%27/g' -e 's/%26%23697%3B/%27/g' \
-e 's/%CB%8A/%27/g' -e 's/%26%23714%3B/%27/g' \
-e 's/%CB%8B/%27/g' -e 's/%26%23715%3B/%27/g' \
\
-e 's/%E2%80%B3/%22/g' -e 's/%26%238243%3B/%22/g' \
-e 's/%E2%80%B6/%22/g' -e 's/%26%238246%3B/%22/g' \
-e 's/%CB%9D/%22/g' -e 's/%26%23733%3B/%22/g' \
-e 's/%E2%80%9C/%22/g' -e 's/%26%238220%3B/%22/g' \
-e 's/%E2%80%9D/%22/g' -e 's/%26%238221%3B/%22/g' \
-e 's/%E2%80%9F/%22/g' -e 's/%26%238223%3B/%22/g' \
-e 's/%CA%BA/%22/g' -e 's/%26%23698%3B/%22/g' \
\
-e 's/%E2%9E%95/%2B/g' -e 's/%26%2310133%3B/%2B/g' \
-e 's/%E2%81%A4/%2B/g' -e 's/%26%238292%3B/%2B/g' \
\
-e 's/%E2%80%90/-/g' -e 's/%26%238208%3B/-/g' \
-e 's/%E2%80%91/-/g' -e 's/%26%238209%3B/-/g' \
-e 's/%E2%80%93/-/g' -e 's/%26%238211%3B/-/g' \
-e 's/%E2%80%94/-/g' -e 's/%26%238212%3B/-/g' \
-e 's/%E2%88%92/-/g' -e 's/%26%238722%3B/-/g' \
-e 's/%E2%9E%96/-/g' -e 's/%26%2310134%3B/-/g' \
\
-e 's/%C2%A0//g' -e 's/%26%23160%3B//g' \
-e 's/%E2%80%87//g' -e 's/%26%238199%3B//g' \
-e 's/%E2%80%89//g' -e 's/%26%238201%3B//g' \
-e 's/%E2%80%8A//g' -e 's/%26%238202%3B//g' \
-e 's/%E2%80%8B//g' -e 's/%26%238203%3B//g' \
-e 's/%E2%80%AF//g' -e 's/%26%238239%3B//g' \
-e 's/%C2%AB//g' -e 's/%26%23171%3B//g' \
-e 's/%C2%BB//g' -e 's/%26%23187%3B//g' \
-e 's/%E2%81%A3//g' -e 's/%26%238291%3B//g' \
\
-e 's/%B0/d/g' \
-e 's/%BA/d/g' \
-e 's/%2A/d/g' -e 's/\*/d/g' \
-e 's/%60/%27/g' -e 's/`/%27/g' \
-e 's/%B4/%27/g' \
-e 's/%91/%27/g' \
-e 's/%92/%27/g' \
-e 's/%93/%22/g' \
-e 's/%94/%22/g' \
-e 's/%96/-/g' \
-e 's/%97/-/g' \
-e 's/%A0//g' \
-e 's/%AB//g' \
-e 's/%BB//g' \
\
-e 's/%27%27/%22/g'
}
# Look up and decode a key
lookupkey () {
decodevalue `lookuprawkey "$1" "$2"`
}
# Look up, translate, and decode a key. If result has unprintable
# characters, log the raw value.
lookupcheckkey () {
RAWVAL=`lookuprawkey "$1" "$2"`
VALUE=`translate "$RAWVAL"`
VALUE=`decodevalue "$VALUE"`
test `echo "$VALUE" | tr -d '[ -~\n\t]' | wc -c` -ne 0 &&
echo `date +"%F %T"` Unprintable "$RAWVAL" >> ../persistent/utilities.log
echo "$VALUE"
}
# Look up ellipsoid parameter leaving only allowed characters (--/ -> -, ., /)
lookupellipsoid () {
VALUE=`lookuprawkey "$1" "$2"`
VALUE=`echo "$VALUE" | sed -e 's/%26%238722%3B/-/g'`
VALUE=`decodevalue "$VALUE"`
VALUE=`echo "$VALUE" | tr -cd '[0-9--/Ee]'`
echo "$VALUE"
}
# Encode a string for inclusion into HTML.
encodevalue () {
echo "$1" | sed -e 's/&/\&amp;/g' -e 's/"/\&quot;/g' \
-e 's/>/\&gt;/g' -e 's/</\&lt;/g' -e "s/'/\&#39;/g" -e 's/`/\&#96;/g'
}
# Encode and convert d to &deg;
convertdeg () {
encodevalue "$1" | sed -e 's/d/\&deg;/g'
}
# Generate GeoHack URL. $1 $2 are real position; $3 $4 is displayed
# postion; $5 is link color
geohack () {
echo "<a href=\"http://tools.wmflabs.org/geohack/geohack.php?params=$1;$2\" style=\"color:$5\">$(convertdeg "$3 $4")</a>"
}

View File

@@ -0,0 +1,105 @@
# config file support for find_package (GeographicLib). This needs to
# deal with two environments: (1) finding the build tree and (2)
# finding the install tree. geographiclib-config.cmake detects which
# situation it is handing by looking at @PROJECT_ROOT_DIR@. If
# this is an absolute path, it's in the build tree; otherwise, it's in the
# install tree. (Note that the whole install tree can be relocated.)
# Variables needed by ${PROJECT_NAME_LOWER}-config-version.cmake
if (MSVC)
# For checking the compatibility of MSVC_TOOLSET_VERSION; see
# https://docs.microsoft.com/en-us/cpp/porting/overview-of-potential-upgrade-issues-visual-cpp
# Assume major version number is obtained by dropping the last decimal
# digit.
math (EXPR MSVC_TOOLSET_MAJOR "${MSVC_TOOLSET_VERSION}/10")
else ()
set (MSVC_TOOLSET_VERSION 0)
set (MSVC_TOOLSET_MAJOR 0)
endif ()
if (CMAKE_CROSSCOMPILING)
# Ensure that all "true" (resp. "false") settings are represented by
# the same string.
set (CMAKE_CROSSCOMPILING_STR "ON")
else ()
set (CMAKE_CROSSCOMPILING_STR "OFF")
endif ()
# geographiclib-config.cmake for the build tree
set (PROJECT_ROOT_DIR "${PROJECT_BINARY_DIR}")
set (PROJECT_INCLUDE_DIRS
"${PROJECT_BINARY_DIR}/include" "${PROJECT_SOURCE_DIR}/include")
if (PROJECT_STATIC_LIBRARIES)
set (CONFIG_STATIC_LIBRARIES "${PROJECT_NAME}::${PROJECT_STATIC_LIBRARIES}")
else ()
set (CONFIG_STATIC_LIBRARIES)
endif ()
if (PROJECT_SHARED_LIBRARIES)
set (CONFIG_SHARED_LIBRARIES "${PROJECT_NAME}::${PROJECT_SHARED_LIBRARIES}")
else ()
set (CONFIG_SHARED_LIBRARIES)
endif ()
configure_file (project-config.cmake.in
"${PROJECT_BINARY_DIR}/${PROJECT_NAME_LOWER}-config.cmake" @ONLY)
configure_file (project-config-version.cmake.in
"${PROJECT_BINARY_DIR}/${PROJECT_NAME_LOWER}-config-version.cmake" @ONLY)
export (TARGETS
${PROJECT_ALL_LIBRARIES} ${TOOLS}
NAMESPACE ${PROJECT_NAME}::
FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME_LOWER}-targets.cmake")
# geographiclib-config.cmake for the install tree. It's installed in
# ${CMAKEDIR} and @PROJECT_ROOT_DIR@ is the relative path to the root
# from there. (Note that the whole install tree can be relocated.)
if (CMAKEDIR)
# Find root of install tree relative to CMAKEDIR
file (RELATIVE_PATH PROJECT_ROOT_DIR
"${CMAKE_INSTALL_PREFIX}/${CMAKEDIR}" "${CMAKE_INSTALL_PREFIX}")
# strip trailing slash
get_filename_component (PROJECT_ROOT_DIR "${PROJECT_ROOT_DIR}/." PATH)
# @PROJECT_INCLUDE_DIRS@ is not used in the install tree; reset
# it to prevent the source and build paths appearing in the installed
# config files
set (PROJECT_INCLUDE_DIRS)
configure_file (project-config.cmake.in project-config.cmake @ONLY)
configure_file (project-config-version.cmake.in
project-config-version.cmake @ONLY)
install (FILES
"${CMAKE_CURRENT_BINARY_DIR}/project-config.cmake"
DESTINATION "${CMAKEDIR}"
RENAME "${PROJECT_NAME_LOWER}-config.cmake")
install (FILES
"${CMAKE_CURRENT_BINARY_DIR}/project-config-version.cmake"
DESTINATION "${CMAKEDIR}"
RENAME "${PROJECT_NAME_LOWER}-config-version.cmake")
# Make information about the cmake targets (the library and the tools)
# available.
install (EXPORT targets
NAMESPACE ${PROJECT_NAME}::
FILE ${PROJECT_NAME_LOWER}-targets.cmake
DESTINATION "${CMAKEDIR}")
if (MSVC AND PACKAGE_DEBUG_LIBS)
install (FILES
"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Export/${CMAKEDIR}/${PROJECT_NAME_LOWER}-targets-debug.cmake"
DESTINATION "${CMAKEDIR}" CONFIGURATIONS Release)
endif ()
endif ()
# Support for pkgconfig/geographiclib.pc
set (prefix ${CMAKE_INSTALL_PREFIX})
set (exec_prefix "\${prefix}")
set (libdir "\${exec_prefix}/${LIBDIR}")
set (includedir "\${prefix}/${INCDIR}")
set (bindir "\${exec_prefix}/${BINDIR}")
set (PACKAGE_NAME "${PROJECT_NAME}")
set (PACKAGE_VERSION "${PROJECT_VERSION}")
configure_file (project.pc.in geographiclib.pc @ONLY)
if (PKGDIR)
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/geographiclib.pc"
DESTINATION "${PKGDIR}")
endif ()

View File

@@ -0,0 +1,41 @@
# Look for GeographicLib
#
# Set
# GeographicLib_FOUND = TRUE
# GeographicLib_INCLUDE_DIRS = /usr/local/include
# GeographicLib_LIBRARIES = /usr/local/lib/libGeographicLib.so
# GeographicLib_LIBRARY_DIRS = /usr/local/lib
find_library (GeographicLib_LIBRARIES GeographicLib
PATHS "${CMAKE_INSTALL_PREFIX}/../GeographicLib/lib")
if (GeographicLib_LIBRARIES)
get_filename_component (GeographicLib_LIBRARY_DIRS
"${GeographicLib_LIBRARIES}" PATH)
get_filename_component (_ROOT_DIR "${GeographicLib_LIBRARY_DIRS}" PATH)
set (GeographicLib_INCLUDE_DIRS "${_ROOT_DIR}/include")
set (GeographicLib_BINARY_DIRS "${_ROOT_DIR}/bin")
if (NOT EXISTS "${GeographicLib_INCLUDE_DIRS}/GeographicLib/Config.h")
# On Debian systems the library is in e.g.,
# /usr/lib/x86_64-linux-gnu/libGeographicLib.so
# so try stripping another element off _ROOT_DIR
get_filename_component (_ROOT_DIR "${_ROOT_DIR}" PATH)
set (GeographicLib_INCLUDE_DIRS "${_ROOT_DIR}/include")
set (GeographicLib_BINARY_DIRS "${_ROOT_DIR}/bin")
if (NOT EXISTS "${GeographicLib_INCLUDE_DIRS}/GeographicLib/Config.h")
unset (GeographicLib_INCLUDE_DIRS)
unset (GeographicLib_LIBRARIES)
unset (GeographicLib_LIBRARY_DIRS)
unset (GeographicLib_BINARY_DIRS)
endif ()
endif ()
unset (_ROOT_DIR)
endif ()
# This sets GeographicLib_FOUND (and GEOGRAPHICLIB_FOUND, deprecated) to TRUE
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (GeographicLib DEFAULT_MSG
GeographicLib_LIBRARY_DIRS GeographicLib_LIBRARIES
GeographicLib_INCLUDE_DIRS)
mark_as_advanced (GeographicLib_LIBRARY_DIRS GeographicLib_LIBRARIES
GeographicLib_INCLUDE_DIRS)

View File

@@ -0,0 +1,14 @@
#
# Makefile.am
#
# Copyright (C) 2011-2022, Charles Karney <charles@karney.com>
cmakedir=$(datadir)/cmake/GeographicLib
install:
$(INSTALL) -d $(DESTDIR)$(cmakedir)
$(INSTALL) -m 644 $(srcdir)/FindGeographicLib.cmake \
$(DESTDIR)$(cmakedir)
EXTRA_DIST = CMakeLists.txt FindGeographicLib.cmake \
project-config-version.cmake.in project-config.cmake.in

View File

@@ -0,0 +1,82 @@
# In non-RELEASE mode the mans pages are in pod format
add_custom_target (man ALL)
set (MANPAGES)
set (USAGE)
set (HTMLMAN)
foreach (TOOL ${TOOLS})
set (MANPAGES ${MANPAGES} ${CMAKE_CURRENT_BINARY_DIR}/${TOOL}.1)
set (USAGE ${USAGE} ${CMAKE_CURRENT_BINARY_DIR}/${TOOL}.usage)
set (HTMLMAN ${HTMLMAN} ${CMAKE_CURRENT_BINARY_DIR}/${TOOL}.1.html)
if (MAINTAINER)
# A maintainer can transform these to man, html, and usage formats.
add_custom_command (OUTPUT ${TOOL}.1
COMMAND ${POD2MAN} --center=\"GeographicLib Utilities\"
--release=\"GeographicLib ${PROJECT_VERSION}\"
${CMAKE_CURRENT_SOURCE_DIR}/${TOOL}.pod > ${TOOL}.1
COMMENT "Building man page for ${TOOL}"
MAIN_DEPENDENCY ${TOOL}.pod)
add_custom_command (OUTPUT ${TOOL}.1.html COMMAND
${POD2HTML} --title "'${TOOL}(1)'"
--noindex ${CMAKE_CURRENT_SOURCE_DIR}/${TOOL}.pod |
sed
-e 's%<head>%<head><link href="http://search.cpan.org/s/style.css" rel="stylesheet" type="text/css">%'
-e 's%<code>\\\([^<>]*\\\)\(\\\(.\\\)\)</code>%<a href="\\1.\\2.html">&</a>%'g > ${TOOL}.1.html
COMMENT "Building html version of man page for ${TOOL}"
MAIN_DEPENDENCY ${TOOL}.pod)
add_custom_command (OUTPUT ${TOOL}.usage
COMMAND env POD2MAN=${POD2MAN} COL=${COL}
sh ${CMAKE_CURRENT_SOURCE_DIR}/makeusage.sh
${CMAKE_CURRENT_SOURCE_DIR}/${TOOL}.pod ${PROJECT_VERSION}
> ${TOOL}.usage
COMMENT "Building usage code for ${TOOL}"
MAIN_DEPENDENCY ${TOOL}.pod)
else ()
# Otherwise, dummy versions of these pages are created from
# templates dummy.XXX.in. These dummy versions point to the online
# documentation.
configure_file (dummy.usage.in ${TOOL}.usage @ONLY)
configure_file (dummy.1.in ${TOOL}.1 @ONLY)
configure_file (dummy.1.html.in ${TOOL}.1.html @ONLY)
endif ()
endforeach ()
if (MANDIR AND BINDIR)
install (FILES ${MANPAGES} DESTINATION ${MANDIR}/man1)
endif ()
if (MAINTAINER)
add_custom_target (manpages ALL DEPENDS ${MANPAGES}
COMMENT "Building all the man pages")
add_custom_target (usage ALL DEPENDS ${USAGE}
COMMENT "Converting the man pages to online usage")
add_custom_target (htmlman ALL DEPENDS ${HTMLMAN}
COMMENT "Building html versions of the man pages")
else ()
add_custom_target (manpages ALL DEPENDS ${MANPAGES}
COMMENT "Building dummy man pages")
add_custom_target (usage ALL DEPENDS ${USAGE}
COMMENT "Converting dummy man pages to online usage")
add_custom_target (htmlman ALL DEPENDS ${HTMLMAN}
COMMENT "Building dummy html versions of the man pages")
endif ()
add_dependencies (man manpages usage htmlman)
if (MAINTAINER)
# The distrib-man target copies the derived documentation files into
# the source tree.
add_custom_target (distrib-man)
add_dependencies (distrib-man man)
add_custom_command (TARGET distrib-man
COMMAND
for f in ${MANPAGES} ${USAGE} ${HTMLMAN}\; do
install -C -m 644 "$$f" ../distrib/${PACKAGE_DIR}/man\; done
COMMENT "Installing man documentation page in source tree")
endif ()

View File

@@ -0,0 +1,123 @@
set (DISTRIB_DIR "${CMAKE_BINARY_DIR}/distrib")
set (DISTRIB_NAME "${DISTRIB_DIR}/${PACKAGE_DIR}")
add_custom_target (prep-source
COMMAND ${CMAKE_MAKE_PROGRAM} package_source
COMMAND ${CMAKE_COMMAND} -E rm -rf ${DISTRIB_NAME}
COMMAND ${CMAKE_COMMAND} -E copy_directory
_CPack_Packages/Linux-Source/TGZ/${PACKAGE_DIR} ${DISTRIB_NAME}
COMMAND cd ${DISTRIB_NAME} &&
find * -type f | sort -u > ${DISTRIB_DIR}/files.1 &&
( cd ${PROJECT_SOURCE_DIR} && git ls-files ) |
sort -u > ${DISTRIB_DIR}/files.2 &&
comm -23 ${DISTRIB_DIR}/files.[12] | xargs -r -d '\\n' rm
# Remove now empty directories
COMMAND for p in 1 2 3 4 5\; do
find ${DISTRIB_NAME} -type d -empty -print0 | xargs -0r rmdir\; done
COMMAND ${CMAKE_COMMAND} -E rm -f autogen.done)
add_custom_command (OUTPUT autogen.done
COMMAND cd ${DISTRIB_NAME} && ${PROJECT_SOURCE_DIR}/autogen.sh &&
touch ${PROJECT_BINARY_DIR}/autogen.done
DEPENDS prep-source autogen.sh configure.ac
Makefile.am src/Makefile.am include/Makefile.am tools/Makefile.am
doc/Makefile.am man/Makefile.am cmake/Makefile.am
examples/Makefile.am tests/Makefile.am)
add_dependencies (distrib-man prep-source)
add_custom_target (distrib-all DEPENDS distrib-man autogen.done)
add_custom_command (TARGET distrib-all
COMMAND cd ${DISTRIB_NAME} && echo ${PROJECT_VERSION} > VERSION &&
chmod -R g-w .)
add_custom_target (dist
COMMAND
cd ${DISTRIB_DIR} &&
find ${PACKAGE_DIR} -type f | tar cfzT ${PACKAGE_NAME}.tar.gz -
COMMAND
rm -f ${DISTRIB_DIR}/${PACKAGE_NAME}.zip &&
cd ${DISTRIB_DIR} &&
find ${PACKAGE_DIR} -type f | zip -q ${PACKAGE_NAME}.zip -@
COMMENT "created distrib/${PACKAGE_NAME}.{tar.gz,zip}")
add_dependencies (dist distrib-all)
if (RSYNC)
set (USER karney)
set (DATATOP $ENV{HOME}/web/geographiclib-files)
set (DATAROOT ${DATATOP}/distrib-C++)
set (DOCTOP $ENV{HOME}/web/geographiclib-web)
set (DOCROOT ${DOCTOP}/htdocs/C++)
set (CGIROOT ${DOCTOP}/cgi-bin)
set (GEOIDROOT ${DOCTOP}/geoids)
set (FRSDEPLOY ${USER}@frs.sourceforge.net:/home/frs/project/geographiclib)
set (WEBDEPLOY ${USER},geographiclib@web.sourceforge.net:.)
add_custom_target (stage-dist
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${DISTRIB_DIR}/${PACKAGE_NAME}.tar.gz
${DISTRIB_DIR}/${PACKAGE_NAME}.zip
${PROJECT_SOURCE_DIR}/data-distrib/distrib-C++/)
add_dependencies (stage-dist dist)
if (BUILD_DOCUMENTATION)
add_custom_target (stage-doc
COMMAND ${RSYNC} --delete -a doc/html/ ${DOCROOT}/${PROJECT_VERSION}/)
add_dependencies (stage-doc doc)
endif ()
add_custom_target (deploy-dist
COMMAND
${RSYNC} --delete -av --exclude '*~'
${PROJECT_SOURCE_DIR}/data-distrib/distrib-C++/ ${DATAROOT}/ &&
${RSYNC} --delete -av
${PROJECT_SOURCE_DIR}/data-distrib/00README.md
${PROJECT_SOURCE_DIR}/data-distrib/distrib ${DATATOP}/
COMMAND ${RSYNC} --delete -av
${DATAROOT} ${DATATOP}/00README.md ${DATATOP}/distrib
${USER}@frs.sourceforge.net:/home/frs/project/geographiclib/)
add_custom_target (deploy-data
COMMAND
${RSYNC} --delete -av --exclude '*~'
${PROJECT_SOURCE_DIR}/data-distrib/*-distrib ${DATATOP}/
COMMAND ${RSYNC} --delete -av ${DATATOP}/*-distrib
${USER}@frs.sourceforge.net:/home/frs/project/geographiclib/)
add_custom_target (deploy-doc
COMMAND ${RSYNC} --delete -av -e ssh ${DOCROOT} ${WEBDEPLOY}/htdocs/)
set (CGI_SCRIPTS
GeoConvert GeodSolve GeoidEval Planimeter RhumbSolve printlogs Geod)
set (CGI_UTILS utils)
add_custom_target (stage-cgi
COMMAND for f in ${CGI_SCRIPTS}\; do
install -C $$f.cgi ${CGIROOT}/$$f\; done
COMMAND for f in ${CGI_UTILS}\; do
install -C -m 644 $$f.sh ${CGIROOT}/$$f.sh\; done
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/cgi-bin)
add_custom_target (deploy-cgi
COMMAND ${RSYNC} --delete -av -e ssh ${CGIROOT} ${GEOIDROOT} ${WEBDEPLOY}/)
endif ()
if (NOT WIN32)
set (BINARY_EXT "m4|gif|pdf|png|kmz")
add_custom_target (checktrailingspace
COMMAND git ls-files |
egrep -v '\\.\(${BINARY_EXT}\)$$' |
xargs grep '[ \t]$$' || true
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Looking for trailing spaces")
add_custom_target (checktabs
COMMAND git ls-files |
egrep -v '\([Mm]akefile|test-distribution.sh|\\.\(${BINARY_EXT}\)$$\)' |
xargs grep -l '\t' || true
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Looking for tabs")
add_custom_target (checkblanklines
COMMAND git ls-files |
egrep -v '\\.\(${BINARY_EXT}\)$$' |
while read f\; do tr 'X\\n' 'YX' < $$f |
egrep '\(^X|XXX|XX$$|[^X]$$\)' > /dev/null && echo $$f\; done || true
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Looking for extra blank lines")
add_custom_target (sanitize)
add_dependencies (sanitize checktrailingspace checktabs checkblanklines)
endif ()

View File

@@ -0,0 +1,90 @@
# Version checking for @PROJECT_NAME@
set (PACKAGE_VERSION "@PROJECT_VERSION@")
set (PACKAGE_VERSION_MAJOR "@PROJECT_VERSION_MAJOR@")
set (PACKAGE_VERSION_MINOR "@PROJECT_VERSION_MINOR@")
set (PACKAGE_VERSION_PATCH "@PROJECT_VERSION_PATCH@")
# These variable definitions parallel those in @PROJECT_NAME@'s
# cmake/CMakeLists.txt.
if (MSVC)
# For checking the compatibility of MSVC_TOOLSET_VERSION; see
# https://docs.microsoft.com/en-us/cpp/porting/overview-of-potential-upgrade-issues-visual-cpp
# Assume major version number is obtained by dropping the last decimal
# digit.
math (EXPR MSVC_TOOLSET_MAJOR "${MSVC_TOOLSET_VERSION}/10")
endif ()
if (CMAKE_CROSSCOMPILING)
# Ensure that all "true" (resp. "false") settings are represented by
# the same string.
set (CMAKE_CROSSCOMPILING_STR "ON")
else ()
set (CMAKE_CROSSCOMPILING_STR "OFF")
endif ()
if (NOT PACKAGE_FIND_NAME STREQUAL "@PROJECT_NAME@")
# Check package name (in particular, because of the way cmake finds
# package config files, the capitalization could easily be "wrong").
# This is necessary to ensure that the automatically generated
# variables, e.g., <package>_FOUND, are consistently spelled.
set (REASON "package = @PROJECT_NAME@, NOT ${PACKAGE_FIND_NAME}")
set (PACKAGE_VERSION_UNSUITABLE TRUE)
elseif (NOT (APPLE OR (NOT DEFINED CMAKE_SIZEOF_VOID_P) OR
CMAKE_SIZEOF_VOID_P EQUAL @CMAKE_SIZEOF_VOID_P@))
# Reject if there's a 32-bit/64-bit mismatch (not necessary with Apple
# since a multi-architecture library is built for that platform).
set (REASON "sizeof(*void) = @CMAKE_SIZEOF_VOID_P@")
set (PACKAGE_VERSION_UNSUITABLE TRUE)
elseif (MSVC AND NOT (
# toolset version must be at least as great as @PROJECT_NAME@'s.
MSVC_TOOLSET_VERSION GREATER_EQUAL @MSVC_TOOLSET_VERSION@
# and major versions must match
AND MSVC_TOOLSET_MAJOR EQUAL @MSVC_TOOLSET_MAJOR@ ))
# Reject if there's a mismatch in MSVC compiler versions.
set (REASON "MSVC_TOOLSET_VERSION = @MSVC_TOOLSET_VERSION@")
set (PACKAGE_VERSION_UNSUITABLE TRUE)
elseif (GEOGRAPHICLIB_PRECISION MATCHES "^[1-5]\$" AND NOT (
GEOGRAPHICLIB_PRECISION EQUAL @GEOGRAPHICLIB_PRECISION@ ))
# Reject if the user asks for an incompatible precsision.
set (REASON "GEOGRAPHICLIB_PRECISION = @GEOGRAPHICLIB_PRECISION@")
set (PACKAGE_VERSION_UNSUITABLE TRUE)
elseif (NOT CMAKE_CROSSCOMPILING_STR STREQUAL "@CMAKE_CROSSCOMPILING_STR@")
# Reject if there's a mismatch in ${CMAKE_CROSSCOMPILING}.
set (REASON "cross-compiling = @CMAKE_CROSSCOMPILING@")
set (PACKAGE_VERSION_UNSUITABLE TRUE)
elseif (CMAKE_CROSSCOMPILING AND
NOT (CMAKE_SYSTEM_NAME STREQUAL "@CMAKE_SYSTEM_NAME@" AND
CMAKE_SYSTEM_PROCESSOR STREQUAL "@CMAKE_SYSTEM_PROCESSOR@"))
# Reject if cross-compiling and there's a mismatch in the target system.
set (REASON "target = @CMAKE_SYSTEM_NAME@-@CMAKE_SYSTEM_PROCESSOR@")
set (PACKAGE_VERSION_UNSUITABLE TRUE)
elseif (PACKAGE_FIND_VERSION)
if (PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
set (PACKAGE_VERSION_EXACT TRUE)
elseif (PACKAGE_FIND_VERSION VERSION_LESS PACKAGE_VERSION
AND PACKAGE_FIND_VERSION_MAJOR EQUAL PACKAGE_VERSION_MAJOR)
set (PACKAGE_VERSION_COMPATIBLE TRUE)
endif ()
endif ()
set (@PROJECT_NAME@_SHARED_FOUND @GEOGRAPHICLIB_SHARED_LIB@)
set (@PROJECT_NAME@_STATIC_FOUND @GEOGRAPHICLIB_STATIC_LIB@)
# Check for the components requested. The convention is that
# @PROJECT_NAME@_${comp}_FOUND should be true for all the required
# components.
if (@PROJECT_NAME@_FIND_COMPONENTS)
foreach (comp ${@PROJECT_NAME@_FIND_COMPONENTS})
if (@PROJECT_NAME@_FIND_REQUIRED_${comp} AND
NOT @PROJECT_NAME@_${comp}_FOUND)
set (REASON "without ${comp}")
set (PACKAGE_VERSION_UNSUITABLE TRUE)
endif ()
endforeach ()
endif ()
# If unsuitable, append the reason to the package version so that it's
# visible to the user.
if (PACKAGE_VERSION_UNSUITABLE)
set (PACKAGE_VERSION "${PACKAGE_VERSION} (${REASON})")
endif ()

View File

@@ -0,0 +1,97 @@
# Configure @PROJECT_NAME@
#
# Set
# @PROJECT_NAME@_FOUND = TRUE
# @PROJECT_NAME@_INCLUDE_DIRS = /usr/local/include
# @PROJECT_NAME@_SHARED_LIBRARIES = GeographicLib_SHARED (or empty)
# @PROJECT_NAME@_STATIC_LIBRARIES = GeographicLib_STATIC (or empty)
# @PROJECT_NAME@_LIBRARY_DIRS = /usr/local/lib
# @PROJECT_NAME@_BINARY_DIRS = /usr/local/bin
# @PROJECT_NAME@_VERSION = 1.34 (for example)
# @PROJECT_NAME_UPPER@_DATA = /usr/local/share/GeographicLib (for example)
# Depending on @PROJECT_NAME@_USE_STATIC_LIBS
# @PROJECT_NAME@_LIBRARIES = ${@PROJECT_NAME@_SHARED_LIBRARIES}, if OFF
# @PROJECT_NAME@_LIBRARIES = ${@PROJECT_NAME@_STATIC_LIBRARIES}, if ON
# If only one of the libraries is provided, then
# @PROJECT_NAME@_USE_STATIC_LIBS is ignored.
#
# Since cmake 2.8.11 or later, there's no need to include
# include_directories (${GeographicLib_INCLUDE_DIRS})
# The variables are retained for information.
#
# The following variables are only relevant if the library has been
# compiled with a default precision different from double:
# @PROJECT_NAME_UPPER@_PRECISION = the precision of the library (usually 2)
# @PROJECT_NAME@_HIGHPREC_LIBRARIES = the libraries need for high precision
message (STATUS "Reading ${CMAKE_CURRENT_LIST_FILE}")
# @PROJECT_NAME@_VERSION is set by version file
message (STATUS
"@PROJECT_NAME@ configuration, version ${@PROJECT_NAME@_VERSION}")
# Tell the user project where to find our headers and libraries
get_filename_component (_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
if (IS_ABSOLUTE "@PROJECT_ROOT_DIR@")
# This is an uninstalled package (still in the build tree)
set (_ROOT "@PROJECT_ROOT_DIR@")
set (@PROJECT_NAME@_INCLUDE_DIRS "@PROJECT_INCLUDE_DIRS@")
set (@PROJECT_NAME@_LIBRARY_DIRS "${_ROOT}/src")
set (@PROJECT_NAME@_BINARY_DIRS "${_ROOT}/tools")
else ()
# This is an installed package; figure out the paths relative to the
# current directory.
get_filename_component (_ROOT "${_DIR}/@PROJECT_ROOT_DIR@" ABSOLUTE)
set (@PROJECT_NAME@_INCLUDE_DIRS "${_ROOT}/include")
set (@PROJECT_NAME@_LIBRARY_DIRS "${_ROOT}/lib@LIB_SUFFIX@")
set (@PROJECT_NAME@_BINARY_DIRS "${_ROOT}/bin")
endif ()
set (@PROJECT_NAME_UPPER@_DATA "@GEOGRAPHICLIB_DATA@")
set (@PROJECT_NAME_UPPER@_PRECISION @GEOGRAPHICLIB_PRECISION@)
set (@PROJECT_NAME@_HIGHPREC_LIBRARIES "@HIGHPREC_LIBRARIES@")
set (@PROJECT_NAME@_SHARED_LIBRARIES @CONFIG_SHARED_LIBRARIES@)
set (@PROJECT_NAME@_STATIC_LIBRARIES @CONFIG_STATIC_LIBRARIES@)
# Read in the exported definition of the library
include ("${_DIR}/@PROJECT_NAME_LOWER@-targets.cmake")
# For interoperability with older installations of GeographicLib and
# with packages which depend on GeographicLib, @PROJECT_NAME@_LIBRARIES
# etc. still point to the non-namespace variables. Tentatively plan to
# transition to namespace variables as follows:
#
# * namespace targets were introduced with version 1.47 (2017-02-15)
# * switch @PROJECT_NAME@_LIBRARIES to point to namespace variable after
# 2020-02
# * remove non-namespace variables after 2023-02
unset (_ROOT)
unset (_DIR)
if ((NOT @PROJECT_NAME@_SHARED_LIBRARIES) OR
(@PROJECT_NAME@_USE_STATIC_LIBS AND @PROJECT_NAME@_STATIC_LIBRARIES))
set (@PROJECT_NAME@_LIBRARIES ${@PROJECT_NAME@_STATIC_LIBRARIES})
message (STATUS " \${@PROJECT_NAME@_LIBRARIES} set to static library")
else ()
set (@PROJECT_NAME@_LIBRARIES ${@PROJECT_NAME@_SHARED_LIBRARIES})
message (STATUS " \${@PROJECT_NAME@_LIBRARIES} set to shared library")
endif ()
# Check for the components requested. This only supports components
# STATIC and SHARED by checking the value of
# @PROJECT_NAME@_${comp}_LIBRARIES. No need to check if the component
# is required or not--the version file took care of that.
# @PROJECT_NAME@_${comp}_FOUND is set appropriately for each component.
if (@PROJECT_NAME@_FIND_COMPONENTS)
foreach (comp ${@PROJECT_NAME@_FIND_COMPONENTS})
if (@PROJECT_NAME@_${comp}_LIBRARIES)
set (@PROJECT_NAME@_${comp}_FOUND TRUE)
message (STATUS "@PROJECT_NAME@ component ${comp} found")
else ()
set (@PROJECT_NAME@_${comp}_FOUND FALSE)
message (WARNING "@PROJECT_NAME@ component ${comp} not found")
endif ()
endforeach ()
endif ()
# @PROJECT_NAME@_FOUND is set to TRUE automatically
set (@PROJECT_NAME_UPPER@_FOUND TRUE) # for backwards compatibility, deprecated

View File

@@ -0,0 +1,14 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
bindir=@bindir@
Name: @PACKAGE_NAME@
Description: A library for geographic projections
Version: @PACKAGE_VERSION@
URL: https://geographiclib.sourceforge.io
Requires:
Libs: -L${libdir} -l@PACKAGE_NAME@
Cflags: -I${includedir}

View File

@@ -0,0 +1,93 @@
dnl
dnl Copyright (C) 2009, Francesco P. Lovergine <frankie@debian.org>
AC_INIT([GeographicLib],[2.1.2],[charles@karney.com])
AC_CANONICAL_TARGET
AC_PREREQ([2.71])
AC_CONFIG_SRCDIR(src/Geodesic.cpp)
AC_CONFIG_MACRO_DIR(m4)
AM_INIT_AUTOMAKE
GEOGRAPHICLIB_VERSION_MAJOR=2
GEOGRAPHICLIB_VERSION_MINOR=1
GEOGRAPHICLIB_VERSION_PATCH=2
AC_DEFINE_UNQUOTED([GEOGRAPHICLIB_VERSION_MAJOR],
[$GEOGRAPHICLIB_VERSION_MAJOR],[major version number])
AC_DEFINE_UNQUOTED([GEOGRAPHICLIB_VERSION_MINOR],
[$GEOGRAPHICLIB_VERSION_MINOR],[minor version number])
AC_DEFINE_UNQUOTED([GEOGRAPHICLIB_VERSION_PATCH],
[$GEOGRAPHICLIB_VERSION_PATCH],[patch number])
AC_SUBST(GEOGRAPHICLIB_VERSION_MAJOR)
AC_SUBST(GEOGRAPHICLIB_VERSION_MINOR)
AC_SUBST(GEOGRAPHICLIB_VERSION_PATCH)
dnl
dnl This directive is deprecated by someone, but I prefer to avoid
dnl running autotools if not required explicitly. The reason is
dnl the need to be in sync with autoconf/automake.
dnl
AM_MAINTAINER_MODE
AC_CONFIG_HEADERS(include/GeographicLib/Config-ac.h)
dnl Library code modified: REVISION++
dnl Interfaces changed/added/removed: CURRENT++ REVISION=0
dnl Interfaces added: AGE++
dnl Interfaces removed: AGE=0
LT_CURRENT=24
LT_REVISION=0
LT_AGE=1
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
AC_SUBST(LT_AGE)
AC_ARG_PROGRAM
AC_PROG_CPP
AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX_11([noext],[mandatory])
AC_PROG_LIBTOOL
AC_LANG([C++])
# Checks for long double
AC_TYPE_LONG_DOUBLE
# Check endianness
AC_C_BIGENDIAN
# Check flag for accurate arithmetic with Intel compiler. This is
# needed to stop the compiler from ignoring parentheses in expressions
# like (a + b) + c and from simplifying 0.0 + x to x (which is wrong if
# x = -0.0).
AX_CHECK_COMPILE_FLAG([-fp-model precise -diag-disable=11074,11076],
[CXXFLAGS="$CXXFLAGS -fp-model precise -diag-disable=11074,11076"],,
[-Werror])
# Check for doxygen. Version 1.8.7 or later needed for &hellip;
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AM_CONDITIONAL([HAVE_DOXYGEN],
[test "$DOXYGEN" && test `"$DOXYGEN" --version |
sed 's/\b\([[0-9]]\)\b/0\1/g'` '>' 01.08.06.99])
dnl
dnl Add here new file to be generated
dnl
AC_CONFIG_FILES([
Makefile
src/Makefile
include/Makefile
tools/Makefile
doc/Makefile
man/Makefile
cmake/Makefile
examples/Makefile
tests/Makefile
])
PKG_PROG_PKG_CONFIG
PKG_INSTALLDIR
AC_CONFIG_FILES([cmake/geographiclib.pc:cmake/project.pc.in])
AC_OUTPUT

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
# Build the test programs...
# Use fftw for AreaEst? Because CMake support for installed fftw
# package is broken, using FFTW required building local copies of the
# library (a separate cmake configure and build for each precision). So
# default to not using fftw and fall back on kissfftw. For these
# reasons + the overall complexity of adding a dependency to
# GeographicLib, the DST class uses kissfft (despite it being somewhat
# slower that fftw).
set (USE_FFTW OFF)
if (USE_FFTW)
if (GEOGRAPHICLIB_PRECISION EQUAL 1)
set (FFTW_PACKAGE FFTW3f)
elseif (GEOGRAPHICLIB_PRECISION EQUAL 2)
set (FFTW_PACKAGE FFTW3)
elseif (GEOGRAPHICLIB_PRECISION EQUAL 3)
set (FFTW_PACKAGE FFTW3l)
elseif (GEOGRAPHICLIB_PRECISION EQUAL 4)
set (FFTW_PACKAGE FFTW3q)
else () # GEOGRAPHICLIB_PRECISION EQUAL 5
set (FFTW_PACKAGE OFF)
endif ()
if (FFTW_PACKAGE)
find_package (${FFTW_PACKAGE})
if (${FFTW_PACKAGE}_FOUND)
set (FFTW_FOUND ON)
set (FFTW_LIBRARIES ${${FFTW_PACKAGE}_LIBRARIES})
set (FFTW_LIBRARY_DIRS ${${FFTW_PACKAGE}_LIBRARY_DIRS})
set (FFTW_INCLUDE_DIRS ${${FFTW_PACKAGE}_INCLUDE_DIRS})
endif ()
endif ()
endif ()
set (DEVELPROGRAMS
ProjTest TMTest GeodTest ConicTest NaNTester HarmTest EllipticTest intersect
ClosestApproach M12zero GeodShort NormalTest)
if (Boost_FOUND AND NOT GEOGRAPHICLIB_PRECISION EQUAL 4)
# Skip LevelEllipsoid for quad precision because of compiler errors
# with boost 1.69 and g++ 9.2.1 (Fedora 30). Problem reported as
# https://github.com/boostorg/odeint/issues/40
set (DEVELPROGRAMS ${DEVELPROGRAMS} LevelEllipsoid)
include_directories ("${Boost_INCLUDE_DIRS}")
if (APPLE)
# Suppress warnings from Boost library
# warnings with Mac OS X and boost 1.63
# no warnings with Linux and boost 1.60
set (CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-unused-variable -Wno-unused-local-typedef")
endif ()
endif ()
# Loop over all the tools, specifying the source and library.
add_custom_target (develprograms)
foreach (DEVELPROGRAM ${DEVELPROGRAMS})
add_executable (${DEVELPROGRAM} EXCLUDE_FROM_ALL ${DEVELPROGRAM}.cpp)
add_dependencies (develprograms ${DEVELPROGRAM})
target_link_libraries (${DEVELPROGRAM} ${PROJECT_LIBRARIES}
${HIGHPREC_LIBRARIES})
endforeach ()
add_executable (GeodExact EXCLUDE_FROM_ALL GeodExact.cpp
Geodesic30.cpp GeodesicLine30.cpp
Geodesic30.hpp GeodesicLine30.hpp)
add_dependencies (develprograms GeodExact)
target_link_libraries (GeodExact ${PROJECT_LIBRARIES} ${HIGHPREC_LIBRARIES})
set (DEVELPROGRAMS ${DEVELPROGRAMS} GeodExact)
add_executable (AreaEst EXCLUDE_FROM_ALL AreaEst.cpp)
add_dependencies (develprograms AreaEst)
target_link_libraries (AreaEst ${PROJECT_LIBRARIES} ${FFTW_LIBRARIES}
${HIGHPREC_LIBRARIES})
if (FFTW_FOUND)
target_compile_definitions (AreaEst PUBLIC HAVE_FFTW=1)
target_include_directories (AreaEst PUBLIC ${FFTW_INCLUDE_DIRS})
endif ()
set (DEVELPROGRAMS ${DEVELPROGRAMS} AreaEst)
add_executable (reformat EXCLUDE_FROM_ALL reformat.cpp)
add_dependencies (develprograms reformat)
set (DEVELPROGRAMS ${DEVELPROGRAMS} reformat)
if (MSVC OR CMAKE_CONFIGURATION_TYPES)
# Add _d suffix for your debug versions of the tools
set_target_properties (${DEVELPROGRAMS} PROPERTIES
DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
endif ()
# Put all the programs into a folder in the IDE
set_property (TARGET develprograms ${DEVELPROGRAMS} PROPERTY FOLDER develop)
# Don't install develop programs

View File

@@ -0,0 +1,152 @@
// Determine time and position of closest approach for two vessels traveling
// along geodesics. Thanks to
// Jorge D. Taramona
// Inspector de Navegación Aérea
// Dirección General de Aviación Civil del Perú
// for suggesting this problem. See discussion entry from 2014-08-19:
// https://sourceforge.net/p/geographiclib/discussion/1026620/thread/33ce09e0/
// Compile with
// g++ -O3 -std=c++11 -o ClosestApproach ClosestApproach.cpp -lGeographic -L/usr/local/lib -Wl,-rpath=/usr/local/lib
// Example: Planes leave
// (1) Istanbul 42N 29E bearing 51W traveling at 900 km/hr
// (2) Reyjkavik 64N 22W bearing 154E traveling at 800 km/hr
// at the same time; compute time of closest approach. Guess that the time of
// closest approach is after 1 hr. So run
// echo 42 29 -51 900e3 64 -22 154 800e3 1 | ./ClosestApproach
// 0 1 2696504 -3.532249e+12 46.74926 19.83775 57.4055 -16.17089
// 1 2.751696 1083726 6.786464e+10 52.80517 -0.05892146 45.43817 -9.817806
// 2 2.71894 1082700 -2657490 52.72565 0.3576737 45.66487 -9.90999
// 3 2.718941 1082700 -0.005293798 52.72565 0.3576574 45.66486 -9.909987
// 4 2.718941 1082700 0 52.72565 0.3576574 45.66486 -9.909987
// 5 2.718941 1082700 0 52.72565 0.3576574 45.66486 -9.909987
// 6 2.718941 1082700 0 52.72565 0.3576574 45.66486 -9.909987
// 7 2.718941 1082700 0 52.72565 0.3576574 45.66486 -9.909987
// 8 2.718941 1082700 0 52.72565 0.3576574 45.66486 -9.909987
// 9 2.718941 1082700 0 52.72565 0.3576574 45.66486 -9.909987
// At closest approach
// time = 2.72 hr
// dist = 1083 km
// position of first plane = 52.7N 0.3E
// position of second plane = 45.7N 9.9W
// CAVEAT: if the initial guess is bad, this program may return the time at
// which the distance is a maximum.
// Explanation:
// Consider f(t) = s12^2 / 2
// Find zeros of g(t) = f'(t) = s12' * s12 by Newton's method
// using g'(t) = (s12')^2 + s12'' * s12
// Using s12^2 / 2 as the governing function (as opposed, for example, to
// |s12|) means that in the planar limit f(t) is a quadratic function and g(t)
// is a linear function. So Newton's method just needs a single iteration.
// Let gam{1,2} be angle between s12 and v{1,2}.
// s12' = v2 * cos(gam2) - v1 * cos(gam1)
// g(t) = s12 * (v2 * cos(gam2) - v1 * cos(gam1))
// s12'' = - v2*sin(gam2) * dgam2/dt + v1*sin(gam1) * dgam1/dt
// dgam1/dt = (+ M12*v1*sin(gam1) - v2*sin(gam2)) / m12
// dgam2/dt = (- M21*v2*sin(gam2) + v1*sin(gam1)) / m12
// s12'' = (M12*v1^2*sin(gam1)^2 + M21*v2^2*sin(gam2)^2
// - 2*v1*v2*sin(gam1)*sin(gam2)) / m12
// g'(t) = v1^2 * (cos(gam1)^2 + M12*s12/m12 * sin(gam1)^2)
// + v2^2 * (cos(gam2)^2 + M21*s12/m12 * sin(gam2)^2)
// - 2*v1*v2 * (cos(gam1)*cos(gam2) + s12/m12 * sin(gam1)*sin(gam2))
// Planar limit (m12 = s12, M12 = M21 = 1):
// g(t) = (v2-v1) . (r2-r1)
// g'(t) = v1^2 + v2^2 - 2*v1*v2 * cos(gam1-gam2)
// = |v1-v2|^2 = const
// Special case when v2 = 0 (simple interception), v1 = 1
// s12' = - cos(gam1)
// g(t) = - s12 * cos(gam1)
// s12'' = sin(gam1) * dgam1/dt
// dgam1/dt = M12*sin(gam1) / m12
// s12'' = M12*sin(gam1)^2 / m12
// g'(t) = (cos(gam1)^2 + M12*s12/m12 * sin(gam1)^2)
// Planar limit (m12 = s12, M12 = M21 = 1):
// g(t) = -v1 . (r2-r1)
// g'(t) = 1 = const
#include <iostream>
#include <iomanip>
#include <cmath>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/GeodesicExact.hpp>
#include <GeographicLib/Utility.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
typedef Math::real real;
Utility::set_digits();
const Geodesic/*Exact*/ g = Geodesic/*Exact*/(Constants::WGS84_a(),
Constants::WGS84_f());
real lat1, lon1, azi1, v1;
real lat2, lon2, azi2, v2;
real t0;
cout << setprecision(7);
while (cin
>> lat1 >> lon1 >> azi1 >> v1
>> lat2 >> lon2 >> azi2 >> v2
>> t0) {
real t = t0;
for (int i = 0; i < 10; ++i) {
// Compute positions at time t
real lat1a, lon1a, azi1a;
real lat2a, lon2a, azi2a;
g.Direct(lat1, lon1, azi1, t*v1, lat1a, lon1a, azi1a);
g.Direct(lat2, lon2, azi2, t*v2, lat2a, lon2a, azi2a);
// Compute distance at time t
real s12, azi1c, azi2c, m12, M12, M21;
g.Inverse(lat1a, lon1a, lat2a, lon2a,
s12, azi1c, azi2c, m12, M12, M21);
real
r12 = s12 / m12,
gam1 = (azi1c - azi1a) * Math::degree(),
gam2 = (azi2c - azi2a) * Math::degree(),
x1 = v1 * cos(gam1), y1 = v1 * sin(gam1),
x2 = v2 * cos(gam2), y2 = v2 * sin(gam2);
// Find g = 0 using Newton's method where
// g = d( (1/2)*s12^2 ) / dt = s12 * d(s12)/dt
real g = s12 * (x2 - x1);
real dg = // dg = dg/dt
(Math::sq(x1) + M12 * r12 * Math::sq(y1)) +
(Math::sq(x2) + M21 * r12 * Math::sq(y2)) -
2 * (x1 * x2 + r12 * y1 * y2);
cout << i << " "
<< fixed << setprecision(12) << t << " " << s12 << " "
<< defaultfloat << setprecision(6) << g << " "
<< fixed << setprecision(20)
<< lat1a << " " << lon1a << " "
<< fixed << setprecision(6)
<< lat2a << " " << lon2a << "\n";
t -= g/dg; // Newton iteration
}
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
cerr << "Caught unknown exception\n";
return 1;
}
return 0;
}

View File

@@ -0,0 +1,273 @@
/**
* \file ConicTest.cpp
* \brief Command line utility for testing transverse Mercator projections
*
* Copyright (c) Charles Karney (2008-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#include "GeographicLib/LambertConformalConic.hpp"
#include "GeographicLib/AlbersEqualArea.hpp"
#include "GeographicLib/Constants.hpp"
#include "GeographicLib/Geodesic.hpp"
#include "GeographicLib/DMS.hpp"
#include <string>
#include <limits>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <stdexcept>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (disable: 4127)
#endif
GeographicLib::Math::real
dist(GeographicLib::Math::real a, GeographicLib::Math::real f,
GeographicLib::Math::real lat0, GeographicLib::Math::real lon0,
GeographicLib::Math::real lat1, GeographicLib::Math::real lon1) {
using namespace GeographicLib;
typedef Math::real real;
using std::cos; using std::sin; using std::sqrt; using std::hypot;
real
phi = lat0 * Math::degree(),
e2 = f * (2 - f),
sinphi = sin(phi),
n = 1/sqrt(1 - e2 * sinphi * sinphi),
// See Wikipedia article on latitude
hlon = cos(phi) * n,
hlat = (1 - e2) * n * n * n,
dlon = lon1 - lon0;
if (dlon >= 180) dlon -= 360;
else if (dlon < -180) dlon += 360;
return a * Math::degree() *
hypot((lat1 - lat0) * hlat, dlon * hlon);
}
class TestData {
// Read test data with one line of buffering
public:
typedef GeographicLib::Math::real real;
private:
std::istream& _is;
bool _usesaved; // Should GetNext use saved values?
bool _valid; // Are there saved values?
real _lat0, _lat, _lon, _x, _y, _k;
TestData& operator=(const TestData&);
public:
TestData(std::istream& is) : _is(is), _usesaved(false), _valid(false) {}
bool GetNext(real& lat0, real& lat, real& lon,
real& x, real& y, real& k) {
if (_usesaved)
_usesaved = false;
else {
// Avoid a warning about void* changed to bool
_valid = (_is >> _lat0 >> _lat >> _lon >> _x >> _y >> _k) ? true : false;
if (!_valid)
return false;
}
lat0 = _lat0; lat = _lat; lon = _lon; x = _x; y = _y; k = _k;
return true;
}
bool BackUp() {
if (!_valid || _usesaved)
return false; // Can't backup up again
else {
_usesaved = true; // Set flag for GetNext
return true;
}
}
};
int usage(int retval) {
( retval ? std::cerr : std::cout ) <<
"ConicTest -l -s\n\
\n\
Checks conic projections\n";
return retval;
}
int main(int argc, char* argv[]) {
using namespace GeographicLib;
using namespace std;
typedef Math::real real;
bool lambert = true;
bool albers = false;
bool checkstdlats = false;
real a = Constants::WGS84_a(), f = Constants::WGS84_f();
for (int m = 1; m < argc; ++m) {
string arg(argv[m]);
if (arg == "-l") {
lambert = true;
albers = false;
} else if (arg == "-a") {
lambert = false;
albers = true;
} else if (arg == "-s") {
checkstdlats = true;
} else if (arg == "-e") {
if (m + 2 >= argc) return usage(1);
try {
a = Utility::val<real>(string(argv[m + 1]));
f = Utility::fract<real>(string(argv[m + 2]));
}
catch (const exception& e) {
cerr << "Error decoding arguments of -e: " << e.what() << "\n";
return 1;
}
m += 2;
if (f > 1) f = 1/f;
} else
return usage(arg != "-h");
}
try {
if (checkstdlats) { // stdin contains lat1 lat2 lat0 k0
cout << setprecision(17);
real quant = real(1e12);
while (true) {
real lat1, lat2, lat0, k0;
if (!(cin >> lat1 >> lat2 >> lat0 >> k0))
break;
int
sign1 = lat1 < 0 ? -1 : 1,
sign2 = lat2 < 0 ? -1 : 1;
lat1 = real(floor(sign1 * lat1 * quant + 0.5L));
lat2 = real(floor(sign2 * lat2 * quant + 0.5L));
real
colat1 = (90 * quant - lat1) / quant,
colat2 = (90 * quant - lat2) / quant;
lat1 /= quant;
lat2 /= quant;
real
sinlat1 = sign1 * (lat1 < 45 ? sin(lat1 * Math::degree())
: cos(colat1 * Math::degree())),
sinlat2 = sign2 * (lat2 < 45 ? sin(lat2 * Math::degree())
: cos(colat2 * Math::degree())),
coslat1 = (lat1 < 45 ? cos(lat1 * Math::degree())
: sin(colat1 * Math::degree())),
coslat2 = (lat2 < 45 ? cos(lat2 * Math::degree())
: sin(colat2 * Math::degree()));
lat1 *= sign1;
lat2 *= sign2;
const LambertConformalConic lam(a, f, /* real(lat1), real(lat2), */
real(sinlat1), real(coslat1),
real(sinlat2), real(coslat2),
real(1));
const AlbersEqualArea alb(a, f, /* real(lat1), real(lat2), */
real(sinlat1), real(coslat1),
real(sinlat2), real(coslat2),
real(1));
real
lat0a = albers ? alb.OriginLatitude() : lam.OriginLatitude();
//k0a = albers ? alb.CentralScale() : lam.CentralScale();
if (!(abs(lat0a-lat0) <= 4.5e-14))
cout << lat1 << " " << lat2 << " " << lat0
<< " " << lat0a << " " << lat0a - lat0 << "\n";
}
} else { // Check projection
// stdin contains lat0 lat lon x y k
TestData testset(cin);
cout << setprecision(8);
while (true) {
real lat0, lat, lon, x, y, k;
if (!testset.GetNext(lat0, lat, lon, x, y, k))
break;
if (!testset.BackUp())
break;
int
sign0 = lat0 < 0 ? -1 : 1;
real quant = real(1e12);
real
lat00 = real(floor(sign0 * lat0 * quant + 0.5L)),
colat00 = (90 * quant - lat00) / quant;
lat00 /= quant;
real
sinlat0 = real(sign0 * (lat00 < 45 ?
sin(lat00 * Math::degree()) :
cos(colat00 * Math::degree()))),
coslat0 = real(lat00 < 45 ? cos(lat00 * Math::degree())
: sin(colat00 * Math::degree()));
const LambertConformalConic lcc(a, f,
sinlat0, coslat0, sinlat0, coslat0,
real(1));
const AlbersEqualArea alb(a, f,
sinlat0, coslat0, sinlat0, coslat0,
real(1));
real maxerrf = 0, maxerrr = 0, maxerrkf = 0, maxerrkr = 0;
real latf = 0, lonf = 0, latr = 0, lonr = 0,
latkf = 0, lonkf = 0, latkr = 0, lonkr = 0;
// cout << "New lat0: " << lat0 << "\n";
while (true) {
real lat0x;
if (!testset.GetNext(lat0x, lat, lon, x, y, k))
break;
if (lat0 != lat0x) {
testset.BackUp();
break;
}
real latb, lonb, xa, ya, gammaa, gammab, ka, kb;
if (albers)
alb.Forward(real(0), real(lat), real(lon), xa, ya, gammaa, ka);
else
lcc.Forward(real(0), real(lat), real(lon), xa, ya, gammaa, ka);
real errf = real(hypot(real(xa) - x, real(ya) - y));
if (lambert)
errf /= real(k);
real errkf = real(abs(real(ka) - k)/k);
if (albers)
alb.Reverse(real(0), real(x), real(y), latb, lonb, gammab, kb);
else
lcc.Reverse(real(0), real(x), real(y), latb, lonb, gammab, kb);
real errr = real(dist(real(a), real(f),
lat, lon, real(latb), real(lonb)));
/*
cout << latb << " " << lonb << " " << xa << " " << ya << " "
<< ka << " " << kb << " "
<< gammaa << " " << gammab << "\n";
*/
real errkr = real(abs(real(kb) - k)/k);
if (!(errf <= maxerrf)) {
maxerrf = errf;
latf = real(lat);
lonf = real(lon);
}
if (!(errr <= maxerrr)) {
maxerrr = errr;
latr = real(lat);
lonr = real(lon);
}
if (!(errkf <= maxerrkf || abs(lat) >= 89)) {
maxerrkf = errkf;
latkf = real(lat);
lonkf = real(lon);
}
if (!(errkr <= maxerrkr || abs(lat) >= 89)) {
maxerrkr = errkr;
latkr = real(lat);
lonkr = real(lon);
}
cout << lat0 << " " << lat << " " << lon << " "
<< errf << " " << errr << " "
<< errkf << " " << errkr << "\n";
}
cout << "Max errf: " << lat0 << " "
<< maxerrf << " " << latf << " " << lonf << "\n";
cout << "Max errr: " << lat0 << " "
<< maxerrr << " " << latr << " " << lonr << "\n";
cout << "Max errkf: " << lat0 << " "
<< maxerrkf << " " << latkf << " " << lonkf << "\n";
cout << "Max errkr: " << lat0 << " "
<< maxerrkr << " " << latkr << " " << lonkr << "\n";
}
}
}
catch (const exception& e) {
cout << "ERROR: " << e.what() << "\n";
return 1;
}
return 0;
}

View File

@@ -0,0 +1,163 @@
#include <iostream>
#include <iomanip>
#include <GeographicLib/EllipticFunction.hpp>
#include <GeographicLib/Ellipsoid.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (disable: 4127)
#endif
using namespace GeographicLib;
using namespace std;
int main() {
typedef GeographicLib::Math::real real;
try {
if (true) {
for (int i = -7; i <= 7; ++i) {
if (i == 0)
continue;
real a = 1, b = a * real(pow(real(2), i)), f = (a-b)/a;
Ellipsoid e(a, f);
real m = e.QuarterMeridian();
real na = a * real(1e7)/m, nb = na * (1-f);
Ellipsoid ne(na, f);
cout << b/a << " " << na << " " << nb << " "
<< ne.QuarterMeridian() << "\n";
}
for (int i = -1; i <= 1; ++i) {
if (i == 0)
continue;
real a = 1, b = a * real(pow(real(3), i)), f = (a-b)/a;
Ellipsoid e(a, f);
real m = e.QuarterMeridian();
real na = a * real(1e7)/m, nb = na * (1-f);
Ellipsoid ne(na, f);
cout << b/a << " " << na << " " << nb << " "
<< ne.QuarterMeridian() << "\n";
}
return 0;
}
if (false) {
// Longitude check
real a = real(1.5), b = 1, f = (a - b)/a,
e2 = (a*a - b*b)/(a*a), ep2 = (a*a - b*b)/(b*b),
alp0 = real(0.85), calp0 = cos(alp0), salp0 = sin(alp0),
k2 = ep2 * Math::sq(calp0), kp2 = k2/(1 + k2),
sigma = real(1.2), theta = atan(sqrt(1+k2) * tan(sigma)),
kap2 = Math::sq(calp0)/(1-Math::sq(salp0)*e2),
omg = atan(salp0 * tan(sigma)),
ups = atan(sqrt((1+ep2)/(1+k2*Math::sq(sin(sigma)))) * tan(omg)),
// psi = atan(sqrt((1+k2*Math::sq(sin(sigma)))/(1+ep2)) * tan(omg)),
psi = atan(sqrt((1-e2)/(1+k2*Math::sq(cos(theta)))) *
salp0*tan(theta));
EllipticFunction ella1(-k2, Math::sq(calp0));
EllipticFunction ella2(-k2, -ep2);
EllipticFunction ellb1(kp2, kap2);
EllipticFunction ellb2(kp2, e2);
EllipticFunction ellc(kp2, kp2);
cout << setprecision(15);
cout << (1 - f) * salp0 * ella1.G(sigma) << " "
<< ups - ep2/sqrt(1+ep2) * salp0 * ella2.H(sigma) << " "
<< (1-f) * sqrt(1-kp2) * salp0 * ellb1.Pi(theta) << " "
<< psi + (1-f) * sqrt(1-kp2) * salp0 *
(ellb2.F(theta) - ellb2.Pi(theta)) << "\n";
cout << b*ella1.E(sigma) << " "
<< b * sqrt(1-kp2) * ellc.Pi(theta) << " "
<< b / sqrt(1-kp2) *
(ellc.E(theta) - kp2 * cos(theta) * sin(theta)/
sqrt(1 - kp2*Math::sq(sin(theta)))) << "\n";
return 0;
}
if (false) {
real b = 1, a = 10,
e2 = (a*a - b*b)/(a*a), ep2 = (a*a - b*b)/(b*b);
EllipticFunction elle(e2, e2);
EllipticFunction ellep(-ep2, -ep2);
cout << fixed << setprecision(8);
for (int i = 0; i <= 90; i += 5) {
real
beta = i * Math::degree(),
phi = atan(sqrt(1 + ep2) * tan(beta)),
u = elle.F(phi),
y = b * ellep.E(beta),
M = a*elle.E();
cout << (y / M) * 90 << " "
<< i << " "
<< phi / Math::degree() << " "
<< (u / elle.K()) * 90 << "\n";
}
/* Create plot with
t=load('data.txt');
plot(t(:,1),t(:,1),'-k',...
t(:,1),t(:,2),'-kx',...
t(:,1),t(:,4),'-ko',...
t(:,1),t(:,3),'-k+')
axis equal;axis([0,90,0,90]);
title('meridian measures for a/b = 10');
xlabel('meridian distance (\circ)');
ylabel('measure (\circ)');
legend('distance',...
'parametric latitude',...
'elliptic variable',...
'geographic latitude',...
'Location','SouthEast');
set(gcf,'PaperSize',[4.5,4.5]);
set(gcf,'PaperPosition',[0,0,4.5,4.5]);
print meridian-measures.png -dpng
*/
return 0;
}
if (false) {
real alpha2 = real(0.8), k2 = real(-0.4);
EllipticFunction ellG(k2,alpha2);
EllipticFunction ellH(k2,k2/alpha2);
cout << setprecision(10);
for (int i = -179; i <= 180; i += 10) {
real
phi = i * Math::degree(),
sn = sin(phi), cn = cos(phi), dn = ellG.Delta(sn, cn),
g = ellG.G(phi),
h = (k2/alpha2)*ellH.H(phi) + sqrt(1-k2/alpha2)/sqrt(1-alpha2)*
atan2(sqrt(1-alpha2)*sqrt(1-k2/alpha2)*sn, dn*cn);
cout << i << " " << g << " " << h << " " << h-g << "\n";
}
return 0;
}
if (false) {
// For tabulated values in A+S
real
ASalpha = 30*Math::degree<real>(),
k2 = Math::sq(sin(ASalpha)),
alpha2 = real(0.3);
EllipticFunction ell(k2, alpha2);
real dphi = Math::degree();
cout << fixed << setprecision(10);
for (int i = 0; i <= 90; i += 15) {
real phi = i * dphi;
cout << i << " "
<< ell.F(phi) << " "
<< ell.E(phi) << " "
<< ell.D(phi) << " "
<< ell.Pi(phi) << " "
<< ell.G(phi) << " "
<< ell.H(phi) << "\n";
}
return 0;
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
cerr << "Caught unknown exception\n";
return 1;
}
return 0;
}

View File

@@ -0,0 +1,34 @@
#include <iostream>
#include "Geodesic30.hpp"
int main() {
{
GeographicLib::Geodesic30<double> g(6.4e6, 0.01);
{
double lat2, lon2, azi2;
g.Direct(10, 30, 20, 1e6, lat2, lon2, azi2);
std::cout << lat2 << " " << lon2 << " " << azi2 << "\n";
}
{
double s12, azi1, azi2;
g.Inverse(-20, 0, 10, 70, s12, azi1, azi2);
std::cout << s12 << " " << azi1 << " " << azi2 << "\n";
}
}
/*
{
GeographicLib::Geodesic30<long double> g(6.4e6L, 0.01L);
{
long double lat2, lon2, azi2;
g.Direct(10, 30, 20, 1e6L, lat2, lon2, azi2);
std::cout << lat2 << " " << lon2 << " " << azi2 << "\n";
}
{
long double s12, azi1, azi2;
g.Inverse(-20, 0, 10, 70, s12, azi1, azi2);
std::cout << s12 << " " << azi1 << " " << azi2 << "\n";
}
}
*/
return 0;
}

View File

@@ -0,0 +1,337 @@
/**
* \file GeodShort.cpp
*
* Test various solutions to the inverse problem in the limit of short lines
* (following Bowring 1981).
**********************************************************************/
#include <ctime> // for std::time
#include <functional> // for std::function and std::bind
#include <random> // for C++11 random numbers
#include <limits> // for digits
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/GeodesicExact.hpp>
#include <GeographicLib/Utility.hpp>
#include <GeographicLib/EllipticFunction.hpp>
using namespace GeographicLib;
using namespace std;
class GeodShort {
private:
typedef Math::real real;
real _a, _f, _f1, _b, _e2, _ep2, _e;
EllipticFunction _E;
inline real eatanhe(real x) const {
return _f >= 0 ? _e * atanh(_e * x) : - _e * atan(_e * x);
}
static inline real psi0f(real phi) { return asinh(tan(phi)); }
static inline real invpsi0f(real psi) { return atan(sinh(psi)); }
inline real psif(real phi) { return psi0f(phi) - eatanhe(sin(phi)); }
static inline void SinCosNorm(real& sinx, real& cosx) {
real r = hypot(sinx, cosx);
sinx /= r;
cosx /= r;
}
static real GreatCircle(real sbet1, real cbet1,
real sbet2, real cbet2,
real omg12, real& azi1, real& azi2) {
real
// bet12 = bet2 - bet1 in [0, pi)
sbet12 = sbet2 * cbet1 - cbet2 * sbet1,
sbet12a = sbet2 * cbet1 + cbet2 * sbet1,
somg12 = sin(omg12), comg12 = cos(omg12);
real
salp1 = cbet2 * somg12,
calp1 = (comg12 >= 0 ?
sbet12 + cbet2 * sbet1 * Math::sq(somg12) / (1 + comg12) :
sbet12a - cbet2 * sbet1 * Math::sq(somg12) / (1 - comg12));
real
ssig12 = hypot(salp1, calp1),
csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12;
real
salp2 = cbet1 * somg12,
calp2 = sbet12 - cbet1 * sbet2 * Math::sq(somg12) / (1 + comg12),
sig12 = atan2(ssig12, csig12);
azi1 = atan2(salp1, calp1) / Math::degree();
azi2 = atan2(salp2, calp2) / Math::degree();
return sig12;
}
public:
GeodShort(real a, real f)
: _a(a)
, _f(f)
, _f1(1 - _f)
, _b(_a * _f1)
, _e2(_f * (2 - _f))
, _ep2(_e2/Math::sq(_f1))
, _e(sqrt(abs(_e2)))
, _E(-_ep2) {}
real Inverse(real lat1, real lon1, real lat2, real lon2,
real& azi1, real& azi2) {
int mode = 1;
real
phi1 = Math::degree() * lat1,
phi2 = Math::degree() * lat2,
lam12 = Math::degree() * Math::AngNormalize(lon2 - lon1),
sbet1 = _f1 * sin(phi1), cbet1 = cos(phi1),
sbet2 = _f1 * sin(phi2), cbet2 = cos(phi2);
SinCosNorm(sbet1, cbet1); SinCosNorm(sbet2, cbet2);
real
dn1 = sqrt(1 + _ep2 * Math::sq(sbet1)),
dn2 = sqrt(1 + _ep2 * Math::sq(sbet2)),
dnm;
if (mode == 0)
dnm = (dn1 + dn2) / 2;
else {
real sbetm2 = Math::sq(sbet1 + sbet2);
sbetm2 = sbetm2 / (sbetm2 + Math::sq(cbet1 + cbet2));
dnm = sqrt(1 + _ep2 * sbetm2);
}
return _b * dnm * GreatCircle(sbet1, cbet1, sbet2, cbet2,
lam12 / (_f1 * dnm),
azi1, azi2);
}
real Inverse2(real lat1, real lon1, real lat2, real lon2,
real& azi1, real& azi2) {
real
phi1 = Math::degree() * lat1,
phi2 = Math::degree() * lat2,
lam12 = Math::degree() * Math::AngNormalize(lon2 - lon1),
sbet1 = _f1 * sin(phi1), cbet1 = cos(phi1),
sbet2 = _f1 * sin(phi2), cbet2 = cos(phi2);
SinCosNorm(sbet1, cbet1); SinCosNorm(sbet2, cbet2);
real dnm;
real sbetm2 = Math::sq(sbet1 + sbet2);
sbetm2 = sbetm2 / (sbetm2 + Math::sq(cbet1 + cbet2));
dnm = sqrt(1 + _ep2 * sbetm2);
// Adjust bet1 and bet2 via conformal map
real
A = 1/(dnm * _f1),
phim = atan((sbet1+sbet2)/(_f1*(cbet1+cbet2))),
betm = atan((sbet1+sbet2)/(cbet1+cbet2)),
psim = psif(phim),
psipm = psi0f(betm),
K = psipm - A * psim,
bet1 = invpsi0f( A*psif(phi1) + K ),
bet2 = invpsi0f( A*psif(phi2) + K );
sbet1 = sin(bet1); cbet1 = cos(bet1);
sbet2 = sin(bet2); cbet2 = cos(bet2);
return _b * dnm * GreatCircle(sbet1, cbet1, sbet2, cbet2,
lam12 / (_f1 * dnm),
azi1, azi2);
}
real Bowring0(real lat1, real lon1, real lat2, real lon2,
real& azi1, real& azi2) {
int mode = 2;
real
phi1 = Math::degree() * lat1,
phi2 = Math::degree() * lat2,
lam12 = Math::degree() * Math::AngNormalize(lon2 - lon1),
m = 0.5,
phim = ( abs(phi1) >= abs(phi2) ?
(1 - m) * phi1 + m * phi2 :
(1 - m) * phi2 + m * phi1 ),
dphi1 = phi1 - phim,
dphi2 = phi2 - phim,
cosm = cos(phim),
sinm = sin(phim),
A = sqrt(1 + _ep2 * Math::sq(Math::sq(cosm))),
B = sqrt(1 + _ep2 * Math::sq(cosm)),
C = sqrt(1 + _ep2),
omg12 = A * lam12,
phipm = atan(tan(phim)/B),
R = _a * C/(B*B),
phip1, phip2;
if (mode == 0) {
phip1 = phipm + (dphi1/B) * (1 + (3*_ep2*dphi1)/(4*B*B) *
sin(2 * (phim + dphi1/3)));
phip2 = phipm + (dphi2/B) * (1 + (3*_ep2*dphi2)/(4*B*B) *
sin(2 * (phim + dphi2/3)));
} else if (mode == 1) {
real
psi1 = psif(phi1), psi2 = psif(phi2),
psim = psif(phim), psipm = psi0f(phipm);
phip1 = invpsi0f(A * (psi1-psim) + psipm);
phip2 = invpsi0f(A * (psi2-psim) + psipm);
} else {
phip1 = phipm + (dphi1/B) *
( 1 + _ep2*dphi1/(2*B*B) *
(3*cosm*sinm + dphi1*(1-2*sinm*sinm +
_ep2 * (cosm*cosm * (1 + 3*sinm*sinm)))/B*B));
phip2 = phipm + (dphi2/B) *
( 1 + _ep2*dphi2/(2*B*B) *
(3*cosm*sinm + dphi2*(1-2*sinm*sinm +
_ep2 * (cosm*cosm * (1 + 3*sinm*sinm)))/B*B));
}
return R * GreatCircle(sin(phip1), cos(phip1), sin(phip2), cos(phip2),
omg12, azi1, azi2);
}
real Bowring1(real lat1, real lon1, real lat2, real lon2,
real& azi1, real& azi2) {
real
phi1 = Math::degree() * lat1,
phi2 = Math::degree() * lat2,
lam12 = Math::degree() * Math::AngNormalize(lon2 - lon1),
bet1 = atan(_f1 * tan(phi1)),
bet2 = atan(_f1 * tan(phi2)),
betm = (bet1 + bet2)/2,
phim = atan(tan(betm) / _f1),
cosm = cos(phim),
A = sqrt(1 + _ep2 * Math::sq(Math::sq(cosm))),
B = sqrt(1 + _ep2 * Math::sq(cosm)),
C = sqrt(1 + _ep2),
omg12 = A * lam12,
phipm = atan(tan(phim)/B),
R = _a * C/(B*B),
m1 = _E.E(sin(bet1), cos(bet1), sqrt(1 + _ep2 * Math::sq(sin(bet1)))),
m2 = _E.E(sin(bet2), cos(bet2), sqrt(1 + _ep2 * Math::sq(sin(bet2)))),
mm = _E.E(sin(betm), cos(betm), sqrt(1 + _ep2 * Math::sq(sin(betm)))),
phip1 = phipm + (m1 - mm) * _a * _f1 / R,
phip2 = phipm + (m2 - mm) * _a * _f1 / R;
return R * GreatCircle(sin(phip1), cos(phip1), sin(phip2), cos(phip2),
omg12, azi1, azi2);
}
real Bowring2(real lat1, real lon1, real lat2, real lon2,
real& azi1, real& azi2) {
real highfact = 1;
real
phi1 = Math::degree() * lat1,
phi2 = Math::degree() * lat2,
lam12 = Math::degree() * Math::AngNormalize(lon2 - lon1),
bet1 = atan(_f1 * tan(phi1)),
bet2 = atan(_f1 * tan(phi2)),
betm = (bet1 + bet2)/2,
sbetm = sin(betm),
cbetm = cos(betm),
phim = atan(tan(betm) / _f1),
cosm = cos(phim),
A = sqrt(1 + _ep2 * Math::sq(Math::sq(cosm))),
B = sqrt(1 + _ep2 * Math::sq(cosm)),
C = sqrt(1 + _ep2),
omg12 = A * lam12,
phipm = atan(tan(phim)/B),
R = _a * C/(B*B),
dbet1 = bet1-betm,
dbet2 = bet2-betm,
dnm2 = 1+_ep2*Math::sq(sbetm),
dnm = sqrt(dnm2),
phip1 = phipm + dbet1/dnm *
(1 + dbet1 * _ep2/(2*dnm2) *
( cbetm*sbetm + highfact * dbet1 * ( Math::sq(cbetm) -
Math::sq(sbetm)*dnm2)/(3*dnm2) )),
phip2 = phipm + dbet2/dnm *
(1 + dbet2 * _ep2/(2*dnm2) *
( cbetm*sbetm + highfact * dbet2 * ( Math::sq(cbetm) -
Math::sq(sbetm)*dnm2)/(3*dnm2) ));
return R * GreatCircle(sin(phip1), cos(phip1), sin(phip2), cos(phip2),
omg12, azi1, azi2);
}
};
int main(int argc, char* argv[]) {
try {
// Args are f and sig
if (argc != 3) {
cerr << "Usage: GeodShort f sig\n";
return 1;
}
typedef Math::real real;
real
f = Utility::fract<real>(string(argv[1])),
sig = Utility::val<real>(string(argv[2]));
Geodesic g(1, f);
GeodesicExact ge(1, f);
GeodShort s(1, f);
bool exact = abs(f) > 0.02;
real norm, consist;
{
real m;
if (exact)
ge.Inverse(0, 0, 90, 0, m);
else
g.Inverse(0, 0, 90, 0, m);
norm = max(m, Math::pi()/2 * g.EquatorialRadius());
consist = min(m, Math::pi()/2 * g.EquatorialRadius()) /
(Math::pi()/2);
}
unsigned seed = random_device()(); // Set seed from random_device
mt19937 r(seed); // Initialize URNG
uniform_real_distribution<double> U;
cout << norm << " " << consist << " "
<< f << " " << sig << " " << seed << endl;
real maxerr1 = -1, maxerr2 = -1, maxerr3 = -1;
for (unsigned k = 0; k < 10000000; ++k) {
real
lat1 = 90*real(U(r)),
lon1 = 0,
azi1 = 180*real(U(r)),
lat2, lon2, s12, azi2;
if (exact)
ge.ArcDirect(lat1, lon1, azi1, sig, lat2, lon2, azi2, s12);
else
g.ArcDirect(lat1, lon1, azi1, sig, lat2, lon2, azi2, s12);
real
s12a = s.Bowring2(lat1, lon1, lat2, lon2, azi1, azi2),
err1 = abs(s12a - s12) / norm;
if (err1 > maxerr1) {
maxerr1 = err1;
cout << "A " << k << " "
<< lat1 << " " << azi1 << " " << maxerr1 << endl;
}
real lat, lon, azi1a, azi2a;
if (exact)
ge.Direct(lat1, lon1, azi1, s12a, lat, lon);
else
g.Direct(lat1, lon1, azi1, s12a, lat, lon);
real err2 = s.Inverse(lat2, lon2, lat, lon, azi1a, azi2a);
if (exact)
ge.Direct(lat2, lon2, azi2, -s12a, lat, lon);
else
g.Direct(lat2, lon2, azi2, -s12a, lat, lon);
err2 = max(err2, s.Inverse(lat1, lon1, lat, lon, azi1a, azi2a)) / norm;
if (err2 > maxerr2) {
maxerr2 = err2;
cout << "B " << k << " "
<< lat1 << " " << azi1 << " " << maxerr2 << endl;
}
real latx, lonx;
if (exact) {
ge.Direct(lat1, lon1, azi1, s12a + consist, lat, lon);
ge.Direct(lat2, lon2, azi2, consist, latx, lonx);
} else {
g.Direct(lat1, lon1, azi1, s12a + consist, lat, lon);
g.Direct(lat2, lon2, azi2, consist, latx, lonx);
}
real err3 = s.Inverse(lat, lon, latx, lonx, azi1a, azi2a);
if (exact) {
ge.Direct(lat1, lon1, azi1, -consist, lat, lon);
ge.Direct(lat2, lon2, azi2, -s12a - consist, latx, lonx);
} else {
g.Direct(lat1, lon1, azi1, -consist, lat, lon);
g.Direct(lat2, lon2, azi2, -s12a - consist, latx, lonx);
}
err3 = max(err3, s.Inverse(lat, lon, latx, lonx, azi1a, azi2a)) / norm;
if (err3 > maxerr3) {
maxerr3 = err3;
cout << "C " << k << " "
<< lat1 << " " << azi1 << " " << maxerr3 << endl;
}
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
cerr << "Caught unknown exception\n";
return 1;
}
cout << "DONE\n";
return 0;
}

View File

@@ -0,0 +1,498 @@
/**
* \file GeodTest.cpp
**********************************************************************/
#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#include "GeographicLib/Geodesic.hpp"
#include "GeographicLib/GeodesicLine.hpp"
#include "GeographicLib/GeodesicExact.hpp"
#include "GeographicLib/GeodesicLineExact.hpp"
#include "GeographicLib/Constants.hpp"
#include <GeographicLib/Utility.hpp>
#include <cmath>
#include <vector>
#include <utility>
#include <algorithm>
#include <limits>
using namespace std;
using namespace GeographicLib;
int usage(int retval) {
( retval ? cerr : cout ) <<
"GeodTest [ -a | -c | -t0 | -t1 | -t2 | -t3 | -h ]\n\
\n\
Check GeographicLib::Geodesic class.\n\
-a (default) accuracy test (reads test data on standard input)\n\
-E accuracy test with GeodesicExact (reads test data on standard input)\n\
-F accuracy test with GeodesicExact (reads test data on standard input\n\
first line gives a and f)\n\
-c coverage test (reads test data on standard input)\n\
-t0 time GeodecicLine with distances using synthetic data\n\
-t1 time GeodecicLine with angles using synthetic data\n\
-t2 time Geodecic::Direct using synthetic data\n\
-t3 time Geodecic::Inverse with synthetic data\n\
-T0 time GeodecicLineExact with distances using synthetic data\n\
-T1 time GeodecicLineExact with angles using synthetic data\n\
-T2 time GeodecicExact::Direct using synthetic data\n\
-T3 time GeodecicExact::Inverse with synthetic data\n\
\n\
-c requires an instrumented version of Geodesic.\n";
return retval;
}
Math::real angdiff(Math::real a1, Math::real a2) {
Math::real d = a2 - a1;
if (d >= 180)
d -= 360;
else if (d < -180)
d += 360;
return d;
}
Math::real azidiff(Math::real lat,
Math::real lon1, Math::real lon2,
Math::real azi1, Math::real azi2) {
Math::real
phi = lat * Math::degree(),
alpha1 = azi1 * Math::degree(),
alpha2 = azi2 * Math::degree(),
dlam = angdiff(lon1, lon2) * Math::degree();
Math::real res = sin(alpha2-alpha1)*cos(dlam)
-cos(alpha2-alpha1)*sin(dlam)*sin(phi)
// -sin(alpha1)*cos(alpha2)*(1-cos(dlam))*cos(phi)*cos(phi)
;
return res;
}
Math::real dist(Math::real a, Math::real f,
Math::real lat0, Math::real lon0,
Math::real lat1, Math::real lon1) {
// typedef GeographicLib::Math::real real;
// real s12;
// GeographicLib::Geodesic::
// WGS84.Inverse(real(lat0), real(lon0), real(lat1), real(lon1), s12);
// return Math::real(s12);
a *= Math::degree();
if (abs(lat0 + lat1) > Math::real(179.998)) {
// Near pole, transform into polar coordinates
Math::real
r0 = 90 - abs(lat0),
r1 = 90 - abs(lat1),
lam0 = lon0 * Math::degree(),
lam1 = lon1 * Math::degree();
return (a / (1 - f)) *
hypot(r0 * cos(lam0) - r1 * cos(lam1), r0 * sin(lam0) - r1 * sin(lam1));
} else {
// Otherwise use cylindrical formula
Math::real
phi = lat0 * Math::degree(),
cphi = abs(lat0) <= 45 ? cos(phi)
: sin((90 - abs(lat0)) * Math::degree()),
e2 = f * (2 - f),
sinphi = sin(phi),
n = 1/sqrt(1 - e2 * sinphi * sinphi),
// See Wikipedia article on latitude
degreeLon = a * cphi * n,
degreeLat = a * (1 - e2) * n * n * n,
dlon = angdiff(lon1, lon0),
dlat = lat1 - lat0;
dlat *= degreeLat;
dlon *= degreeLon;
return hypot(dlat, dlon);
}
}
// err[0] error in position of point 2 for the direct problem.
// err[1] error in azimuth at point 2 for the direct problem.
// err[2] error in m12 for the direct problem & inverse (except near conjugacy)
// err[3] error in s12 for the inverse problem.
// err[4] error in the azimuths for the inverse problem scaled by m12.
// err[5] consistency of the azimuths for the inverse problem.
// err[6] area error direct & inverse (except near conjugacy)
template<class test>
void GeodError(const test& tgeod,
Math::real lat1, Math::real lon1, Math::real azi1,
Math::real lat2, Math::real lon2, Math::real azi2,
Math::real s12, Math::real /*a12*/,
Math::real m12, Math::real S12,
vector<Math::real>& err) {
Math::real tlat1, tlon1, tazi1, tlat2, tlon2, tazi2, ts12, tm12a, tm12b,
tM12, tM21, tS12a, tS12b /*, ta12*/;
Math::real rlat1, rlon1, razi1, rlat2, rlon2, razi2, rm12;
tgeod.Direct(lat1, lon1, azi1, s12,
tlat2, tlon2, tazi2, tm12a,
tM12, tM21, tS12a);
tS12a -= tgeod.EllipsoidArea() * (tazi2-azi2)/720;
tgeod.Direct(lat2, lon2, azi2, -s12,
tlat1, tlon1, tazi1, tm12b,
tM12, tM21, tS12b);
tS12b -= tgeod.EllipsoidArea() * (tazi1-azi1)/720;
err[0] = max(dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
lat2, lon2, tlat2, tlon2),
dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
lat1, lon1, tlat1, tlon1));
err[1] = max(abs(azidiff(lat2, lon2, tlon2, azi2, tazi2)),
abs(azidiff(lat1, lon1, tlon1, azi1, tazi1))) *
tgeod.EquatorialRadius();
err[2] = max(abs(tm12a - m12), abs(tm12b + m12));
if (!isnan(S12))
err[6] = max(abs(tS12a - S12), abs(tS12b + S12)) / tgeod.EquatorialRadius();
/* ta12 = */ tgeod.Inverse(lat1, lon1, lat2, lon2,
ts12, tazi1, tazi2, tm12a,
tM12, tM21, tS12a);
tS12a -= tgeod.EllipsoidArea() * ((tazi2-azi2)-(tazi1-azi1))/720;
err[3] = abs(ts12 - s12);
err[4] = max(abs(angdiff(azi1, tazi1)), abs(angdiff(azi2, tazi2))) *
Math::degree() * abs(m12);
if (lat1 + lat2 == 0)
err[4] = min(err[4],
max(abs(angdiff(azi1, tazi2)), abs(angdiff(azi2, tazi1))) *
Math::degree() * abs(m12));
// m12 and S12 are very sensitive with the inverse problem near conjugacy
if (!(s12 > tgeod.EquatorialRadius() && m12 < 10e3)) {
err[2] = max(err[2], abs(tm12a - m12));
if (!isnan(S12))
err[6] = max(err[6], abs(tS12a - S12) / tgeod.EquatorialRadius());
}
if (s12 > tgeod.EquatorialRadius()) {
tgeod.Direct(lat1, lon1, tazi1, ts12/2, rlat2, rlon2, razi2, rm12);
tgeod.Direct(lat2, lon2, tazi2, - ts12/2, rlat1, rlon1, razi1, rm12);
err[5] = dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
rlat1, rlon1, rlat2, rlon2);
} else {
tgeod.Direct(lat1, lon1, tazi1,
ts12 + tgeod.EquatorialRadius(),
rlat2, rlon2, razi2, rm12);
tgeod.Direct(lat2, lon2, tazi2, tgeod.EquatorialRadius(),
rlat1, rlon1, razi1, rm12);
err[5] = dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
rlat1, rlon1, rlat2, rlon2);
tgeod.Direct(lat1, lon1, tazi1, - tgeod.EquatorialRadius(),
rlat2, rlon2, razi2, rm12);
tgeod.Direct(lat2, lon2, tazi2,
- ts12 - tgeod.EquatorialRadius(),
rlat1, rlon1, razi1, rm12);
err[5] = max(err[5], dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
rlat1, rlon1, rlat2, rlon2));
}
}
int main(int argc, char* argv[]) {
Utility::set_digits();
Math::real a = Constants::WGS84_a();
Math::real f = Constants::WGS84_f();
bool timing = false;
int timecase = 0; // 0 = line, 1 = line ang, 2 = direct, 3 = inverse
bool accuracytest = true;
bool coverage = false;
bool exact = false;
if (argc == 2) {
string arg = argv[1];
if (arg == "-a") {
accuracytest = true;
coverage = false;
timing = false;
exact = false;
} else if (arg == "-E") {
accuracytest = true;
coverage = false;
timing = false;
exact = true;
} else if (arg == "-F") {
accuracytest = true;
coverage = false;
timing = false;
exact = true;
string s;
getline(cin, s);
istringstream str(s);
str >> a >> f;
} else if (arg == "-c") {
accuracytest = false;
coverage = true;
timing = false;
exact = false;
} else if (arg == "-t0") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 0;
exact = false;
} else if (arg == "-t1") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 1;
exact = false;
} else if (arg == "-t2") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 2;
exact = false;
} else if (arg == "-t3") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 3;
exact = false;
} else if (arg == "-T0") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 0;
exact = true;
} else if (arg == "-T1") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 1;
exact = true;
} else if (arg == "-T2") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 2;
exact = true;
} else if (arg == "-T3") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 3;
exact = true;
} else
return usage(arg == "-h" ? 0 : 1);
} else if (argc > 2)
return usage(1);
if (timing) {
if (!exact) {
const Geodesic& geod = Geodesic::WGS84();
unsigned cnt = 0;
Math::real s = 0;
Math::real dl;
switch (timecase) {
case 0:
// Time Line
dl = 2e7/1000;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
const GeodesicLine l(geod, lat1, 0.0, azi1);
for (int k = 0; k <= 1000; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
l.Position(s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 1:
// Time Line ang
dl = Math::real(180)/1000;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
GeodesicLine l(geod, lat1, 0.0, azi1);
for (int k = 0; k <= 1000; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
l.ArcPosition(s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 2:
// Time Direct
dl = 2e7/200;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
for (int k = 0; k <= 200; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
geod.Direct(lat1, 0.0, azi1, s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 3:
// Time Inverse
for (int i = 1; i <= 179; i += 2) {
Math::real lat1 = i * Math::real(0.5);
for (int j = -179; j <= 179; j += 2) {
Math::real lat2 = j * Math::real(0.5);
for (int k = 1; k <= 359; k += 2) {
Math::real lon2 = k * Math::real(0.5);
Math::real s12;
geod.Inverse(lat1, 0.0, lat2, lon2, s12);
++cnt;
s += s12;
}
}
}
cout << cnt << " " << s << "\n";
break;
}
} else {
const GeodesicExact& geod = GeodesicExact::WGS84();
unsigned cnt = 0;
Math::real s = 0;
Math::real dl;
switch (timecase) {
case 0:
// Time Line
dl = 2e7/1000;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
const GeodesicLineExact l(geod, lat1, 0.0, azi1);
for (int k = 0; k <= 1000; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
l.Position(s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 1:
// Time Line ang
dl = Math::real(180)/1000;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
GeodesicLineExact l(geod, lat1, 0.0, azi1);
for (int k = 0; k <= 1000; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
l.ArcPosition(s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 2:
// Time Direct
dl = 2e7/200;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
for (int k = 0; k <= 200; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
geod.Direct(lat1, 0.0, azi1, s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 3:
// Time Inverse
for (int i = 1; i <= 179; i += 2) {
Math::real lat1 = i * Math::real(0.5);
for (int j = -179; j <= 179; j += 2) {
Math::real lat2 = j * Math::real(0.5);
for (int k = 1; k <= 359; k += 2) {
Math::real lon2 = k * Math::real(0.5);
Math::real s12;
geod.Inverse(lat1, 0.0, lat2, lon2, s12);
++cnt;
s += s12;
}
}
}
cout << cnt << " " << s << "\n";
break;
}
}
}
else if (accuracytest || coverage) {
const Geodesic geod(a, f);
const GeodesicExact geode(a, f);
const unsigned NUMERR = 7;
cout << fixed << setprecision(2);
vector<Math::real> erra(NUMERR);
vector<Math::real> err(NUMERR, 0.0);
vector<unsigned> errind(NUMERR);
unsigned cnt = 0;
string s;
while (getline(cin, s)) {
istringstream str(s);
Math::real lat1l, lon1l, azi1l, lat2l, lon2l, azi2l,
s12l, a12l, m12l, S12l;
if (!(str >> lat1l >> lon1l >> azi1l
>> lat2l >> lon2l >> azi2l
>> s12l >> a12l >> m12l))
break;
if (!(str >> S12l))
S12l = Math::NaN();
if (coverage) {
#if defined(GEOD_DIAG) && GEOD_DIAG
Math::real
lat1 = lat1l, lon1 = lon1l,
lat2 = lat2l, lon2 = lon2l,
azi1, azi2, s12, m12;
geod.Inverse(lat1, lon1, lat2, lon2, s12, azi1, azi2, m12);
cout << geod.coverage << " " << geod.niter << "\n";
#endif
} else {
exact ?
GeodError< GeodesicExact >
(geode, lat1l, lon1l, azi1l,
lat2l, lon2l, azi2l,
s12l, a12l, m12l, S12l,
erra) :
GeodError< Geodesic >
(geod, lat1l, lon1l, azi1l,
lat2l, lon2l, azi2l,
s12l, a12l, m12l, S12l,
erra);
for (unsigned i = 0; i < NUMERR; ++i) {
if (isfinite(err[i]) && !(erra[i] <= err[i])) {
err[i] = erra[i];
errind[i] = cnt;
}
}
++cnt;
}
}
if (accuracytest) {
Math::real mult = Math::real(Math::extra_digits() == 0 ? 1e9l :
Math::extra_digits() <= 3 ? 1e12l : 1e15l);
for (unsigned i = 0; i < NUMERR; ++i)
cout << i << " " << mult * err[i]
<< " " << errind[i] << "\n";
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,838 @@
/**
* \file Geodesic30.hpp
* \brief Header for GeographicLib::Geodesic30 class
*
* Copyright (c) Charles Karney (2009-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#if !defined(GEOGRAPHICLIB_GEODESICEXACT_HPP)
#define GEOGRAPHICLIB_GEODESICEXACT_HPP 1
#include <GeographicLib/Constants.hpp>
#if !defined(GEOGRAPHICLIB_GEODESICEXACT_ORDER)
/**
* The order of the expansions used by Geodesic30.
**********************************************************************/
# define GEOGRAPHICLIB_GEODESICEXACT_ORDER 30
#endif
namespace GeographicLib {
template<typename real> class GeodesicLine30;
/**
* \brief %Geodesic calculations
*
* The shortest path between two points on an ellipsoid at (\e lat1, \e lon1)
* and (\e lat2, \e lon2) is called the geodesic. Its length is \e s12 and
* the geodesic from point 1 to point 2 has azimuths \e azi1 and \e azi2 at
* the two end points. (The azimuth is the heading measured clockwise from
* north. \e azi2 is the "forward" azimuth, i.e., the heading that takes you
* beyond point 2 not back to point 1.)
*
* Given \e lat1, \e lon1, \e azi1, and \e s12, we can determine \e lat2, \e
* lon2, and \e azi2. This is the \e direct geodesic problem and its
* solution is given by the function Geodesic30::Direct. (If \e s12 is
* sufficiently large that the geodesic wraps more than halfway around the
* earth, there will be another geodesic between the points with a smaller \e
* s12.)
*
* Given \e lat1, \e lon1, \e lat2, and \e lon2, we can determine \e azi1, \e
* azi2, and \e s12. This is the \e inverse geodesic problem, whose solution
* is given by Geodesic30::Inverse. Usually, the solution to the inverse
* problem is unique. In cases where there are multiple solutions (all with
* the same \e s12, of course), all the solutions can be easily generated
* once a particular solution is provided.
*
* The standard way of specifying the direct problem is the specify the
* distance \e s12 to the second point. However it is sometimes useful
* instead to specify the arc length \e a12 (in degrees) on the auxiliary
* sphere. This is a mathematical construct used in solving the geodesic
* problems. The solution of the direct problem in this form is provided by
* Geodesic30::ArcDirect. An arc length in excess of 180&deg; indicates that
* the geodesic is not a shortest path. In addition, the arc length between
* an equatorial crossing and the next extremum of latitude for a geodesic is
* 90&deg;.
*
* This class can also calculate several other quantities related to
* geodesics. These are:
* - <i>reduced length</i>. If we fix the first point and increase \e azi1
* by \e dazi1 (radians), the second point is displaced \e m12 \e dazi1 in
* the direction \e azi2 + 90&deg;. The quantity \e m12 is called
* the "reduced length" and is symmetric under interchange of the two
* points. On a curved surface the reduced length obeys a symmetry
* relation, \e m12 + \e m21 = 0. On a flat surface, we have \e m12 = \e
* s12. The ratio <i>s12</i>/\e m12 gives the azimuthal scale for an
* azimuthal equidistant projection.
* - <i>geodesic scale</i>. Consider a reference geodesic and a second
* geodesic parallel to this one at point 1 and separated by a small
* distance \e dt. The separation of the two geodesics at point 2 is \e
* M12 \e dt where \e M12 is called the "geodesic scale". \e M21 is
* defined similarly (with the geodesics being parallel at point 2). On a
* flat surface, we have \e M12 = \e M21 = 1. The quantity 1/\e M12 gives
* the scale of the Cassini-Soldner projection.
* - <i>area</i>. Consider the quadrilateral bounded by the following lines:
* the geodesic from point 1 to point 2, the meridian from point 2 to the
* equator, the equator from \e lon2 to \e lon1, the meridian from the
* equator to point 1. The area of this quadrilateral is represented by \e
* S12 with a clockwise traversal of the perimeter counting as a positive
* area and it can be used to compute the area of any simple geodesic
* polygon.
*
* Overloaded versions of Geodesic30::Direct, Geodesic30::ArcDirect,
* and Geodesic30::Inverse allow these quantities to be returned. In
* addition there are general functions Geodesic30::GenDirect, and
* Geodesic30::GenInverse which allow an arbitrary set of results to be
* computed. The quantities \e m12, \e M12, \e M21 which all specify the
* behavior of nearby geodesics obey addition rules. Let points 1, 2, and 3
* all lie on a single geodesic, then
* - \e m13 = \e m12 \e M23 + \e m23 \e M21
* - \e M13 = \e M12 \e M23 &minus; (1 &minus; \e M12 \e M21) \e m23 / \e m12
* - \e M31 = \e M32 \e M21 &minus; (1 &minus; \e M23 \e M32) \e m12 / \e m23
*
* Additional functionality is provided by the GeodesicLine30 class, which
* allows a sequence of points along a geodesic to be computed.
*
* The calculations are accurate to better than 15 nm (15 nanometers). See
* Sec. 9 of
* <a href="https://arxiv.org/abs/1102.1215v1">arXiv:1102.1215v1</a>
* for details.
*
* The algorithms are described in
* - C. F. F. Karney,
* <a href="https://doi.org/10.1007/s00190-012-0578-z">
* Algorithms for geodesics</a>,
* J. Geodesy <b>87</b>, 43--55 (2013);
* DOI: <a href="https://doi.org/10.1007/s00190-012-0578-z">
* 10.1007/s00190-012-0578-z</a>;
* addenda: <a href="https://geographiclib.sourceforge.io/geod-addenda.html">
* geod-addenda.html</a>.
* .
* For more information on geodesics see \ref geodesic.
**********************************************************************/
template<typename real>
class Geodesic30 {
private:
friend class GeodesicLine30<real>;
static const int nA1_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
static const int nC1_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
static const int nC1p_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
static const int nA2_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
static const int nC2_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
static const int nA3_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
static const int nA3x_ = nA3_;
static const int nC3_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
static const int nC3x_ = (nC3_ * (nC3_ - 1)) / 2;
static const int nC4_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
static const int nC4x_ = (nC4_ * (nC4_ + 1)) / 2;
static const unsigned maxit_ = 50;
static const real tiny_;
static const real tol0_;
static const real tol1_;
static const real tol2_;
static const real xthresh_;
enum captype {
CAP_NONE = 0U,
CAP_C1 = 1U<<0,
CAP_C1p = 1U<<1,
CAP_C2 = 1U<<2,
CAP_C3 = 1U<<3,
CAP_C4 = 1U<<4,
CAP_ALL = 0x1FU,
OUT_ALL = 0x7F80U,
};
static real SinCosSeries(bool sinp,
real sinx, real cosx, const real c[], int n)
;
static inline real AngRound(real x) {
// The makes the smallest gap in x = 1/16 - nextafter(1/16, 0) = 1/2^57
// for reals = 0.7 pm on the earth if x is an angle in degrees. (This
// is about 1000 times more resolution than we get with angles around 90
// degrees.) We use this to avoid having to deal with near singular
// cases when x is non-zero but tiny (e.g., 1.0e-200).
const real z = real(0.0625); // 1/16
volatile real y = std::abs(x);
// The compiler mustn't "simplify" z - (z - y) to y
y = y < z ? z - (z - y) : y;
return x < 0 ? -y : y;
}
static inline void SinCosNorm(real& sinx, real& cosx) {
using std::hypot;
real r = hypot(sinx, cosx);
sinx /= r;
cosx /= r;
}
static real Astroid(real x, real y);
real _a, _f, _f1, _e2, _ep2, _n, _b, _c2, _etol2;
real _A3x[nA3x_], _C3x[nC3x_], _C4x[nC4x_];
void Lengths(real eps, real sig12,
real ssig1, real csig1, real ssig2, real csig2,
real cbet1, real cbet2,
real& s12s, real& m12a, real& m0,
bool scalep, real& M12, real& M21,
real C1a[], real C2a[]) const;
real InverseStart(real sbet1, real cbet1, real sbet2, real cbet2,
real lam12,
real& salp1, real& calp1,
real& salp2, real& calp2,
real C1a[], real C2a[]) const;
real Lambda12(real sbet1, real cbet1, real sbet2, real cbet2,
real salp1, real calp1,
real& salp2, real& calp2, real& sig12,
real& ssig1, real& csig1, real& ssig2, real& csig2,
real& eps, real& domg12, bool diffp, real& dlam12,
real C1a[], real C2a[], real C3a[])
const;
// These are Maxima generated functions to provide series approximations to
// the integrals for the ellipsoidal geodesic.
static real A1m1f(real eps);
static void C1f(real eps, real c[]);
static void C1pf(real eps, real c[]);
static real A2m1f(real eps);
static void C2f(real eps, real c[]);
void A3coeff();
real A3f(real eps) const;
void C3coeff();
void C3f(real eps, real c[]) const;
void C4coeff();
void C4f(real k2, real c[]) const;
public:
/**
* Bit masks for what calculations to do. These masks do double duty.
* They signify to the GeodesicLine30::GeodesicLine30 constructor and
* to Geodesic30::Line what capabilities should be included in the
* GeodesicLine30 object. They also specify which results to return in
* the general routines Geodesic30::GenDirect and
* Geodesic30::GenInverse routines. GeodesicLine30::mask is a
* duplication of this enum.
**********************************************************************/
enum mask {
/**
* No capabilities, no output.
* @hideinitializer
**********************************************************************/
NONE = 0U,
/**
* Calculate latitude \e lat2. (It's not necessary to include this as a
* capability to GeodesicLine30 because this is included by default.)
* @hideinitializer
**********************************************************************/
LATITUDE = 1U<<7 | CAP_NONE,
/**
* Calculate longitude \e lon2.
* @hideinitializer
**********************************************************************/
LONGITUDE = 1U<<8 | CAP_C3,
/**
* Calculate azimuths \e azi1 and \e azi2. (It's not necessary to
* include this as a capability to GeodesicLine30 because this is
* included by default.)
* @hideinitializer
**********************************************************************/
AZIMUTH = 1U<<9 | CAP_NONE,
/**
* Calculate distance \e s12.
* @hideinitializer
**********************************************************************/
DISTANCE = 1U<<10 | CAP_C1,
/**
* Allow distance \e s12 to be used as input in the direct geodesic
* problem.
* @hideinitializer
**********************************************************************/
DISTANCE_IN = 1U<<11 | CAP_C1 | CAP_C1p,
/**
* Calculate reduced length \e m12.
* @hideinitializer
**********************************************************************/
REDUCEDLENGTH = 1U<<12 | CAP_C1 | CAP_C2,
/**
* Calculate geodesic scales \e M12 and \e M21.
* @hideinitializer
**********************************************************************/
GEODESICSCALE = 1U<<13 | CAP_C1 | CAP_C2,
/**
* Calculate area \e S12.
* @hideinitializer
**********************************************************************/
AREA = 1U<<14 | CAP_C4,
/**
* All capabilities, calculate everything.
* @hideinitializer
**********************************************************************/
ALL = OUT_ALL| CAP_ALL,
};
/** \name Constructor
**********************************************************************/
///@{
/**
* Constructor for an ellipsoid with
*
* @param[in] a equatorial radius (meters).
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
* Negative \e f gives a prolate ellipsoid. If \e f > 1, set flattening
* to 1/\e f.
* @exception GeographicErr if \e a or (1 &minus; \e f ) \e a is not
* positive.
**********************************************************************/
Geodesic30(real a, real f);
///@}
/** \name Direct geodesic problem specified in terms of distance.
**********************************************************************/
///@{
/**
* Perform the direct geodesic calculation where the length of the geodesic
* is specified in terms of distance.
*
* @param[in] lat1 latitude of point 1 (degrees).
* @param[in] lon1 longitude of point 1 (degrees).
* @param[in] azi1 azimuth at point 1 (degrees).
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
* signed.
* @param[out] lat2 latitude of point 2 (degrees).
* @param[out] lon2 longitude of point 2 (degrees).
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
* @param[out] m12 reduced length of geodesic (meters).
* @param[out] M12 geodesic scale of point 2 relative to point 1
* (dimensionless).
* @param[out] M21 geodesic scale of point 1 relative to point 2
* (dimensionless).
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
* @return \e a12 arc length of between point 1 and point 2 (degrees).
*
* \e lat1 should be in the range [&minus;90&deg;, 90&deg;]; \e lon1 and \e
* azi1 should be in the range [&minus;540&deg;, 540&deg;). The values of
* \e lon2 and \e azi2 returned are in the range [&minus;180&deg;,
* 180&deg;).
*
* If either point is at a pole, the azimuth is defined by keeping the
* longitude fixed and writing \e lat = 90&deg; &minus; &epsilon; or
* &minus;90&deg; + &epsilon; and taking the limit &epsilon; &rarr; 0 from
* above. An arc length greater that 180&deg; signifies a geodesic which
* is not a shortest path. (For a prolate ellipsoid, an additional
* condition is necessary for a shortest path: the longitudinal extent must
* not exceed of 180&deg;.)
*
* The following functions are overloaded versions of Geodesic30::Direct
* which omit some of the output parameters. Note, however, that the arc
* length is always computed and returned as the function value.
**********************************************************************/
real Direct(real lat1, real lon1, real azi1, real s12,
real& lat2, real& lon2, real& azi2,
real& m12, real& M12, real& M21, real& S12)
const {
real t;
return GenDirect(lat1, lon1, azi1, false, s12,
LATITUDE | LONGITUDE | AZIMUTH |
REDUCEDLENGTH | GEODESICSCALE | AREA,
lat2, lon2, azi2, t, m12, M12, M21, S12);
}
/**
* See the documentation for Geodesic30::Direct.
**********************************************************************/
real Direct(real lat1, real lon1, real azi1, real s12,
real& lat2, real& lon2)
const {
real t;
return GenDirect(lat1, lon1, azi1, false, s12,
LATITUDE | LONGITUDE,
lat2, lon2, t, t, t, t, t, t);
}
/**
* See the documentation for Geodesic30::Direct.
**********************************************************************/
real Direct(real lat1, real lon1, real azi1, real s12,
real& lat2, real& lon2, real& azi2)
const {
real t;
return GenDirect(lat1, lon1, azi1, false, s12,
LATITUDE | LONGITUDE | AZIMUTH,
lat2, lon2, azi2, t, t, t, t, t);
}
/**
* See the documentation for Geodesic30::Direct.
**********************************************************************/
real Direct(real lat1, real lon1, real azi1, real s12,
real& lat2, real& lon2, real& azi2, real& m12)
const {
real t;
return GenDirect(lat1, lon1, azi1, false, s12,
LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH,
lat2, lon2, azi2, t, m12, t, t, t);
}
/**
* See the documentation for Geodesic30::Direct.
**********************************************************************/
real Direct(real lat1, real lon1, real azi1, real s12,
real& lat2, real& lon2, real& azi2,
real& M12, real& M21)
const {
real t;
return GenDirect(lat1, lon1, azi1, false, s12,
LATITUDE | LONGITUDE | AZIMUTH | GEODESICSCALE,
lat2, lon2, azi2, t, t, M12, M21, t);
}
/**
* See the documentation for Geodesic30::Direct.
**********************************************************************/
real Direct(real lat1, real lon1, real azi1, real s12,
real& lat2, real& lon2, real& azi2,
real& m12, real& M12, real& M21)
const {
real t;
return GenDirect(lat1, lon1, azi1, false, s12,
LATITUDE | LONGITUDE | AZIMUTH |
REDUCEDLENGTH | GEODESICSCALE,
lat2, lon2, azi2, t, m12, M12, M21, t);
}
///@}
/** \name Direct geodesic problem specified in terms of arc length.
**********************************************************************/
///@{
/**
* Perform the direct geodesic calculation where the length of the geodesic
* is specified in terms of arc length.
*
* @param[in] lat1 latitude of point 1 (degrees).
* @param[in] lon1 longitude of point 1 (degrees).
* @param[in] azi1 azimuth at point 1 (degrees).
* @param[in] a12 arc length between point 1 and point 2 (degrees); it can
* be signed.
* @param[out] lat2 latitude of point 2 (degrees).
* @param[out] lon2 longitude of point 2 (degrees).
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
* @param[out] s12 distance between point 1 and point 2 (meters).
* @param[out] m12 reduced length of geodesic (meters).
* @param[out] M12 geodesic scale of point 2 relative to point 1
* (dimensionless).
* @param[out] M21 geodesic scale of point 1 relative to point 2
* (dimensionless).
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
*
* \e lat1 should be in the range [&minus;90&deg;, 90&deg;]; \e lon1 and \e
* azi1 should be in the range [&minus;540&deg;, 540&deg;). The values of
* \e lon2 and \e azi2 returned are in the range [&minus;180&deg;,
* 180&deg;).
*
* If either point is at a pole, the azimuth is defined by keeping the
* longitude fixed and writing \e lat = 90&deg; &minus; &epsilon; or
* &minus;90&deg; + &epsilon; and taking the limit &epsilon; &rarr; 0 from
* above. An arc length greater that 180&deg; signifies a geodesic which
* is not a shortest path. (For a prolate ellipsoid, an additional
* condition is necessary for a shortest path: the longitudinal extent must
* not exceed of 180&deg;.)
*
* The following functions are overloaded versions of Geodesic30::Direct
* which omit some of the output parameters.
**********************************************************************/
void ArcDirect(real lat1, real lon1, real azi1, real a12,
real& lat2, real& lon2, real& azi2, real& s12,
real& m12, real& M12, real& M21, real& S12)
const {
GenDirect(lat1, lon1, azi1, true, a12,
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
REDUCEDLENGTH | GEODESICSCALE | AREA,
lat2, lon2, azi2, s12, m12, M12, M21, S12);
}
/**
* See the documentation for Geodesic30::ArcDirect.
**********************************************************************/
void ArcDirect(real lat1, real lon1, real azi1, real a12,
real& lat2, real& lon2) const {
real t;
GenDirect(lat1, lon1, azi1, true, a12,
LATITUDE | LONGITUDE,
lat2, lon2, t, t, t, t, t, t);
}
/**
* See the documentation for Geodesic30::ArcDirect.
**********************************************************************/
void ArcDirect(real lat1, real lon1, real azi1, real a12,
real& lat2, real& lon2, real& azi2) const {
real t;
GenDirect(lat1, lon1, azi1, true, a12,
LATITUDE | LONGITUDE | AZIMUTH,
lat2, lon2, azi2, t, t, t, t, t);
}
/**
* See the documentation for Geodesic30::ArcDirect.
**********************************************************************/
void ArcDirect(real lat1, real lon1, real azi1, real a12,
real& lat2, real& lon2, real& azi2, real& s12)
const {
real t;
GenDirect(lat1, lon1, azi1, true, a12,
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE,
lat2, lon2, azi2, s12, t, t, t, t);
}
/**
* See the documentation for Geodesic30::ArcDirect.
**********************************************************************/
void ArcDirect(real lat1, real lon1, real azi1, real a12,
real& lat2, real& lon2, real& azi2,
real& s12, real& m12) const {
real t;
GenDirect(lat1, lon1, azi1, true, a12,
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
REDUCEDLENGTH,
lat2, lon2, azi2, s12, m12, t, t, t);
}
/**
* See the documentation for Geodesic30::ArcDirect.
**********************************************************************/
void ArcDirect(real lat1, real lon1, real azi1, real a12,
real& lat2, real& lon2, real& azi2, real& s12,
real& M12, real& M21) const {
real t;
GenDirect(lat1, lon1, azi1, true, a12,
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
GEODESICSCALE,
lat2, lon2, azi2, s12, t, M12, M21, t);
}
/**
* See the documentation for Geodesic30::ArcDirect.
**********************************************************************/
void ArcDirect(real lat1, real lon1, real azi1, real a12,
real& lat2, real& lon2, real& azi2, real& s12,
real& m12, real& M12, real& M21) const {
real t;
GenDirect(lat1, lon1, azi1, true, a12,
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
REDUCEDLENGTH | GEODESICSCALE,
lat2, lon2, azi2, s12, m12, M12, M21, t);
}
///@}
/** \name General version of the direct geodesic solution.
**********************************************************************/
///@{
/**
* The general direct geodesic calculation. Geodesic30::Direct and
* Geodesic30::ArcDirect are defined in terms of this function.
*
* @param[in] lat1 latitude of point 1 (degrees).
* @param[in] lon1 longitude of point 1 (degrees).
* @param[in] azi1 azimuth at point 1 (degrees).
* @param[in] arcmode boolean flag determining the meaning of the second
* parameter.
* @param[in] s12_a12 if \e arcmode is false, this is the distance between
* point 1 and point 2 (meters); otherwise it is the arc length between
* point 1 and point 2 (degrees); it can be signed.
* @param[in] outmask a bitor'ed combination of Geodesic30::mask values
* specifying which of the following parameters should be set.
* @param[out] lat2 latitude of point 2 (degrees).
* @param[out] lon2 longitude of point 2 (degrees).
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
* @param[out] s12 distance between point 1 and point 2 (meters).
* @param[out] m12 reduced length of geodesic (meters).
* @param[out] M12 geodesic scale of point 2 relative to point 1
* (dimensionless).
* @param[out] M21 geodesic scale of point 1 relative to point 2
* (dimensionless).
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
* @return \e a12 arc length of between point 1 and point 2 (degrees).
*
* The Geodesic30::mask values possible for \e outmask are
* - \e outmask |= Geodesic30::LATITUDE for the latitude \e lat2.
* - \e outmask |= Geodesic30::LONGITUDE for the latitude \e lon2.
* - \e outmask |= Geodesic30::AZIMUTH for the latitude \e azi2.
* - \e outmask |= Geodesic30::DISTANCE for the distance \e s12.
* - \e outmask |= Geodesic30::REDUCEDLENGTH for the reduced length \e
* m12.
* - \e outmask |= Geodesic30::GEODESICSCALE for the geodesic scales \e
* M12 and \e M21.
* - \e outmask |= Geodesic30::AREA for the area \e S12.
* .
* The function value \e a12 is always computed and returned and this
* equals \e s12_a12 is \e arcmode is true. If \e outmask includes
* Geodesic30::DISTANCE and \e arcmode is false, then \e s12 = \e
* s12_a12. It is not necessary to include Geodesic30::DISTANCE_IN in
* \e outmask; this is automatically included is \e arcmode is false.
**********************************************************************/
real GenDirect(real lat1, real lon1, real azi1,
bool arcmode, real s12_a12, unsigned outmask,
real& lat2, real& lon2, real& azi2,
real& s12, real& m12, real& M12, real& M21,
real& S12) const;
///@}
/** \name Inverse geodesic problem.
**********************************************************************/
///@{
/**
* Perform the inverse geodesic calculation.
*
* @param[in] lat1 latitude of point 1 (degrees).
* @param[in] lon1 longitude of point 1 (degrees).
* @param[in] lat2 latitude of point 2 (degrees).
* @param[in] lon2 longitude of point 2 (degrees).
* @param[out] s12 distance between point 1 and point 2 (meters).
* @param[out] azi1 azimuth at point 1 (degrees).
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
* @param[out] m12 reduced length of geodesic (meters).
* @param[out] M12 geodesic scale of point 2 relative to point 1
* (dimensionless).
* @param[out] M21 geodesic scale of point 1 relative to point 2
* (dimensionless).
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
* @return \e a12 arc length of between point 1 and point 2 (degrees).
*
* \e lat1 and \e lat2 should be in the range [&minus;90&deg;, 90&deg;]; \e
* lon1 and \e lon2 should be in the range [&minus;540&deg;, 540&deg;).
* The values of \e azi1 and \e azi2 returned are in the range
* [&minus;180&deg;, 180&deg;).
*
* If either point is at a pole, the azimuth is defined by keeping the
* longitude fixed and writing \e lat = 90&deg; &minus; &epsilon; or
* &minus;90&deg; + &epsilon; and taking the limit &epsilon; &rarr; 0 from
* above. If the routine fails to converge, then all the requested outputs
* are set to Math::NaN(). (Test for such results with Math::isnan.) This
* is not expected to happen with ellipsoidal models of the earth; please
* report all cases where this occurs.
*
* The following functions are overloaded versions of Geodesic30::Inverse
* which omit some of the output parameters. Note, however, that the arc
* length is always computed and returned as the function value.
**********************************************************************/
real Inverse(real lat1, real lon1, real lat2, real lon2,
real& s12, real& azi1, real& azi2, real& m12,
real& M12, real& M21, real& S12) const {
return GenInverse(lat1, lon1, lat2, lon2,
DISTANCE | AZIMUTH |
REDUCEDLENGTH | GEODESICSCALE | AREA,
s12, azi1, azi2, m12, M12, M21, S12);
}
/**
* See the documentation for Geodesic30::Inverse.
**********************************************************************/
real Inverse(real lat1, real lon1, real lat2, real lon2,
real& s12) const {
real t;
return GenInverse(lat1, lon1, lat2, lon2,
DISTANCE,
s12, t, t, t, t, t, t);
}
/**
* See the documentation for Geodesic30::Inverse.
**********************************************************************/
real Inverse(real lat1, real lon1, real lat2, real lon2,
real& azi1, real& azi2) const {
real t;
return GenInverse(lat1, lon1, lat2, lon2,
AZIMUTH,
t, azi1, azi2, t, t, t, t);
}
/**
* See the documentation for Geodesic30::Inverse.
**********************************************************************/
real Inverse(real lat1, real lon1, real lat2, real lon2,
real& s12, real& azi1, real& azi2)
const {
real t;
return GenInverse(lat1, lon1, lat2, lon2,
DISTANCE | AZIMUTH,
s12, azi1, azi2, t, t, t, t);
}
/**
* See the documentation for Geodesic30::Inverse.
**********************************************************************/
real Inverse(real lat1, real lon1, real lat2, real lon2,
real& s12, real& azi1, real& azi2, real& m12)
const {
real t;
return GenInverse(lat1, lon1, lat2, lon2,
DISTANCE | AZIMUTH | REDUCEDLENGTH,
s12, azi1, azi2, m12, t, t, t);
}
/**
* See the documentation for Geodesic30::Inverse.
**********************************************************************/
real Inverse(real lat1, real lon1, real lat2, real lon2,
real& s12, real& azi1, real& azi2,
real& M12, real& M21) const {
real t;
return GenInverse(lat1, lon1, lat2, lon2,
DISTANCE | AZIMUTH | GEODESICSCALE,
s12, azi1, azi2, t, M12, M21, t);
}
/**
* See the documentation for Geodesic30::Inverse.
**********************************************************************/
real Inverse(real lat1, real lon1, real lat2, real lon2,
real& s12, real& azi1, real& azi2, real& m12,
real& M12, real& M21) const {
real t;
return GenInverse(lat1, lon1, lat2, lon2,
DISTANCE | AZIMUTH |
REDUCEDLENGTH | GEODESICSCALE,
s12, azi1, azi2, m12, M12, M21, t);
}
///@}
/** \name General version of inverse geodesic solution.
**********************************************************************/
///@{
/**
* The general inverse geodesic calculation. Geodesic30::Inverse is
* defined in terms of this function.
*
* @param[in] lat1 latitude of point 1 (degrees).
* @param[in] lon1 longitude of point 1 (degrees).
* @param[in] lat2 latitude of point 2 (degrees).
* @param[in] lon2 longitude of point 2 (degrees).
* @param[in] outmask a bitor'ed combination of Geodesic30::mask values
* specifying which of the following parameters should be set.
* @param[out] s12 distance between point 1 and point 2 (meters).
* @param[out] azi1 azimuth at point 1 (degrees).
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
* @param[out] m12 reduced length of geodesic (meters).
* @param[out] M12 geodesic scale of point 2 relative to point 1
* (dimensionless).
* @param[out] M21 geodesic scale of point 1 relative to point 2
* (dimensionless).
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
* @return \e a12 arc length of between point 1 and point 2 (degrees).
*
* The Geodesic30::mask values possible for \e outmask are
* - \e outmask |= Geodesic30::DISTANCE for the distance \e s12.
* - \e outmask |= Geodesic30::AZIMUTH for the latitude \e azi2.
* - \e outmask |= Geodesic30::REDUCEDLENGTH for the reduced length \e
* m12.
* - \e outmask |= Geodesic30::GEODESICSCALE for the geodesic scales \e
* M12 and \e M21.
* - \e outmask |= Geodesic30::AREA for the area \e S12.
* .
* The arc length is always computed and returned as the function value.
**********************************************************************/
real GenInverse(real lat1, real lon1, real lat2, real lon2,
unsigned outmask,
real& s12, real& azi1, real& azi2,
real& m12, real& M12, real& M21, real& S12)
const;
///@}
/** \name Interface to GeodesicLine30.
**********************************************************************/
///@{
/**
* Set up to compute several points on a single geodesic.
*
* @param[in] lat1 latitude of point 1 (degrees).
* @param[in] lon1 longitude of point 1 (degrees).
* @param[in] azi1 azimuth at point 1 (degrees).
* @param[in] caps bitor'ed combination of Geodesic30::mask values
* specifying the capabilities the GeodesicLine30 object should
* possess, i.e., which quantities can be returned in calls to
* GeodesicLine::Position.
*
* \e lat1 should be in the range [&minus;90&deg;, 90&deg;]; \e lon1 and \e
* azi1 should be in the range [&minus;540&deg;, 540&deg;).
*
* The Geodesic30::mask values are
* - \e caps |= Geodesic30::LATITUDE for the latitude \e lat2; this is
* added automatically
* - \e caps |= Geodesic30::LONGITUDE for the latitude \e lon2
* - \e caps |= Geodesic30::AZIMUTH for the latitude \e azi2; this is
* added automatically
* - \e caps |= Geodesic30::DISTANCE for the distance \e s12
* - \e caps |= Geodesic30::REDUCEDLENGTH for the reduced length \e m12
* - \e caps |= Geodesic30::GEODESICSCALE for the geodesic scales \e M12
* and \e M21
* - \e caps |= Geodesic30::AREA for the area \e S12
* - \e caps |= Geodesic30::DISTANCE_IN permits the length of the
* geodesic to be given in terms of \e s12; without this capability the
* length can only be specified in terms of arc length.
* .
* The default value of \e caps is Geodesic30::ALL which turns on all
* the capabilities.
*
* If the point is at a pole, the azimuth is defined by keeping the \e lon1
* fixed and writing \e lat1 = &plusmn;(90&deg; &minus; &epsilon;) and
* taking the limit &epsilon; &rarr; 0+.
**********************************************************************/
GeodesicLine30<real>
Line(real lat1, real lon1, real azi1, unsigned caps = ALL)
const;
///@}
/** \name Inspector functions.
**********************************************************************/
///@{
/**
* @return \e a the equatorial radius of the ellipsoid (meters). This is
* the value used in the constructor.
**********************************************************************/
real EquatorialRadius() const { return _a; }
/**
* @return \e f the flattening of the ellipsoid. This is the
* value used in the constructor.
**********************************************************************/
real Flattening() const { return _f; }
/// \cond SKIP
/**
* <b>DEPRECATED</b>
* @return \e r the inverse flattening of the ellipsoid.
**********************************************************************/
real InverseFlattening() const { return 1/_f; }
/// \endcond
/**
* @return total area of ellipsoid in meters<sup>2</sup>. The area of a
* polygon encircling a pole can be found by adding
* Geodesic30::EllipsoidArea()/2 to the sum of \e S12 for each side of
* the polygon.
**********************************************************************/
real EllipsoidArea() const
{ return 4 * Math::pi<real>() * _c2; }
///@}
/**
* A global instantiation of Geodesic30 with the parameters for the WGS84
* ellipsoid.
**********************************************************************/
static const Geodesic30 WGS84;
};
} // namespace GeographicLib
#endif // GEOGRAPHICLIB_GEODESICEXACT_HPP

View File

@@ -0,0 +1,270 @@
/**
* \file GeodesicLine30.cpp
* \brief Implementation for GeographicLib::GeodesicLine30 class
*
* Copyright (c) Charles Karney (2009-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* This is a reformulation of the geodesic problem. The notation is as
* follows:
* - at a general point (no suffix or 1 or 2 as suffix)
* - phi = latitude
* - beta = latitude on auxiliary sphere
* - omega = longitude on auxiliary sphere
* - lambda = longitude
* - alpha = azimuth of great circle
* - sigma = arc length along great circle
* - s = distance
* - tau = scaled distance (= sigma at multiples of pi/2)
* - at northwards equator crossing
* - beta = phi = 0
* - omega = lambda = 0
* - alpha = alpha0
* - sigma = s = 0
* - a 12 suffix means a difference, e.g., s12 = s2 - s1.
* - s and c prefixes mean sin and cos
**********************************************************************/
#include "GeodesicLine30.hpp"
namespace GeographicLib {
using namespace std;
template<typename real>
GeodesicLine30<real>::GeodesicLine30(const Geodesic30<real>& g,
real lat1, real lon1, real azi1,
unsigned caps)
: _a(g._a)
, _f(g._f)
, _b(g._b)
, _c2(g._c2)
, _f1(g._f1)
// Always allow latitude and azimuth
, _caps(caps | LATITUDE | AZIMUTH)
{
azi1 = Math::AngNormalize(azi1);
// Guard against underflow in salp0
azi1 = Geodesic30<real>::AngRound(azi1);
lon1 = Math::AngNormalize(lon1);
_lat1 = lat1;
_lon1 = lon1;
_azi1 = azi1;
// alp1 is in [0, pi]
real alp1 = azi1 * Math::degree<real>();
// Enforce sin(pi) == 0 and cos(pi/2) == 0. Better to face the ensuing
// problems directly than to skirt them.
_salp1 = azi1 == -180 ? 0 : sin(alp1);
_calp1 = abs(azi1) == 90 ? 0 : cos(alp1);
real cbet1, sbet1, phi;
phi = lat1 * Math::degree<real>();
// Ensure cbet1 = +epsilon at poles
sbet1 = _f1 * sin(phi);
cbet1 = abs(lat1) == 90 ? Geodesic30<real>::tiny_ : cos(phi);
Geodesic30<real>::SinCosNorm(sbet1, cbet1);
// Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0),
_salp0 = _salp1 * cbet1; // alp0 in [0, pi/2 - |bet1|]
// Alt: calp0 = hypot(sbet1, calp1 * cbet1). The following
// is slightly better (consider the case salp1 = 0).
_calp0 = hypot(_calp1, _salp1 * sbet1);
// Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1).
// sig = 0 is nearest northward crossing of equator.
// With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line).
// With bet1 = pi/2, alp1 = -pi, sig1 = pi/2
// With bet1 = -pi/2, alp1 = 0 , sig1 = -pi/2
// Evaluate omg1 with tan(omg1) = sin(alp0) * tan(sig1).
// With alp0 in (0, pi/2], quadrants for sig and omg coincide.
// No atan2(0,0) ambiguity at poles since cbet1 = +epsilon.
// With alp0 = 0, omg1 = 0 for alp1 = 0, omg1 = pi for alp1 = pi.
_ssig1 = sbet1; _somg1 = _salp0 * sbet1;
_csig1 = _comg1 = sbet1 != 0 || _calp1 != 0 ? cbet1 * _calp1 : 1;
Geodesic30<real>::SinCosNorm(_ssig1, _csig1); // sig1 in (-pi, pi]
Geodesic30<real>::SinCosNorm(_somg1, _comg1);
_k2 = Math::sq(_calp0) * g._ep2;
real eps = _k2 / (2 * (1 + sqrt(1 + _k2)) + _k2);
if (_caps & CAP_C1) {
_A1m1 = Geodesic30<real>::A1m1f(eps);
Geodesic30<real>::C1f(eps, _C1a);
_B11 = Geodesic30<real>::SinCosSeries(true, _ssig1, _csig1, _C1a, nC1_);
real s = sin(_B11), c = cos(_B11);
// tau1 = sig1 + B11
_stau1 = _ssig1 * c + _csig1 * s;
_ctau1 = _csig1 * c - _ssig1 * s;
// Not necessary because C1pa reverts C1a
// _B11 = -SinCosSeries(true, _stau1, _ctau1, _C1pa, nC1p_);
}
if (_caps & CAP_C1p)
Geodesic30<real>::C1pf(eps, _C1pa);
if (_caps & CAP_C2) {
_A2m1 = Geodesic30<real>::A2m1f(eps);
Geodesic30<real>::C2f(eps, _C2a);
_B21 = Geodesic30<real>::SinCosSeries(true, _ssig1, _csig1, _C2a, nC2_);
}
if (_caps & CAP_C3) {
g.C3f(eps, _C3a);
_A3c = -_f * _salp0 * g.A3f(eps);
_B31 = Geodesic30<real>::SinCosSeries(true, _ssig1, _csig1,
_C3a, nC3_-1);
}
if (_caps & CAP_C4) {
g.C4f(_k2, _C4a);
// Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0)
_A4 = Math::sq(_a) * _calp0 * _salp0 * g._e2;
_B41 = Geodesic30<real>::SinCosSeries(false, _ssig1, _csig1, _C4a, nC4_);
}
}
template<typename real>
real GeodesicLine30<real>::GenPosition(bool arcmode, real s12_a12,
unsigned outmask,
real& lat2, real& lon2, real& azi2,
real& s12, real& m12,
real& M12, real& M21,
real& S12)
const {
outmask &= _caps & OUT_ALL;
if (!( Init() && (arcmode || (_caps & DISTANCE_IN & OUT_ALL)) ))
// Uninitialized or impossible distance calculation requested
return Math::NaN<real>();
// Avoid warning about uninitialized B12.
real sig12, ssig12, csig12, B12 = 0, AB1 = 0;
if (arcmode) {
// Interpret s12_a12 as spherical arc length
sig12 = s12_a12 * Math::degree<real>();
real s12a = abs(s12_a12);
s12a -= 180 * floor(s12a / 180);
ssig12 = s12a == 0 ? 0 : sin(sig12);
csig12 = s12a == 90 ? 0 : cos(sig12);
} else {
// Interpret s12_a12 as distance
real
tau12 = s12_a12 / (_b * (1 + _A1m1)),
s = sin(tau12),
c = cos(tau12);
// tau2 = tau1 + tau12
B12 = - Geodesic30<real>::SinCosSeries(true, _stau1 * c + _ctau1 * s,
_ctau1 * c - _stau1 * s,
_C1pa, nC1p_);
sig12 = tau12 - (B12 - _B11);
ssig12 = sin(sig12);
csig12 = cos(sig12);
}
real omg12, lam12, lon12;
real ssig2, csig2, sbet2, cbet2, somg2, comg2, salp2, calp2;
// sig2 = sig1 + sig12
ssig2 = _ssig1 * csig12 + _csig1 * ssig12;
csig2 = _csig1 * csig12 - _ssig1 * ssig12;
if (outmask & (DISTANCE | REDUCEDLENGTH | GEODESICSCALE)) {
if (arcmode)
B12 = Geodesic30<real>::SinCosSeries(true, ssig2, csig2, _C1a, nC1_);
AB1 = (1 + _A1m1) * (B12 - _B11);
}
// sin(bet2) = cos(alp0) * sin(sig2)
sbet2 = _calp0 * ssig2;
// Alt: cbet2 = hypot(csig2, salp0 * ssig2);
cbet2 = hypot(_salp0, _calp0 * csig2);
if (cbet2 == 0)
// I.e., salp0 = 0, csig2 = 0. Break the degeneracy in this case
cbet2 = csig2 = Geodesic30<real>::tiny_;
// tan(omg2) = sin(alp0) * tan(sig2)
somg2 = _salp0 * ssig2; comg2 = csig2; // No need to normalize
// tan(alp0) = cos(sig2)*tan(alp2)
salp2 = _salp0; calp2 = _calp0 * csig2; // No need to normalize
// omg12 = omg2 - omg1
omg12 = atan2(somg2 * _comg1 - comg2 * _somg1,
comg2 * _comg1 + somg2 * _somg1);
if (outmask & DISTANCE)
s12 = arcmode ? _b * ((1 + _A1m1) * sig12 + AB1) : s12_a12;
if (outmask & LONGITUDE) {
lam12 = omg12 + _A3c *
( sig12 +
(Geodesic30<real>::SinCosSeries(true, ssig2, csig2, _C3a, nC3_-1)
- _B31));
lon12 = lam12 / Math::degree<real>();
lon12 = Math::AngNormalize(lon12);
lon2 = Math::AngNormalize(_lon1 + lon12);
}
if (outmask & LATITUDE)
lat2 = atan2(sbet2, _f1 * cbet2) / Math::degree<real>();
if (outmask & AZIMUTH)
// minus signs give range [-180, 180). 0- converts -0 to +0.
azi2 = 0 - atan2(-salp2, calp2) / Math::degree<real>();
if (outmask & (REDUCEDLENGTH | GEODESICSCALE)) {
real
ssig1sq = Math::sq(_ssig1),
ssig2sq = Math::sq( ssig2),
w1 = sqrt(1 + _k2 * ssig1sq),
w2 = sqrt(1 + _k2 * ssig2sq),
B22 = Geodesic30<real>::SinCosSeries(true, ssig2, csig2, _C2a, nC2_),
AB2 = (1 + _A2m1) * (B22 - _B21),
J12 = (_A1m1 - _A2m1) * sig12 + (AB1 - AB2);
if (outmask & REDUCEDLENGTH)
// Add parens around (_csig1 * ssig2) and (_ssig1 * csig2) to ensure
// accurate cancellation in the case of coincident points.
m12 = _b * ((w2 * (_csig1 * ssig2) - w1 * (_ssig1 * csig2))
- _csig1 * csig2 * J12);
if (outmask & GEODESICSCALE) {
M12 = csig12 + (_k2 * (ssig2sq - ssig1sq) * ssig2 / (w1 + w2)
- csig2 * J12) * _ssig1 / w1;
M21 = csig12 - (_k2 * (ssig2sq - ssig1sq) * _ssig1 / (w1 + w2)
- _csig1 * J12) * ssig2 / w2;
}
}
if (outmask & AREA) {
real
B42 = Geodesic30<real>::SinCosSeries(false, ssig2, csig2, _C4a, nC4_);
real salp12, calp12;
if (_calp0 == 0 || _salp0 == 0) {
// alp12 = alp2 - alp1, used in atan2 so no need to normalize
salp12 = salp2 * _calp1 - calp2 * _salp1;
calp12 = calp2 * _calp1 + salp2 * _salp1;
// The right thing appears to happen if alp1 = +/-180 and alp2 = 0, viz
// salp12 = -0 and alp12 = -180. However this depends on the sign
// being attached to 0 correctly. The following ensures the correct
// behavior.
if (salp12 == 0 && calp12 < 0) {
salp12 = Geodesic30<real>::tiny_ * _calp1;
calp12 = -1;
}
} else {
// tan(alp) = tan(alp0) * sec(sig)
// tan(alp2-alp1) = (tan(alp2) -tan(alp1)) / (tan(alp2)*tan(alp1)+1)
// = calp0 * salp0 * (csig1-csig2) / (salp0^2 + calp0^2 * csig1*csig2)
// If csig12 > 0, write
// csig1 - csig2 = ssig12 * (csig1 * ssig12 / (1 + csig12) + ssig1)
// else
// csig1 - csig2 = csig1 * (1 - csig12) + ssig12 * ssig1
// No need to normalize
salp12 = _calp0 * _salp0 *
(csig12 <= 0 ? _csig1 * (1 - csig12) + ssig12 * _ssig1 :
ssig12 * (_csig1 * ssig12 / (1 + csig12) + _ssig1));
calp12 = Math::sq(_salp0) + Math::sq(_calp0) * _csig1 * csig2;
}
S12 = _c2 * atan2(salp12, calp12) + _A4 * (B42 - _B41);
}
return arcmode ? s12_a12 : sig12 / Math::degree<real>();
}
template class GeodesicLine30<double>;
#if GEOGRAPHICLIB_HAVE_LONG_DOUBLE
template class GeodesicLine30<long double>;
#endif
} // namespace GeographicLib

View File

@@ -0,0 +1,593 @@
/**
* \file GeodesicLine30.hpp
* \brief Header for GeographicLib::GeodesicLine30 class
*
* Copyright (c) Charles Karney (2009-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#if !defined(GEOGRAPHICLIB_GEODESICLINEEXACT_HPP)
#define GEOGRAPHICLIB_GEODESICLINEEXACT_HPP 1
#include <GeographicLib/Constants.hpp>
#include "Geodesic30.hpp"
namespace GeographicLib {
/**
* \brief A geodesic line
*
* GeodesicLine30 facilitates the determination of a series of points on a
* single geodesic. The starting point (\e lat1, \e lon1) and the azimuth \e
* azi1 are specified in the constructor. GeodesicLine30.Position returns
* the location of point 2 a distance \e s12 along the geodesic.
* Alternatively GeodesicLine30.ArcPosition gives the position of point 2
* an arc length \e a12 along the geodesic.
*
* The default copy constructor and assignment operators work with this
* class. Similarly, a vector can be used to hold GeodesicLine30 objects.
*
* The calculations are accurate to better than 15 nm (15 nanometers). See
* Sec. 9 of
* <a href="https://arxiv.org/abs/1102.1215v1">arXiv:1102.1215v1</a> for
* details.
*
* The algorithms are described in
* - C. F. F. Karney,
* <a href="https://doi.org/10.1007/s00190-012-0578-z">
* Algorithms for geodesics</a>,
* J. Geodesy <b>87</b>, 43--55 (2013);
* DOI: <a href="https://doi.org/10.1007/s00190-012-0578-z">
* 10.1007/s00190-012-0578-z</a>;
* <a href="https://geographiclib.sourceforge.io/geod-addenda.html">
* addenda</a>.
* .
* For more information on geodesics see \ref geodesic.
**********************************************************************/
template<typename real>
class GeodesicLine30 {
private:
friend class Geodesic30<real>;
static const int nC1_ = Geodesic30<real>::nC1_;
static const int nC1p_ = Geodesic30<real>::nC1p_;
static const int nC2_ = Geodesic30<real>::nC2_;
static const int nC3_ = Geodesic30<real>::nC3_;
static const int nC4_ = Geodesic30<real>::nC4_;
real _lat1, _lon1, _azi1;
real _a, _f, _b, _c2, _f1, _salp0, _calp0, _k2,
_salp1, _calp1, _ssig1, _csig1, _stau1, _ctau1, _somg1, _comg1,
_A1m1, _A2m1, _A3c, _B11, _B21, _B31, _A4, _B41;
// index zero elements of _C1a, _C1pa, _C2a, _C3a are unused
real _C1a[nC1_ + 1], _C1pa[nC1p_ + 1], _C2a[nC2_ + 1], _C3a[nC3_],
_C4a[nC4_]; // all the elements of _C4a are used
unsigned _caps;
enum captype {
CAP_NONE = Geodesic30<real>::CAP_NONE,
CAP_C1 = Geodesic30<real>::CAP_C1,
CAP_C1p = Geodesic30<real>::CAP_C1p,
CAP_C2 = Geodesic30<real>::CAP_C2,
CAP_C3 = Geodesic30<real>::CAP_C3,
CAP_C4 = Geodesic30<real>::CAP_C4,
CAP_ALL = Geodesic30<real>::CAP_ALL,
OUT_ALL = Geodesic30<real>::OUT_ALL,
};
public:
/**
* Bit masks for what calculations to do. They signify to the
* GeodesicLine30::GeodesicLine30 constructor and to
* Geodesic30::Line what capabilities should be included in the
* GeodesicLine30 object. This is merely a duplication of
* Geodesic30::mask.
**********************************************************************/
enum mask {
/**
* No capabilities, no output.
* @hideinitializer
**********************************************************************/
NONE = Geodesic30<real>::NONE,
/**
* Calculate latitude \e lat2. (It's not necessary to include this as a
* capability to GeodesicLine30 because this is included by default.)
* @hideinitializer
**********************************************************************/
LATITUDE = Geodesic30<real>::LATITUDE,
/**
* Calculate longitude \e lon2.
* @hideinitializer
**********************************************************************/
LONGITUDE = Geodesic30<real>::LONGITUDE,
/**
* Calculate azimuths \e azi1 and \e azi2. (It's not necessary to
* include this as a capability to GeodesicLine30 because this is
* included by default.)
* @hideinitializer
**********************************************************************/
AZIMUTH = Geodesic30<real>::AZIMUTH,
/**
* Calculate distance \e s12.
* @hideinitializer
**********************************************************************/
DISTANCE = Geodesic30<real>::DISTANCE,
/**
* Allow distance \e s12 to be used as input in the direct geodesic
* problem.
* @hideinitializer
**********************************************************************/
DISTANCE_IN = Geodesic30<real>::DISTANCE_IN,
/**
* Calculate reduced length \e m12.
* @hideinitializer
**********************************************************************/
REDUCEDLENGTH = Geodesic30<real>::REDUCEDLENGTH,
/**
* Calculate geodesic scales \e M12 and \e M21.
* @hideinitializer
**********************************************************************/
GEODESICSCALE = Geodesic30<real>::GEODESICSCALE,
/**
* Calculate area \e S12.
* @hideinitializer
**********************************************************************/
AREA = Geodesic30<real>::AREA,
/**
* All capabilities, calculate everything.
* @hideinitializer
**********************************************************************/
ALL = Geodesic30<real>::ALL,
};
/** \name Constructors
**********************************************************************/
///@{
/**
* Constructor for a geodesic line staring at latitude \e lat1, longitude
* \e lon1, and azimuth \e azi1 (all in degrees).
*
* @param[in] g A Geodesic30 object used to compute the necessary
* information about the GeodesicLine30.
* @param[in] lat1 latitude of point 1 (degrees).
* @param[in] lon1 longitude of point 1 (degrees).
* @param[in] azi1 azimuth at point 1 (degrees).
* @param[in] caps bitor'ed combination of GeodesicLine30::mask values
* specifying the capabilities the GeodesicLine30 object should
* possess, i.e., which quantities can be returned in calls to
* GeodesicLine::Position.
*
* \e lat1 should be in the range [&minus;90&deg;, 90&deg;]; \e lon1 and \e
* azi1 should be in the range [&minus;540&deg;, 540&deg;).
*
* The GeodesicLine30::mask values are
* - \e caps |= GeodesicLine30::LATITUDE for the latitude \e lat2; this
* is added automatically
* - \e caps |= GeodesicLine30::LONGITUDE for the latitude \e lon2
* - \e caps |= GeodesicLine30::AZIMUTH for the latitude \e azi2; this is
* added automatically
* - \e caps |= GeodesicLine30::DISTANCE for the distance \e s12
* - \e caps |= GeodesicLine30::REDUCEDLENGTH for the reduced length \e
m12
* - \e caps |= GeodesicLine30::GEODESICSCALE for the geodesic scales \e
* M12 and \e M21
* - \e caps |= GeodesicLine30::AREA for the area \e S12
* - \e caps |= GeodesicLine30::DISTANCE_IN permits the length of the
* geodesic to be given in terms of \e s12; without this capability the
* length can only be specified in terms of arc length.
* .
* The default value of \e caps is GeodesicLine30::ALL which turns on
* all the capabilities.
*
* If the point is at a pole, the azimuth is defined by keeping the \e lon1
* fixed and writing \e lat1 = &plusmn;(90&deg; &minus; &epsilon;) and
* taking the limit &epsilon; &rarr; 0+.
**********************************************************************/
GeodesicLine30(const Geodesic30<real>& g, real lat1, real lon1, real azi1,
unsigned caps = ALL)
;
/**
* A default constructor. If GeodesicLine30::Position is called on the
* resulting object, it returns immediately (without doing any
* calculations). The object can be set with a call to
* Geodesic30::Line. Use Init() to test whether object is still in this
* uninitialized state.
**********************************************************************/
GeodesicLine30() : _caps(0U) {}
///@}
/** \name Position in terms of distance
**********************************************************************/
///@{
/**
* Compute the position of point 2 which is a distance \e s12 (meters)
* from point 1.
*
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
* signed.
* @param[out] lat2 latitude of point 2 (degrees).
* @param[out] lon2 longitude of point 2 (degrees); requires that the
* GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::LONGITUDE.
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
* @param[out] m12 reduced length of geodesic (meters); requires that the
* GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::REDUCEDLENGTH.
* @param[out] M12 geodesic scale of point 2 relative to point 1
* (dimensionless); requires that the GeodesicLine30 object was
* constructed with \e caps |= GeodesicLine30::GEODESICSCALE.
* @param[out] M21 geodesic scale of point 1 relative to point 2
* (dimensionless); requires that the GeodesicLine30 object was
* constructed with \e caps |= GeodesicLine30::GEODESICSCALE.
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
* that the GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::AREA.
* @return \e a12 arc length of between point 1 and point 2 (degrees).
*
* The values of \e lon2 and \e azi2 returned are in the range
* [&minus;180&deg;, 180&deg;).
*
* The GeodesicLine30 object \e must have been constructed with \e caps
* |= GeodesicLine30::DISTANCE_IN; otherwise Math::NaN() is returned and
* no parameters are set. Requesting a value which the GeodesicLine30
* object is not capable of computing is not an error; the corresponding
* argument will not be altered.
*
* The following functions are overloaded versions of
* GeodesicLine30::Position which omit some of the output parameters.
* Note, however, that the arc length is always computed and returned as
* the function value.
**********************************************************************/
real Position(real s12,
real& lat2, real& lon2, real& azi2,
real& m12, real& M12, real& M21,
real& S12) const {
real t;
return GenPosition(false, s12,
LATITUDE | LONGITUDE | AZIMUTH |
REDUCEDLENGTH | GEODESICSCALE | AREA,
lat2, lon2, azi2, t, m12, M12, M21, S12);
}
/**
* See the documentation for GeodesicLine30::Position.
**********************************************************************/
real Position(real s12, real& lat2, real& lon2) const {
real t;
return GenPosition(false, s12,
LATITUDE | LONGITUDE,
lat2, lon2, t, t, t, t, t, t);
}
/**
* See the documentation for GeodesicLine30::Position.
**********************************************************************/
real Position(real s12, real& lat2, real& lon2,
real& azi2) const {
real t;
return GenPosition(false, s12,
LATITUDE | LONGITUDE | AZIMUTH,
lat2, lon2, azi2, t, t, t, t, t);
}
/**
* See the documentation for GeodesicLine30::Position.
**********************************************************************/
real Position(real s12, real& lat2, real& lon2,
real& azi2, real& m12) const {
real t;
return GenPosition(false, s12,
LATITUDE | LONGITUDE |
AZIMUTH | REDUCEDLENGTH,
lat2, lon2, azi2, t, m12, t, t, t);
}
/**
* See the documentation for GeodesicLine30::Position.
**********************************************************************/
real Position(real s12, real& lat2, real& lon2,
real& azi2, real& M12, real& M21)
const {
real t;
return GenPosition(false, s12,
LATITUDE | LONGITUDE |
AZIMUTH | GEODESICSCALE,
lat2, lon2, azi2, t, t, M12, M21, t);
}
/**
* See the documentation for GeodesicLine30::Position.
**********************************************************************/
real Position(real s12,
real& lat2, real& lon2, real& azi2,
real& m12, real& M12, real& M21)
const {
real t;
return GenPosition(false, s12,
LATITUDE | LONGITUDE | AZIMUTH |
REDUCEDLENGTH | GEODESICSCALE,
lat2, lon2, azi2, t, m12, M12, M21, t);
}
///@}
/** \name Position in terms of arc length
**********************************************************************/
///@{
/**
* Compute the position of point 2 which is an arc length \e a12 (degrees)
* from point 1.
*
* @param[in] a12 arc length between point 1 and point 2 (degrees); it can
* be signed.
* @param[out] lat2 latitude of point 2 (degrees).
* @param[out] lon2 longitude of point 2 (degrees); requires that the
* GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::LONGITUDE.
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
* @param[out] s12 distance between point 1 and point 2 (meters); requires
* that the GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::DISTANCE.
* @param[out] m12 reduced length of geodesic (meters); requires that the
* GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::REDUCEDLENGTH.
* @param[out] M12 geodesic scale of point 2 relative to point 1
* (dimensionless); requires that the GeodesicLine30 object was
* constructed with \e caps |= GeodesicLine30::GEODESICSCALE.
* @param[out] M21 geodesic scale of point 1 relative to point 2
* (dimensionless); requires that the GeodesicLine30 object was
* constructed with \e caps |= GeodesicLine30::GEODESICSCALE.
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
* that the GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::AREA.
*
* The values of \e lon2 and \e azi2 returned are in the range
* [&minus;180&deg;, 180&deg;).
*
* Requesting a value which the GeodesicLine30 object is not capable of
* computing is not an error; the corresponding argument will not be
* altered.
*
* The following functions are overloaded versions of
* GeodesicLine30::ArcPosition which omit some of the output parameters.
**********************************************************************/
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
real& s12, real& m12, real& M12, real& M21,
real& S12) const {
GenPosition(true, a12,
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
REDUCEDLENGTH | GEODESICSCALE | AREA,
lat2, lon2, azi2, s12, m12, M12, M21, S12);
}
/**
* See the documentation for GeodesicLine30::ArcPosition.
**********************************************************************/
void ArcPosition(real a12, real& lat2, real& lon2)
const {
real t;
GenPosition(true, a12,
LATITUDE | LONGITUDE,
lat2, lon2, t, t, t, t, t, t);
}
/**
* See the documentation for GeodesicLine30::ArcPosition.
**********************************************************************/
void ArcPosition(real a12,
real& lat2, real& lon2, real& azi2)
const {
real t;
GenPosition(true, a12,
LATITUDE | LONGITUDE | AZIMUTH,
lat2, lon2, azi2, t, t, t, t, t);
}
/**
* See the documentation for GeodesicLine30::ArcPosition.
**********************************************************************/
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
real& s12) const {
real t;
GenPosition(true, a12,
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE,
lat2, lon2, azi2, s12, t, t, t, t);
}
/**
* See the documentation for GeodesicLine30::ArcPosition.
**********************************************************************/
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
real& s12, real& m12) const {
real t;
GenPosition(true, a12,
LATITUDE | LONGITUDE | AZIMUTH |
DISTANCE | REDUCEDLENGTH,
lat2, lon2, azi2, s12, m12, t, t, t);
}
/**
* See the documentation for GeodesicLine30::ArcPosition.
**********************************************************************/
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
real& s12, real& M12, real& M21)
const {
real t;
GenPosition(true, a12,
LATITUDE | LONGITUDE | AZIMUTH |
DISTANCE | GEODESICSCALE,
lat2, lon2, azi2, s12, t, M12, M21, t);
}
/**
* See the documentation for GeodesicLine30::ArcPosition.
**********************************************************************/
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
real& s12, real& m12, real& M12, real& M21)
const {
real t;
GenPosition(true, a12,
LATITUDE | LONGITUDE | AZIMUTH |
DISTANCE | REDUCEDLENGTH | GEODESICSCALE,
lat2, lon2, azi2, s12, m12, M12, M21, t);
}
///@}
/** \name The general position function.
**********************************************************************/
///@{
/**
* The general position function. GeodesicLine30::Position and
* GeodesicLine30::ArcPosition are defined in terms of this function.
*
* @param[in] arcmode boolean flag determining the meaning of the second
* parameter; if arcmode is false, then the GeodesicLine30 object must
* have been constructed with \e caps |= GeodesicLine30::DISTANCE_IN.
* @param[in] s12_a12 if \e arcmode is false, this is the distance between
* point 1 and point 2 (meters); otherwise it is the arc length between
* point 1 and point 2 (degrees); it can be signed.
* @param[in] outmask a bitor'ed combination of GeodesicLine30::mask
* values specifying which of the following parameters should be set.
* @param[out] lat2 latitude of point 2 (degrees).
* @param[out] lon2 longitude of point 2 (degrees); requires that the
* GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::LONGITUDE.
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
* @param[out] s12 distance between point 1 and point 2 (meters); requires
* that the GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::DISTANCE.
* @param[out] m12 reduced length of geodesic (meters); requires that the
* GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::REDUCEDLENGTH.
* @param[out] M12 geodesic scale of point 2 relative to point 1
* (dimensionless); requires that the GeodesicLine30 object was
* constructed with \e caps |= GeodesicLine30::GEODESICSCALE.
* @param[out] M21 geodesic scale of point 1 relative to point 2
* (dimensionless); requires that the GeodesicLine30 object was
* constructed with \e caps |= GeodesicLine30::GEODESICSCALE.
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
* that the GeodesicLine30 object was constructed with \e caps |=
* GeodesicLine30::AREA.
* @return \e a12 arc length of between point 1 and point 2 (degrees).
*
* The GeodesicLine30::mask values possible for \e outmask are
* - \e outmask |= GeodesicLine30::LATITUDE for the latitude \e lat2.
* - \e outmask |= GeodesicLine30::LONGITUDE for the latitude \e lon2.
* - \e outmask |= GeodesicLine30::AZIMUTH for the latitude \e azi2.
* - \e outmask |= GeodesicLine30::DISTANCE for the distance \e s12.
* - \e outmask |= GeodesicLine30::REDUCEDLENGTH for the reduced length
* \e m12.
* - \e outmask |= GeodesicLine30::GEODESICSCALE for the geodesic scales
* \e M12 and \e M21.
* - \e outmask |= GeodesicLine30::AREA for the area \e S12.
* .
* Requesting a value which the GeodesicLine30 object is not capable of
* computing is not an error; the corresponding argument will not be
* altered. Note, however, that the arc length is always computed and
* returned as the function value.
**********************************************************************/
real GenPosition(bool arcmode, real s12_a12, unsigned outmask,
real& lat2, real& lon2, real& azi2,
real& s12, real& m12, real& M12, real& M21,
real& S12) const;
///@}
/** \name Inspector functions
**********************************************************************/
///@{
/**
* @return true if the object has been initialized.
**********************************************************************/
bool Init() const { return _caps != 0U; }
/**
* @return \e lat1 the latitude of point 1 (degrees).
**********************************************************************/
real Latitude() const
{ return Init() ? _lat1 : Math::NaN<real>(); }
/**
* @return \e lon1 the longitude of point 1 (degrees).
**********************************************************************/
real Longitude() const
{ return Init() ? _lon1 : Math::NaN<real>(); }
/**
* @return \e azi1 the azimuth (degrees) of the geodesic line at point 1.
**********************************************************************/
real Azimuth() const
{ return Init() ? _azi1 : Math::NaN<real>(); }
/**
* @return \e azi0 the azimuth (degrees) of the geodesic line as it crosses
* the equator in a northward direction.
**********************************************************************/
real EquatorialAzimuth() const {
using std::atan2;
return Init() ?
atan2(_salp0, _calp0) / Math::degree<real>() : Math::NaN<real>();
}
/**
* @return \e a1 the arc length (degrees) between the northward equatorial
* crossing and point 1.
**********************************************************************/
real EquatorialArc() const {
using std::atan2;
return Init() ?
atan2(_ssig1, _csig1) / Math::degree<real>() : Math::NaN<real>();
}
/**
* @return \e a the equatorial radius of the ellipsoid (meters). This is
* the value inherited from the Geodesic30 object used in the
* constructor.
**********************************************************************/
real EquatorialRadius() const
{ return Init() ? _a : Math::NaN<real>(); }
/**
* @return \e f the flattening of the ellipsoid. This is the value
* inherited from the Geodesic30 object used in the constructor.
**********************************************************************/
real Flattening() const
{ return Init() ? _f : Math::NaN<real>(); }
/// \cond SKIP
/**
* <b>DEPRECATED</b>
* @return \e r the inverse flattening of the ellipsoid.
**********************************************************************/
real InverseFlattening() const
{ return Init() ? 1/_f : Math::NaN<real>(); }
/// \endcond
/**
* @return \e caps the computational capabilities that this object was
* constructed with. LATITUDE and AZIMUTH are always included.
**********************************************************************/
unsigned Capabilities() const { return _caps; }
/**
* @param[in] testcaps a set of bitor'ed GeodesicLine30::mask values.
* @return true if the GeodesicLine30 object has all these capabilities.
**********************************************************************/
bool Capabilities(unsigned testcaps) const {
testcaps &= OUT_ALL;
return (_caps & testcaps) == testcaps;
}
///@}
};
} // namespace GeographicLib
#endif // GEOGRAPHICLIB_GEODESICLINEEXACT_HPP

View File

@@ -0,0 +1,240 @@
#include <fstream>
#include <iostream>
#include <iomanip>
#include <vector>
#include <ctime>
#include <GeographicLib/MagneticModel.hpp>
#include <GeographicLib/SphericalHarmonic.hpp>
#include <GeographicLib/CircularEngine.hpp>
#include <GeographicLib/MagneticCircle.hpp>
#include <GeographicLib/NormalGravity.hpp>
#include <GeographicLib/GravityModel.hpp>
#include <GeographicLib/GravityCircle.hpp>
#include <GeographicLib/Utility.hpp>
#include <GeographicLib/Geoid.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional and enum-float expressions,
// potentially uninitialized local variables, and unreachable code
# pragma warning (disable: 4127 5055 4701 4702)
#endif
using namespace std;
using namespace GeographicLib;
int main() {
typedef GeographicLib::Math::real real;
try {
{
cout << fixed;
// GravityModel egm("egm2008");
// GravityModel egm("egm84-mod","/home/ckarney/geographiclib/gravity");
GravityModel egm("egm2008");
real lat, lon;
while (cin >> lat >> lon) {
real g = egm.GeoidHeight(lat, lon);
cout << setprecision(6)
<< setw(12) << lat
<< setw(12) << lon
<< setprecision(12) << setw(20)
<< g << "\n";
/*
real h;
cin >> h;
real Dg01, xi, eta;
egm.Anomaly(lat, lon, h, Dg01, xi, eta);
Dg01 *= 1e5;
xi *= Math::ds;
eta *= Math::ds;
cout << setprecision(12) << g << " " << Dg01 << " "
<< xi << " " << eta << "\n";
*/
}
return 0;
}
{
cout << fixed << setprecision(6);
GravityModel egm("egm2008");
real lat, lon;
while (cin >> lat >> lon) {
real
h = 0,
gamma = egm.ReferenceEllipsoid().SurfaceGravity(lat),
U0 = egm.ReferenceEllipsoid().SurfacePotential();
real deltax, deltay, deltaz;
real T = egm.Disturbance(lat, lon, h, deltax, deltay, deltaz);
h = T/gamma;
real h0 = h;
// cout << "I " << U0 << " " << h << "\n";
for (int i = 0; i < 10; ++i) {
real gx, gy, gz;
real W = egm.Gravity(lat, lon, h, gx, gy, gz);
h += (W-U0)/gamma;
if (i == 9)
cout << i << " " << W << " " << h << " " << h - h0 << "\n";
}
}
return 0;
}
if (false) {
{
cout << fixed;
Geoid egm("egm2008-1");
real
lat0 = real(89.234412), lon0 = real(-179.234257),
dl = 180/real(1123), h = 0;
for (int j = 0; j < 2000; ++j) {
real lat = lat0 - j*dl/2;
for (int i = 0; i < 4000; ++i) {
real lon = lon0 + i * dl/2;
// cout << setprecision(3) << lon << " "
// << setprecision(12) << egm.GeoidHeight(lat,lon) << "\n";
h+=egm(lat,lon);
}
}
cout << setprecision(3) << 0/*lon*/ << " "
<< setprecision(12) << h/*c.GeoidHeight(lon)*/ << "\n";
return 0;
}
{
cout << fixed;
GravityModel egm("egm2008","/home/ckarney/geographiclib/gravity");
real lat = 33, lon0 = 44, dlon = real(0.001);
GravityCircle c = egm.Circle(lat, 0.0);
for (int i = 0; i < 100000; ++i) {
real lon = lon0 + i * dlon;
// cout << setprecision(3) << lon << " "
// << setprecision(12) << egm.GeoidHeight(lat,lon) << "\n";
cout << setprecision(3) << lon << " "
<< setprecision(12) << c.GeoidHeight(lon) << "\n";
}
return 0;
}
}
if (true) {
cout << setprecision(8);
// MagneticModel mag("/scratch/WMM2010NewLinux/WMM2010ISO.COF");
MagneticModel mag1("wmm2010");
MagneticModel mag2("emm2010");
MagneticModel mag3("igrf11");
real lat, lon, h, t, bx, by, bz, bxt, byt, bzt;
while (cin >> t >> lat >> lon >> h) {
mag1(t, lat, lon, h, bx, by, bz, bxt, byt, bzt);
cout << by << " " << bx << " " << -bz << " "
<< byt << " " << bxt << " " << -bzt << "\n";
MagneticCircle circ1(mag1.Circle(t, lat, h));
circ1(lon, bx, by, bz, bxt, byt, bzt);
cout << by << " " << bx << " " << -bz << " "
<< byt << " " << bxt << " " << -bzt << "\n";
/*
mag2(t, lat, lon, h, bx, by, bz, bxt, byt, bzt);
cout << by << " " << bx << " " << -bz << " "
<< byt << " " << bxt << " " << -bzt << "\n";
MagneticCircle circ2(mag2.Circle(t, lat, h));
circ2(lon, bx, by, bz, bxt, byt, bzt);
cout << by << " " << bx << " " << -bz << " "
<< byt << " " << bxt << " " << -bzt << "\n";
mag3(t, lat, lon, h, bx, by, bz, bxt, byt, bzt);
cout << by << " " << bx << " " << -bz << " "
<< byt << " " << bxt << " " << -bzt << "\n";
MagneticCircle circ3(mag3.Circle(t, lat, h));
circ3(lon, bx, by, bz, bxt, byt, bzt);
cout << by << " " << bx << " " << -bz << " "
<< byt << " " << bxt << " " << -bzt << "\n";
*/
}
return 0;
}
int type = 2;
int N;
string name;
switch (type) {
case 0:
N = 360;
name = "data_EGM96_360.dat";
break;
case 1:
N = 2190;
name = "data_EGM2008_2190.dat";
break;
case 2:
default:
N = 5;
name = "harmtest.dat";
break;
}
int k = ((N + 1) * (N + 2)) / 2;
vector<real> C(k);
vector<real> S(k);
name = "/scratch/egm2008/harm/" + name;
{
ifstream f(name.c_str(), ios::binary);
if (!f.good())
throw GeographicErr("Cannot open coefficient file");
f.read(reinterpret_cast<char*>(&C[0]), k * sizeof(real));
f.read(reinterpret_cast<char*>(&S[0]), k * sizeof(real));
}
// for (int i = 0; i < k; ++i)
// cout << i << " " << C[i] << " " << S[i] << "\n";
real lat, lon;
cout << setprecision(17);
real a = real(0.9L), r = real(1.2L);
SphericalHarmonic harm(C, S, N, a, SphericalHarmonic::FULL);
vector<real> Z;
while (cin >> lat >> lon) {
real
phi = Math::degree() * lat,
lam = Math::degree() * lon,
x = r * (abs(lat) == 90 ? 0 : cos(phi)) * cos(lam),
y = r * (abs(lat) == 90 ? 0 : cos(phi)) * sin(lam),
z = r * sin(phi);
real
d = real(1e-7L),
dx1 = (harm(x+d, y, z) - harm(x-d, y, z))/(2*d),
dy1 = (harm(x, y+d, z) - harm(x, y-d, z))/(2*d),
dz1 = (harm(x, y, z+d) - harm(x, y, z-d))/(2*d),
dx2, dy2, dz2;
real
v1 = harm(x, y, z);
real
v2 = harm(x, y, z, dx2, dy2, dz2);
cout << v1 << " " << v2 << "\n";
cout << dx1 << " " << dx2 << "\n"
<< dy1 << " " << dy2 << "\n"
<< dz1 << " " << dz2 << "\n";
CircularEngine circ1 = harm.Circle(r * cos(phi), z, false);
CircularEngine circ2 = harm.Circle(r * cos(phi), z, true);
real v3, dx3, dy3, dz3;
v3 = circ2(lon, dx3, dy3, dz3);
cout << v3 << " " << dx3 << " " << dy3 << " " << dz3 << "\n";
}
cout << "start timing" << endl;
real phi, lam, sum, z, p, dx, dy, dz;
lat = 33; phi = lat * Math::degree();
z = r * sin(phi);
p = r * cos(phi);
sum = 0;
for (int i = 0; i < 100; ++i) {
lam = (44 + real(0.01)*i) * Math::degree();
sum += harm(p * cos(lam), p * sin(lam), z, dx, dy, dz);
}
cout << "sum a " << sum << endl;
CircularEngine circ(harm.Circle(p, z, true));
sum = 0;
for (int i = 0; i < 100000; ++i) {
lon = (44 + real(0.01)*i);
sum += circ(lon, dx, dy, dz);
}
cout << "sum b " << sum << endl;
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
cerr << "Caught unknown exception\n";
return 1;
}
return 0;
}

View File

@@ -0,0 +1,403 @@
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <limits>
#include <algorithm>
#include <boost/numeric/odeint.hpp>
#include <GeographicLib/Math.hpp>
#include <GeographicLib/Utility.hpp>
#include <GeographicLib/NormalGravity.hpp>
using namespace GeographicLib;
namespace ode = boost::numeric::odeint;
typedef Math::real real;
typedef std::array<real, 2> point;
// Initialize with the end points of a line
class LineDistance {
point _a, _b;
real _l, _nx, _ny;
public:
LineDistance(const point& a, const point& b);
real Distance(const point& p) const;
// negative on left of line, pos on right
real Displacement(const point& p) const;
};
// Use Ramer-Douglas-Peucker to simplify a polyline
class LineSimplifier {
// Simplify range [a,b]
static void InternalSimplify(std::vector<point>& p, unsigned a, unsigned b,
real thresh);
public:
static void Simplify(std::vector<point>& p, real thresh);
};
inline LineDistance::LineDistance(const point& a, const point& b)
: _a(a), _b(b) {
using std::hypot;
real dx = _b[0] - _a[0], dy = _b[1] - _a[1];
_l = hypot(dx, dy);
if (_l > std::numeric_limits<real>::epsilon()) {
_nx = dx / _l; _ny = dy / _l;
} else {
_l = 0; _nx = 1; _ny = 0;
}
}
inline real LineDistance::Distance(const point& p) const {
using std::abs; using std::hypot;
real x = p[0] - _a[0], y = p[1] - _a[1];
if (_l != 0) {
real X = x * _nx + y * _ny, Y = abs(x * _ny - y * _nx);
X = X < 0 ? -X : (X > _l ? X - _l : 0);
return X != 0 ? hypot(X, Y) : Y;
} else
return hypot(x, y);
}
inline real LineDistance::Displacement(const point& p) const {
real x = p[0] - _a[0], y = p[1] - _a[1];
return x * _ny - y * _nx;
}
inline void LineSimplifier::Simplify(std::vector<point>& p, real thresh) {
using std::isnan;
unsigned n = p.size();
InternalSimplify(p, 0, n-1, thresh);
unsigned i = 0, j = 0;
while (i < n) { // Squeeze out nans
if (!isnan(p[i][0])) { p[j] = p[i]; ++j; }
++i;
}
p.resize(j);
}
void LineSimplifier::InternalSimplify(std::vector<point>& p,
unsigned a, unsigned b,
real thresh) {
if (b - a + 1 <= 2) return;
// Assume b > a+1, thresh > 0
real maxdist = -1;
unsigned maxind = (a + b) / 2; // initial value isn't used
LineDistance dist(p[a], p[b]);
for (unsigned i = a + 1; i <= b - 1; ++i) {
real d = dist.Distance(p[i]);
if (d > maxdist) { maxdist = d; maxind = i; }
}
if (maxdist > thresh) {
InternalSimplify(p, a, maxind, thresh);
InternalSimplify(p, maxind, b, thresh);
} else {
for (unsigned i = a+1; i <= b-1; ++i)
p[i][0] = Math::NaN();
}
}
class PointTest {
real _xmin, _xmax, _ymin, _ymax;
public:
PointTest(real xmin, real xmax, real ymin, real ymax)
: _xmin(xmin)
, _xmax(xmax)
, _ymin(ymin)
, _ymax(ymax) {}
bool operator() (const point &p) const {
return p[0] >= _xmin && p[0] <= _xmax && p[1] >= _ymin && p[1] <= _ymax;
}
};
class GravityInt {
const NormalGravity& _grav;
unsigned _dir;
public:
GravityInt(const NormalGravity& grav, unsigned dir)
: _grav(grav)
, _dir(dir & 3u)
{}
void operator() (const point& p, point &d, const real /*t*/) const {
real Y = 0, gX, gY, gZ;
_grav.U(p[0], Y, p[1], gX, gY, gZ);
Math::norm(gX, gZ);
switch (_dir) {
case 0: d[0] = gX; d[1] = gZ; break; // parallel to g
case 1: d[0] = -gZ; d[1] = gX; break; // counterclockwise 90d from g
case 2: d[0] = -gX; d[1] = -gZ; break; // antiparallel to g
case 3:
default: d[0] = gZ; d[1] = -gX; break; // clockwise 90d from g
}
}
};
class GravityFollow {
public:
static void follow(const GravityInt& sys, const point& p0, real t0, real ds,
std::vector<point>& points, const PointTest& box) {
ode::result_of::make_dense_output
< ode::runge_kutta_dopri5< point, real > >::type integrator =
ode::make_dense_output(real(1.0e-8), real(0*1.0e-8),
ode::runge_kutta_dopri5< point, real >() );
integrator.initialize(p0, t0, real(1e-2));
integrator.do_step(sys);
int n = 1, i = 1;
point out;
while (true) {
real tout = i * ds;
while (integrator.current_time() < tout) {
integrator.do_step(sys); ++n;
}
integrator.calc_state(tout, out);
points.push_back(out);
if (!box(out)) break;
++i;
}
}
};
// Evaluate gravity potential or gradient along 1 axis
class GravityEval {
const NormalGravity& _grav;
bool _zaxis, _grad;
real _disp;
public:
GravityEval(const NormalGravity& grav, bool zaxis, bool grad, real disp)
: _grav(grav)
, _zaxis(zaxis)
, _grad(grad)
, _disp(disp) {};
real operator() (real v) const {
real
X = _zaxis ? _disp : v,
Y = 0,
Z = _zaxis ? v : _disp,
gX, gY, gZ,
U = _grav.U(X, Y, Z, gX, gY, gZ);
return _grad ? gX : U;
}
};
class Interpolator {
private:
int _maxit;
real _eps;
public:
Interpolator()
: _maxit(20), _eps(sqrt(std::numeric_limits<real>::epsilon())) {}
real operator() (const GravityEval& gravfun,
real x0, real x1, real val) {
using std::abs;
real y0 = gravfun(x0) - val, y1;
for (int i = 0, trip = 0; i < _maxit; ++i) {
y1 = gravfun(x1) - val;
if (y1 == y0) break;
real x2 = x1 - y1 * (x1 - x0) / (y1 - y0);
x0 = x1; x1 = x2; y0 = y1;
if (abs(x0 - x1) <= _eps) ++trip;
if (trip > 2) break;
}
return x1;
}
};
void dump(const std::vector<point>& points) {
for (auto p = points.begin(); p != points.end(); ++p) {
std::cout << (*p)[0] << "," << (*p)[1] << ";\n";
}
}
int main() {
Utility::set_digits();
using std::sqrt;
real a = 1, GM = 1, omega = 3/Math::real(10), f = 2/Math::real(10);
real gX, gY, gZ, b = (1 - f) * a, E = a * sqrt(f * (2 - f));
real thresh = real(0.5e-3);
NormalGravity grav(a, GM, omega, f, true);
real xmax = 3, ymax = 2;
PointTest box(0, xmax, 0, ymax);
Interpolator intpol;
real
X0 = a,
U0 = grav.U(X0, 0, 0, gX, gY, gZ),
Uc = grav.U(0, 0, 0, gX, gY, gZ);
real Xnull, Unull;
{
GravityEval eval(grav, false, true, 0);
Xnull = intpol(eval, 1, 2, 0);
Unull = grav.U(Xnull, 0, 0, gX, gY, gZ);
}
int ndiv = 20;
real del = (U0 - Unull) / 20;
std::cout << std::setprecision(6);
std::cout << "a=" << a << "; b=" << b << "; Rnull=" << Xnull
<< "; xmax=" << xmax << "; ymax=" << ymax << ";\n";
std::cout << "q={}; p={}; qa={}; pa={};\n";
std::vector<point> points;
point p0;
int k = 0;
for (int i = 0; i <= 90; i += 10) {
points.clear();
real s, c;
Math::sincosd(real(i), s, c);
p0[0] = a * c; p0[1] = b * s;
points.push_back(p0);
if (i == 0) {
p0[0] = xmax; p0[1] = 0;
points.push_back(p0);
} else if (i == 90) {
p0[0] = 0; p0[1] = ymax;
points.push_back(p0);
} else {
GravityInt sys(grav, 2u);
GravityFollow::follow(sys, p0, real(0), 1/real(100), points, box);
}
LineSimplifier::Simplify(points, thresh);
std::cout << "q{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
{
points.clear();
p0[0] = Xnull; p0[1] = 0;
points.push_back(p0);
p0[0] = Xnull; p0[1] = real(0.001);
points.push_back(p0);
GravityInt sys(grav, 2u);
GravityFollow::follow(sys, p0, real(0), 1/real(100), points, box);
LineSimplifier::Simplify(points, thresh);
std::cout << "q{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
for (int i = 1; i <= 5; ++i) {
points.clear();
p0[0] = xmax;
p0[1] = real(i == 1 ? 0.45 :
(i == 2 ? 0.9 :
(i == 3 ? 1.25 :
(i == 4 ? 1.6 : 1.9))));
points.push_back(p0);
if (!box(p0)) break;
GravityInt sys(grav, 2u);
GravityFollow::follow(sys, p0, real(0), 1/real(100), points, box);
LineSimplifier::Simplify(points, thresh);
std::cout << "q{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
k = 0;
for (int i = 0; i <= 90; i += 10) {
points.clear();
real s, c;
Math::sincosd(real(i), s, c);
p0[0] = a * c; p0[1] = b * s;
points.push_back(p0);
if (i == 0) {
p0[0] = E; p0[1] = 0;
points.push_back(p0);
} else if (i == 90) {
p0[0] = 0; p0[1] = 0;
points.push_back(p0);
} else {
GravityInt sys(grav, 0u);
GravityFollow::follow(sys, p0, real(0), 1/real(100), points, box);
}
LineSimplifier::Simplify(points, thresh);
std::cout << "qa{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
k = 0;
{
GravityEval eval(grav, false, false, 0);
for (int i = 0; i < ndiv; ++i) {
points.clear();
real U = U0 - del * i;
p0[0] = intpol(eval, X0, Xnull, U); p0[1] = 0;
points.push_back(p0);
GravityInt sysa(grav, 3u);
GravityFollow::follow(sysa, p0, real(0), 1/real(100), points, box);
LineSimplifier::Simplify(points, thresh);
std::cout << "p{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
for (int i = ndiv - 1;; --i) {
points.clear();
real U = U0 - del * i;
p0[0] = intpol(eval, Xnull + 3, Xnull, U); p0[1] = 0;
if (!box(p0)) break;
points.push_back(p0);
GravityInt sysa(grav, 1u);
GravityFollow::follow(sysa, p0, real(0), 1/real(100), points, box);
LineSimplifier::Simplify(points, thresh);
std::cout << "p{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
}
{
GravityEval eval(grav, true, false, 0);
for (int i = ndiv + 1;; ++i) {
points.clear();
real U = U0 - del * i;
p0[1] = intpol(eval, X0, Xnull, U); p0[0] = 0;
if (!box(p0)) break;
points.push_back(p0);
GravityInt sysa(grav, 1u);
GravityFollow::follow(sysa, p0, real(0), 1/real(100), points, box);
LineSimplifier::Simplify(points, thresh);
std::cout << "p{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
}
{
real dy = real(0.02);
GravityEval eval(grav, false, false, dy);
points.clear();
p0[0] = Xnull; p0[1] = 0;
points.push_back(p0);
p0[0] = intpol(eval, Xnull - real(0.1), Xnull, Unull); p0[1] = dy;
points.push_back(p0);
GravityInt sysa(grav, 3u);
GravityFollow::follow(sysa, p0, real(0), 1/real(100), points, box);
LineSimplifier::Simplify(points, thresh);
std::cout << "p{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
{
real dy = real(0.02);
GravityEval eval(grav, false, false, dy);
points.clear();
p0[0] = Xnull; p0[1] = 0;
points.push_back(p0);
p0[0] = intpol(eval, Xnull + real(0.1), Xnull, Unull); p0[1] = dy;
points.push_back(p0);
GravityInt sysa(grav, 1u);
GravityFollow::follow(sysa, p0, real(0), 1/real(100), points, box);
LineSimplifier::Simplify(points, thresh);
std::cout << "p{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
k = 0;
{
GravityEval eval(grav, false, false, 0);
for (int i = 1;; ++i) {
points.clear();
real U = U0 + 5 * del * i;
if (U > Uc) break;
p0[0] = intpol(eval, 0, X0, U); p0[1] = 0;
points.push_back(p0);
GravityInt sysa(grav, 3u);
GravityFollow::follow(sysa, p0, real(0), 1/real(100), points, box);
LineSimplifier::Simplify(points, thresh);
std::cout << "pa{" << ++k << "}=[\n";
dump(points);
std::cout << "];\n";
}
}
}

View File

@@ -0,0 +1,57 @@
% Assume output from LevelEllipsoid has been read in
doinside=1;
red=[179,27,27]/255;
white=[1,1,1];
black=[0,0,0];
blue=[0,19,56]/100;
green=[9,45,27]/100;
gray=[0.9,0.9,0.9];
thick=1;
pltsize=[5.9 4.12];
set(gcf,'Units','pixels');
set(gcf,'Position',50+150*[0 0 pltsize]);
set(gcf,'Units','normalized');
hold off;
if ~doinside
fill([p{1}(:,1);0],[p{1}(:,2);0], gray, 'EdgeColor', 'none');
hold on
end
nq=size(q,2);
for i=1:nq;
plot(q{i}(:,1),q{i}(:,2), 'Color', green);
if i == 1, hold on; end
end
np=size(p,2);
for i=1:np
color = blue;
if i == 1
plot(p{i}(:,1),p{i}(:,2), 'Color', red, 'LineWidth', thick);
else
plot(p{i}(:,1),p{i}(:,2), 'Color', blue);
end
end
if doinside
nq=size(qa,2);
for i=1:nq;
plot(qa{i}(:,1),qa{i}(:,2), 'Color', green);
end
np=size(pa,2);
for i=1:np
plot(pa{i}(:,1),pa{i}(:,2), 'Color', blue);
end
plot([0, 0.6], [0, 0], 'Color', black, 'LineWidth', thick);
end
hold off
xlabel('R'); ylabel('Z');
axis equal;
axis([0,xmax,0,ymax]);
set(gcf,'PaperOrientation', 'landscape');
set(gcf,'PaperSize',pltsize);
set(gcf,'PaperPosition',[0 0 pltsize]);
set(gca, 'XTick',[0:3]);
set(gca, 'YTick',[0:2]);
set(gca, 'LooseInset',[0.07 0.09 0.03 0.02]);
ylabelh=get(gca,'ylabel');
set(ylabelh,'rotation',0);
set(ylabelh,'Position', get(ylabelh, 'Position') + [-0.1 0.2 0]);
print('-dsvg', ['normal-gravity-potential-', num2str(doinside), '.svg']);

View File

@@ -0,0 +1,42 @@
#include <iostream>
#include <GeographicLib/Utility.hpp>
#include <GeographicLib/GeodesicExact.hpp>
#include <GeographicLib/GeodesicLineExact.hpp>
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
real a = 2 / Math::pi();
if (argc != 2) {
std::cout << "Usage: M12zero f\n";
return 1;
}
real f = Utility::fract<real>(std::string(argv[1]));
GeodesicExact g(a, f);
GeodesicLineExact l(g, 90, 0, 0);
real s12 = a * Math::pi()/2;
real lat2, lon2, azi2, m12, M12, M21, ds12;
for (int i = 0; i < 20; ++i) {
using std::abs;
l.Position(s12, lat2, lon2, azi2, m12, M12, M21);
ds12 = m12 * M12 / (1 - M12 * M21);
s12 = abs(s12 + ds12);
}
real q;
g.Inverse(0,0,90,0,q);
int p = 16 + Math::extra_digits();
p = 20;
std::cout << std::fixed << std::setprecision(p) << s12 << " " << q << "\n";
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,126 @@
/**
* \file ProjTest.cpp
* \brief Command line utility for testing transverse Mercator projections
*
* Copyright (c) Charles Karney (2008-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#include "GeographicLib/EllipticFunction.hpp"
#include "GeographicLib/TransverseMercator.hpp"
#include "GeographicLib/TransverseMercatorExact.hpp"
#include "GeographicLib/PolarStereographic.hpp"
#include <iostream>
#include <cassert>
using namespace GeographicLib;
using namespace std;
int main() {
{
Math::real x, y, gamma, k;
x = y = gamma = k = 0;
PolarStereographic::UPS().Forward(true, Math::NaN<Math::real>(), 30.0,
x, y, gamma, k);
cout << x << " " << y << " " << k << "\n";
x = y = gamma = k = 0;
PolarStereographic::UPS().Forward(false, -80.0, Math::NaN<Math::real>(),
x, y, gamma, k);
cout << x << " " << y << " " << gamma << "\n";
}
{
Math::real lat, lon, gamma, k;
lat = lon = gamma = k = 0;
PolarStereographic::UPS().Reverse(true, Math::NaN<Math::real>(), 0.0,
lat, lon, gamma, k);
cout << lat << " " << lon << " " << gamma << " " << k << "\n";
lat = lon = gamma = k = 0;
PolarStereographic::UPS().Reverse(false,0.0, Math::NaN<Math::real>(),
lat, lon, gamma, k);
cout << lat << " " << lon << " " << gamma << " " << k << "\n";
}
{
Math::real x, y, gamma, k;
x = y = gamma = k = 0;
TransverseMercator::UTM().Forward(0.0, Math::NaN<Math::real>(), 0.0,
x, y, gamma, k);
cout << x << " " << y << " " << gamma << " " << k << "\n";
x = y = gamma = k = 0;
TransverseMercator::UTM().Forward(0.0, 0.0, Math::NaN<Math::real>(),
x, y, gamma, k);
cout << x << " " << y << " " << gamma << " " << k << "\n";
x = y = gamma = k = 0;
TransverseMercator::UTM().Forward(Math::NaN<Math::real>(), 0.0, 0.0,
x, y, gamma, k);
cout << x << " " << y << " " << gamma << " " << k << "\n";
}
{
Math::real lat, lon, gamma, k;
lat = lon = gamma = k = 0;
TransverseMercator::UTM().Reverse(0.0, Math::NaN<Math::real>(), 0.0,
lat, lon, gamma, k);
cout << lat << " " << lon << " " << gamma << " " << k << "\n";
lat = lon = gamma = k = 0;
TransverseMercator::UTM().Reverse(0.0, 0.0, Math::NaN<Math::real>(),
lat, lon, gamma, k);
cout << lat << " " << lon << " " << gamma << " " << k << "\n";
lat = lon = gamma = k = 0;
TransverseMercator::UTM().Reverse(Math::NaN<Math::real>(), 0.0, 0.0,
lat, lon, gamma, k);
cout << lon << "\n";
}
{
Math::real x, y, gamma, k;
x = y = gamma = k = 0;
TransverseMercatorExact::UTM().Forward(0.0, Math::NaN<Math::real>(), 0.0,
x, y, gamma, k);
cout << x << " " << y << " " << gamma << " " << k << "\n";
x = y = gamma = k = 0;
TransverseMercatorExact::UTM().Forward(0.0, 0.0, Math::NaN<Math::real>(),
x, y, gamma, k);
cout << x << " " << y << " " << gamma << " " << k << "\n";
x = y = gamma = k = 0;
TransverseMercatorExact::UTM().Forward(Math::NaN<Math::real>(), 0.0, 0.0,
x, y, gamma, k);
cout << x << " " << y << " " << gamma << " " << k << "\n";
}
{
Math::real lat, lon, gamma, k;
lat = lon = gamma = k = 0;
TransverseMercatorExact::UTM().Reverse(0.0, Math::NaN<Math::real>(), 0.0,
lat, lon, gamma, k);
cout << lat << " " << lon << " " << gamma << " " << k << "\n";
lat = lon = gamma = k = 0;
TransverseMercatorExact::UTM().Reverse(0.0, 0.0, Math::NaN<Math::real>(),
lat, lon, gamma, k);
cout << lat << " " << lon << " " << gamma << " " << k << "\n";
lat = lon = gamma = k = 0;
TransverseMercatorExact::UTM().Reverse(Math::NaN<Math::real>(), 0.0, 0.0,
lat, lon, gamma, k);
cout << lon << "\n";
}
{
EllipticFunction e(Math::NaN<Math::real>());
Math::real sn, cn, dn;
cout << " k2 " << e.k2()
<< " kp2 " << e.kp2()
<< " K " << e.K()
<< " E " << e.E()
<< " KE " << e.KE() << "\n";
sn = cn = dn = 0;
e.sncndn(Math::real(0.1), sn, cn, dn);
cout << " sncndn " << sn << " " << cn << " " << dn
<< " E(phi) " << e.E(Math::real(0.1))
<< " E(sncndn) " << e.E(sn, cn, dn) << "\n";
}
{
EllipticFunction e(Math::real(0.1));
Math::real sn, cn, dn;
sn = cn = dn = 0;
e.sncndn(Math::NaN<Math::real>(), sn, cn, dn);
cout << " sncndn " << sn << " " << cn << " " << dn
<< " E(phi) " << e.E(Math::NaN<Math::real>())
<< " E(sncndn) " << e.E(sn, cn, dn) << "\n";
}
}

View File

@@ -0,0 +1,134 @@
#include <iostream>
#include <iomanip>
#include <limits>
#include <vector>
#include <random>
#include <algorithm>
#include <GeographicLib/NormalGravity.hpp>
#include <GeographicLib/Ellipsoid.hpp>
#include <GeographicLib/Utility.hpp>
using namespace std;
using namespace GeographicLib;
void checkdiff(const NormalGravity& g,
Math::real X, Math::real Y, Math::real Z,
Math::real eps, Math::real tol) {
Math::real gX, gY, gZ, t,
V = g.V0(X, Y, Z, gX, gY, gZ),
VXp = g.V0(X+eps, Y, Z, t, t, t), VXm = g.V0(X-eps, Y, Z, t, t, t),
VYp = g.V0(X, Y+eps, Z, t, t, t), VYm = g.V0(X, Y-eps, Z, t, t, t),
VZp = g.V0(X, Y, Z+eps, t, t, t), VZm = g.V0(X, Y, Z-eps, t, t, t),
ggX = (VXp - VXm) / (2*eps),
ggY = (VYp - VYm) / (2*eps),
ggZ = (VZp - VZm) / (2*eps),
lap = (VXp + VXm + VYp + VYm + VZp + VZm - 6 * V) / Math::sq(eps);
if (!(abs(ggX - gX) < tol &&
abs(ggY - gY) < tol &&
abs(ggZ - gZ) < tol &&
abs(lap) < tol))
cout << "Failure with f = " << g.Flattening() << " X,Y,Z = "
<< X << " " << Y << " " << Z << "\n"
<< " " << ggX - gX << " " << ggY - gY << " " << ggZ - gZ
<< " " << lap << "\n";
}
// Copied from NormalGravity (w/o the series expansion)
Math::real atanzz(Math::real x, bool alt) {
// This routine obeys the identity
// atanzz(x, alt) = atanzz(-x/(1+x), !alt)
//
// Require x >= -1. Best to call with alt, s.t. x >= 0; this results in
// a call to atan, instead of asin, or to asinh, instead of atanh.
Math::real z = sqrt(abs(x));
return x == 0 ? 1 :
(alt
? (!(x < 0) ? asinh(z) : asin(z)) / sqrt(abs(x) / (1 + x))
: (!(x < 0) ? atan(z) : atanh(z)) / z);
}
// Copied from NormalGravity (w/o the series expansion)
Math::real Qf(Math::real x, bool alt) {
// Compute
// Q(z) = (((1 + 3/z^2) * atan(z) - 3/z)/2) / z^3
// = q(z)/z^3 with q(z) defined by H+M, Eq 2-57 with z = E/u
// z = sqrt(x)
Math::real y = alt ? -x / (1 + x) : x;
return ((1 + 3/y) * atanzz(x, alt) - 3/y) / (2 * y);
}
int main() {
Utility::set_digits();
Math::real
eps = sqrt(sqrt(numeric_limits<Math::real>::epsilon())),
tol = eps;
cout << setprecision(13);
cout << "eps = " << eps << "\n";
unsigned s = random_device()(); // Set seed from random_device
mt19937 r(s); // Initialize URNG
if (1) {
Math::real GM = 1, a = 1, omega = 1;
{
Math::real f = 1/Math::real(5);
NormalGravity g(a, GM, omega, f, true);
Math::real gX, gY, gZ, U, X = Math::real(5)/10, Y = 0,
R = hypot(X, Y),
b = a*(1-f), E2 = abs(a*a - b*b), E = sqrt(E2);
U = g.V0(X, Y, 0, gX, gY, gZ);
cout << U << " " << gX << " " << gY << " " << gZ << "\n";
U = g.V0(X, Y, eps, gX, gY, gZ);
cout << U << " " << gX << " " << gY << " " << gZ << "\n";
cout << "gz = "
<< -(GM/(E*sqrt(E2-R*R)) +
Math::sq(a*b*omega)*b /
(E2*E2*E*Qf(Math::sq(E/b), false)) *
(2*E2/3 - R*R)/sqrt(E2-R*R)) << "\n";
}
{
Math::real f = -1/Math::real(5);
NormalGravity g(a, GM, omega, f, true);
Math::real gX, gY, gZ, U, Z = Math::real(4)/10, Y = 0,
b = a*(1-f), E2 = abs(a*a - b*b), E = sqrt(E2);
U = g.V0(0, Y, Z, gX, gY, gZ);
cout << U << " " << gX << " " << gY << " " << gZ << "\n";
U = g.V0(eps, Y, Z, gX, gY, gZ);
cout << U << " " << gX << " " << gY << " " << gZ << "\n";
cout << "-R*gR = " << eps*hypot(gX, gY) << " "
<< 2*(GM/(2*E) + Math::sq(a*b*omega)*b /
(E2*E2*E*Qf(Math::sq(E/a), true)) *
(3*Z*Z - E2)/12) << "\n";
}
{
Math::real f = 0;
NormalGravity g(a, GM, omega, f, true);
Math::real gX, gY, gZ, U,
X = Math::real(1)/10, Z = Math::real(4)/10, Y = 0,
b = a*(1-f), R = hypot(X, Z), beta = atan2(Z, X);
U = g.V0(X, Y, Z, gX, gY, gZ);
cout << U << " " << gX << " " << gY << " " << gZ << "\n";
cout << "U = " << GM/R + Math::sq(a*b*omega)*b/(R*R*R) *
(3*Math::sq(sin(beta)) - 1)/6 << "\n";
cout << "gR = " << gX*cos(beta) + gZ*sin(beta) << " "
<< -GM/(R*R) - (Math::sq(a*b*omega)*b/(R*R*R*R) *
(3*Math::sq(sin(beta)) - 1)/2)
<< " gbeta = " << -gX*sin(beta) + gZ*cos(beta) << " "
<< Math::sq(a*b*omega)*b/(R*R*R*R) * sin(beta)*cos(beta) << "\n";
}
return 0;
}
uniform_real_distribution<double> dis;
vector<Math::real> f = {-99, -0.1, 0, 0.1, 0.99};
Math::real GM = 1, omega = 1;
int num = 1000;
for (size_t i = 0; i < f.size(); ++i) {
Math::real a = 1 / sqrt(1 - f[i]);
cout << a << " " << a*(1-f[i]) << "\n";
NormalGravity g(a, GM, omega, f[i], true);
for (int j = 0; j < num; ++j) {
Math::real
X = Math::real(dis(r)), Y = Math::real(dis(r)), Z = Math::real(dis(r));
checkdiff(g, X, Y, Z, eps, tol);
}
}
}

View File

@@ -0,0 +1,343 @@
/**
* \file ProjTest.cpp
* \brief Command line utility for testing transverse Mercator projections
*
* Copyright (c) Charles Karney (2008-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#include "GeographicLib/LambertConformalConic.hpp"
#include "GeographicLib/PolarStereographic.hpp"
#include "GeographicLib/TransverseMercator.hpp"
#include "GeographicLib/TransverseMercatorExact.hpp"
#include "GeographicLib/Constants.hpp"
#include <string>
#include <limits>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <stdexcept>
class DataFile {
private:
typedef GeographicLib::Math::real real;
std::istream* _istr;
std::ifstream _fstr;
// String headers
// COORDINATES
// PROJECTION
// DATUM
std::string _coords, _proj, _datum;
// Numeric headers
// CENTRAL MERIDIAN
// FALSE EASTING
// FALSE NORTHING
// LATITUDE OF TRUE SCALE
// LONGITUDE DOWN FROM POLE
// ORIGIN LATITUDE
// SCALE FACTOR
// STANDARD PARALLEL ONE
// STANDARD PARALLEL TWO
real _lon0, _fe, _fn, _latts, _lonfp, _lat0, _k0, _lat1, _lat2;
DataFile(const DataFile&);
DataFile& operator=(const DataFile&);
public:
DataFile(const std::string& file) {
if (!(file.empty() || file == "-")) {
_fstr.open(file.c_str());
if (!_fstr.good())
throw std::out_of_range("Cannot open " + file);
}
_istr = (file.empty() || file == "-") ? &std::cin : &_fstr;
_coords = _proj = _datum = "NONE";
_lon0 = _fe = _fn = _latts = _lonfp = _lat0 = _k0 = _lat1 = _lat2
= GeographicLib::Math::NaN<real>();
std::string s;
while (getline(*_istr, s)) {
if (s.empty() || s[0] == '#')
continue;
if (s.substr(0, 13) == "END OF HEADER")
break;
std::string::size_type p = s.find(':');
if (p == std::string::npos)
continue;
std::string key(s, 0, p);
p = s.find_first_not_of(" \t\v\r\n\f", p + 1);
if (p == std::string::npos)
continue;
s = s.substr(p);
p = s.find_last_not_of(" \t\v\r\n\f");
s = s.substr(0, p + 1);
std::istringstream is(s);
if (key == "COORDINATES") {
_coords = s;
} else if (key == "PROJECTION") {
_proj = s;
} else if (key == "DATUM") {
_datum = s;
} else if (key == "CENTRAL MERIDIAN") {
is >> _lon0;
} else if (key == "FALSE EASTING") {
is >> _fe;
} else if (key == "FALSE NORTHING") {
is >> _fn;
} else if (key == "LATITUDE OF TRUE SCALE") {
is >> _latts;
} else if (key == "LONGITUDE DOWN FROM POLE") {
is >> _lonfp;
} else if (key == "ORIGIN LATITUDE") {
is >> _lat0;
} else if (key == "SCALE FACTOR") {
is >> _k0;
} else if (key == "STANDARD PARALLEL ONE") {
is >> _lat1;
} else if (key == "STANDARD PARALLEL TWO") {
is >> _lat2;
}
}
}
bool Next(real &x, real &y) {
char c;
// Avoid a warning about void* changed to bool
return (*_istr >> x >> c >> y) ? true : false;
}
bool Next(real &x, real &y, real &z) {
char c, d;
// Avoid a warning about void* changed to bool
return (*_istr >> x >> c >> y >> d >> z) ? true : false;
}
const std::string& coords() const { return _coords; }
const std::string& proj() const { return _proj; }
const std::string& datum() const { return _datum; }
real lon0() const { return _lon0; }
real fe() const { return _fe; }
real fn() const { return _fn; }
real latts() const { return _latts; }
real lonfp() const { return _lonfp; }
real lat0() const { return _lat0; }
real k0() const { return _k0; }
real lat1() const { return _lat1; }
real lat2() const { return _lat2; }
};
GeographicLib::Math::real
dist(GeographicLib::Math::real a, GeographicLib::Math::real f,
GeographicLib::Math::real lat0, GeographicLib::Math::real lon0,
GeographicLib::Math::real lat1, GeographicLib::Math::real lon1) {
using namespace GeographicLib;
using std::cos; using std::sin; using std::sqrt; using std::hypot;
typedef Math::real real;
real
phi = lat0 * Math::degree(),
e2 = f * (2 - f),
sinphi = sin(phi),
n = 1/sqrt(1 - e2 * sinphi * sinphi),
// See Wikipedia article on latitude
hlon = cos(phi) * n,
hlat = (1 - e2) * n * n * n,
dlon = lon1 - lon0;
if (dlon >= 180) dlon -= 360;
else if (dlon < -180) dlon += 360;
return a * Math::degree() *
hypot((lat1 - lat0) * hlat, dlon * hlon);
}
int usage(int retval) {
( retval ? std::cerr : std::cout ) <<
"ProjTest latlonfile projfile\n\
\n\
Checks projections against NGS GoldData files\n";
return retval;
}
int main(int argc, char* argv[]) {
using namespace GeographicLib;
typedef Math::real real;
if (argc != 3)
return usage(1);
try {
real eps = 2*std::numeric_limits<real>::epsilon();
enum { undef = 0, tm = 1, ps = 2, lcc = 3 };
int m = 0;
std::string geof(argv[++m]);
DataFile geo(geof);
std::string projf(argv[++m]);
DataFile proj(projf);
if (geo.coords() != "Geodetic")
throw std::out_of_range("Unsupported coordinates " + geo.coords());
real a, f;
if (geo.datum() == "WGE") {
a = Constants::WGS84_a();
f = Constants::WGS84_f();
} else if (geo.datum() == "Test_sphere") {
a = 20000000/Math::pi();
f = 0;
} else if (geo.datum() == "Test_SRMmax") {
a = 6400000;
f = 1/real(150);
} else
throw std::out_of_range("Unsupported datum " + geo.datum());
if (proj.datum() != geo.datum())
throw std::out_of_range("Datum mismatch " +
geo.datum() + " " + proj.datum());
real fe, fn, lat0, lat1, lat2, lon0, k1;
int type = undef;
if (proj.proj() == "Lambert Conformal Conic (1 parallel)") {
fe = proj.fe();
fn = proj.fn();
k1 = proj.k0();
lon0 = proj.lon0();
lat1 = lat2 = lat0 = proj.lat0();
type = lcc;
} else if (proj.proj() == "Lambert Conformal Conic (2 parallel)") {
fe = proj.fe();
fn = proj.fn();
k1 = 1;
lon0 = proj.lon0();
lat0 = proj.lat0();
lat1 = proj.lat1();
lat2 = proj.lat2();
type = lcc;
} else if (proj.proj() == "Mercator") {
using std::isfinite;
fe = proj.fe();
fn = proj.fn();
k1 = proj.k0();
if (!isfinite(k1))
k1 = 1;
lon0 = proj.lon0();
lat0 = 0;
lat1 = proj.latts();
if (!isfinite(lat1))
lat1 = 0;
lat2 = -lat1;
type = lcc;
} else if (proj.proj() == "Polar Stereographic") {
using std::isfinite;
fe = proj.fe();
fn = proj.fn();
lon0 = proj.lonfp();
lat0 = 90;
k1 = proj.k0();
if (!isfinite(k1))
k1 = 1;
real latts = proj.latts();
if (isfinite(latts)) {
if (latts < 0)
lat0 = -lat0;
LambertConformalConic tx(a, f, lat0, 1);
real x, y, gam, k;
tx.Forward(0, latts, 10, x, y, gam, k);
k1 = 1/k;
}
lat1 = lat2 = lat0;
type = lon0 == 0 ? ps : lcc;
} else if (proj.proj() == "Transverse Mercator") {
fe = proj.fe();
fn = proj.fn();
lon0 = proj.lon0();
k1 = proj.k0();
lat0 = lat1 = lat2 = proj.lat0();
type = tm;
} else
throw std::out_of_range("Unsupported projection " + proj.proj());
LambertConformalConic tx(a, f, lat1, lat2, k1);
PolarStereographic txa(a, f, k1);
TransverseMercator txb(a, f, k1);
TransverseMercatorExact txc(a, f == 0 ? real(0.1)/eps : f, k1);
std::cout << a << " 1/" << 1/f << " " << k1 << " " << type << "\n";
real x0, y0, gam, k;
if (type == lcc)
tx.Forward(lon0, lat0, lon0, x0, y0, gam, k);
else if (type == tm)
txb.Forward(lon0, lat0, lon0, x0, y0, gam, k);
else
x0 = y0 = 0;
real lata, lona, xa, ya;
unsigned count = 0;
real maxerrx = 0, maxerry = 0, maxerr = 0, maxerrk = 0, maxerrr = 0;
std::cout << std::fixed << std::setprecision(7);
while (geo.Next(lata, lona) && proj.Next(xa, ya)) {
using std::abs; using std::hypot;
++count;
// Suppress bogus uninitialized warnings for lat and lon
real lat = 0, lon = 0, x, y, xx, yy;
x = xa - fe + x0;
y = ya - fn + y0;
xx = x/k1;
yy = y/k1;
switch (type) {
case lcc:
tx.Reverse(lon0, x, y, lat, lon, gam, k);
break;
case ps:
txa.Reverse(lat1 > 0, x, y, lat, lon, gam, k);
break;
case tm:
txb.Reverse(lon0, x, y, lat, lon, gam, k);
break;
default: break; // To suppress warning
}
real errr = dist(a, f, lata, lona, lat, lon);
maxerrr = std::max(errr, maxerrr);
if (!(errr < 1e-6))
std::cout << "REV: "
<< lata << " "
<< lona << " "
<< xx << " "
<< yy << " "
<< errr << "\n";
switch (type) {
case lcc:
tx.Forward(lon0, lata, lona, x, y, gam, k);
break;
case ps:
txa.Forward(lat1 > 0, lata, lona, x, y, gam, k);
break;
case tm:
txb.Forward(lon0, lata, lona, x, y, gam, k);
break;
default: break; // To suppress warning
}
x -= x0;
y -= y0;
x += fe;
y += fn;
real
errx = abs(x - xa),
erry = abs(y - ya),
err = hypot(errx, erry),
errk = err/std::max(real(1),k);
std::ostringstream sx, sxa, sy, sya;
sx << std::fixed << std::setprecision(6) << x;
sxa << std::fixed << std::setprecision(6) << xa;
sy << std::fixed << std::setprecision(6) << y;
sya << std::fixed << std::setprecision(6) << ya;
// if (sx.str() != sxa.str() || sy.str() != sya.str())
if (!(errk < 1e-6))
std::cout << "FOR: "
<< lata << " "
<< lona << " "
<< xx << " "
<< yy << " "
<< errk << "\n";
maxerrx = std::max(errx, maxerrx);
maxerry = std::max(erry, maxerry);
maxerr = std::max(err, maxerr);
maxerrk = std::max(errk, maxerrk);
}
std::cout << count << " records; maxerr "
<< maxerrk << " " << maxerrr << "\n";
}
catch (const std::exception& e) {
std::cout << "ERROR: " << e.what() << "\n";
return 1;
}
return 0;
}

View File

@@ -0,0 +1,227 @@
/**
* \file TMTest.cpp
* \brief Command line utility for testing transverse Mercator projections
*
* Copyright (c) Charles Karney (2008-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#include "GeographicLib/TransverseMercator.hpp"
#include "GeographicLib/TransverseMercatorExact.hpp"
#include "GeographicLib/Geodesic.hpp"
#include "GeographicLib/Constants.hpp"
#include <vector>
#include <algorithm>
#include <string>
#include <limits>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <stdexcept>
using namespace GeographicLib;
GeographicLib::Math::real
dist(GeographicLib::Math::real a, GeographicLib::Math::real f,
GeographicLib::Math::extended lat0, GeographicLib::Math::extended lon0,
GeographicLib::Math::real lat1, GeographicLib::Math::real lon1) {
using namespace GeographicLib;
using std::cos; using std::sin; using std::sqrt; using std::hypot;
typedef Math::real real;
real
phi = real(lat0) * Math::degree(),
e2 = f * (2 - f),
sinphi = sin(phi),
n = 1/sqrt(1 - e2 * sinphi * sinphi),
// See Wikipedia article on latitude
hlon = cos(phi) * n,
hlat = (1 - e2) * n * n * n;
Math::extended dlon = Math::extended(lon1) - lon0;
if (dlon >= 180) dlon -= 360;
else if (dlon < -180) dlon += 360;
return a * Math::degree() *
hypot(real(Math::extended(lat1) - lat0) * hlat, real(dlon) * hlon);
}
int usage(int retval) {
( retval ? std::cerr : std::cout ) <<
"TMTest [-s] [-d]\n\
\n\
Read in TMcoords.dat on standard input and test TransverseMercatorExact\n\
or (if -s is given) TransverseMercator. If -d dump the error for each\n\
point; otherwise summarise errors. If -tf, perform a timing test of the\n\
forward projection. If -tr, perform a timing test of the reverse\n\
projection.\n";
return retval;
}
int main(int argc, char* argv[]) {
using namespace GeographicLib;
typedef Math::real real;
bool series = false;
bool dump = false;
bool timefor = false, timerev = false;
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-s") {
series = true;
} else if (arg == "-d") {
dump = true;
timefor = false;
timerev = false;
} else if (arg == "-tf") {
dump = false;
timefor = true;
timerev = false;
} else if (arg == "-tr") {
dump = false;
timefor = false;
timerev = true;
} else
return usage(arg != "-h");
}
if (timefor || timerev) {
real s = 0;
int count = 0;
real dlat = real(0.015), dlon = real(0.015), dx = 2e3, dy = 2e3;
if (series) {
const TransverseMercator& tm = TransverseMercator::UTM();
if (timefor) {
real x, y, gam, k;
for (real lat = -80.0; lat <= 84.0; lat += dlat)
for (real lon = -3.0; lon <= 3.0; lon += dlon) {
tm.Forward(0.0, lat, lon, x, y, gam, k);
s += k;
++count;
}
} else {
real lat, lon, gam, k;
for (real x = -400e3; x <= 400e3; x += dx)
for (real y = -9000e3; y <= 9500e3; y += dy) {
tm.Reverse(0.0, x, y, lat, lon, gam, k);
s += k;
++count;
}
}
} else {
const TransverseMercatorExact tm(Constants::WGS84_a<real>(),
Constants::WGS84_f<real>(),
Constants::UTM_k0<real>(),
true);
if (timefor) {
real x, y, gam, k;
for (real lat = -80.0; lat <= 84.0; lat += dlat)
for (real lon = -3.0; lon <= 3.0; lon += dlon) {
tm.Forward(0.0, lat, lon, x, y, gam, k);
s += k;
++count;
}
} else {
real lat, lon, gam, k;
for (real x = -400e3; x <= 400e3; x += dx)
for (real y = -9000e3; y <= 9500e3; y += dy) {
tm.Reverse(0.0, x, y, lat, lon, gam, k);
s += k;
++count;
}
}
}
std::cout << count << " " << s << "\n";
return 0;
}
try {
real minlat = series ? 0 : (dump ? -100 : -15);
const unsigned nbins = 101;
std::vector<real> d(nbins);
std::vector<real> errv(nbins, 0);
std::vector<real> errvg(nbins, 0);
std::vector<real> errvk(nbins, 0);
real esterr = real(sizeof(real) == sizeof(double) ?
(series ? 3e-9 : 8e-9) :
(series ? 4e-12 : 4e-12));
for (unsigned i = 0; i < nbins; ++i)
d[i] = real(100e3 * i);
d[0] = 10e3;
d[nbins - 1] = 10001966;
const TransverseMercator& tm = TransverseMercator::UTM();
const TransverseMercatorExact tme(Constants::WGS84_a<real>(),
Constants::WGS84_f<real>(),
Constants::UTM_k0<real>(),
true);
real
a = series ? tm.EquatorialRadius() : tme.EquatorialRadius(),
f = series ? tm.Flattening() : tme.Flattening();
const Geodesic geod(a, f);
Math::extended lat0l, lon0l, x0l, y0l, gam0l, k0l;
while (std::cin >> lat0l >> lon0l >> x0l >> y0l >> gam0l >> k0l) {
using std::abs; using std::sin; using std::hypot;
real
lat0 = real(lat0l),
lon0 = real(lon0l),
x0 = real(x0l),
y0 = real(y0l),
gam0 = real(gam0l),
k0 = real(k0l);
if (lat0 < minlat)
continue;
real azi1, azi2, s12, m12;
real errf, errgf, errkf, errr, errgr, errkr;
geod.Inverse(std::max(lat0,real(0)), lon0, std::max(lat0,real(0)), -lon0,
s12, azi1, azi2, m12);
s12 /= 2;
real lat, lon, x, y, gam, k;
if (series) {
tm.Forward(0, lat0, lon0, x, y, gam, k);
} else
tme.Forward(0, lat0, lon0, x, y, gam, k);
errf = real(hypot(Math::extended(x) - x0l,
Math::extended(y) - y0l)) / k0;
errgf = real(abs(Math::extended(gam) - gam0));
errkf = real(abs(Math::extended(k) - k0));
if (series) {
tm.Reverse(0, x0, y0, lat, lon, gam, k);
} else
tme.Reverse(0, x0, y0, lat, lon, gam, k);
errr = dist(a, f, lat0l, lon0l, lat, lon);
errgr = real(abs(Math::extended(gam) - gam0));
errkr = real(abs(Math::extended(k) - k0));
real
err = std::max(errf, errr),
errg = std::max(errgf, errgr)
- esterr/(a * sin((90 - lat0) * Math::degree())
* Math::degree()),
errk = std::max(errkf, errkr) / k0;
if (dump)
std::cout << std::fixed << std::setprecision(12)
<< lat0 << " " << lon0 << " "
<< std::scientific << std::setprecision(4)
<< errf << " " << errr << " "
<< errgf << " " << errgr << " "
<< errkf << " " << errkr << "\n";
else
for (unsigned i = 0; i < nbins; ++i) {
if (s12 <= d[i]) {
errv[i] = std::max(err, errv[i]);
errvg[i] = std::max(errg, errvg[i]);
errvk[i] = std::max(errk, errvk[i]);
}
}
}
if (!dump)
for (unsigned i = 0; i < nbins; ++i)
std::cout << int(d[i]/1000) << " "
<< errv[i] << " "
<< errvg[i] << " "
<< errvk[i] << "\n";
}
catch (const std::exception& e) {
std::cout << "ERROR: " << e.what() << "\n";
return 1;
}
return 0;
}

View File

@@ -0,0 +1,29 @@
1d2:3 0
1:2:3 0
1d2'3" 0
1D2'3" 0
1°23″ 0
1º23˝ 0
1⁰2´3“ 0
1˚2`3” 0
1∘23‟ 0
1*23´´ 0
1:23`` 0
1∘23: 0
+1:2:3 0
+1d2'3" 0
+1D2'3" 0
+1°23″ 0
+1º23˝ 0
+1⁰2´3“ 0
+1˚2`3” 0
+1∘23‟ 0
+1*23´´ 0
+1:23`` 0
-1:2:3 0
1d2'3" 0
1D2'3" 0
1°23″ 0
—1º23˝ 0
1⁰2´3“ 0
—1˚2`3” 0

View File

@@ -0,0 +1,78 @@
#include <iostream>
#include <iomanip>
#include <GeographicLib/Utility.hpp>
#include <GeographicLib/Gnomonic.hpp>
#include <GeographicLib/Geodesic.hpp>
class vector3 {
public:
GeographicLib::Math::real _x, _y, _z;
vector3(GeographicLib::Math::real x,
GeographicLib::Math::real y,
GeographicLib::Math::real z = 1) throw()
: _x(x)
, _y(y)
, _z(z) {}
vector3 cross(const vector3& b) const throw() {
return vector3(_y * b._z - _z * b._y,
_z * b._x - _x * b._z,
_x * b._y - _y * b._x);
}
void norm() throw() {
_x /= _z;
_y /= _z;
_z = 1;
}
};
int main() {
GeographicLib::Utility::set_digits();
GeographicLib::Math::real lata1, lona1, lata2, lona2;
GeographicLib::Math::real latb1, lonb1, latb2, lonb2;
std::cin >> lata1 >> lona1 >> lata2 >> lona2
>> latb1 >> lonb1 >> latb2 >> lonb2;
const GeographicLib::Geodesic& geod = GeographicLib::Geodesic::WGS84();
const GeographicLib::Gnomonic gn(geod);
GeographicLib::Math::real
lat0 = (lata1 + lata2 + latb1 + latb2)/4,
// Possibly need to deal with longitudes wrapping around
lon0 = (lona1 + lona2 + lonb1 + lonb2)/4;
std::cout << std::setprecision(16);
std::cout << "Initial guess " << lat0 << " " << lon0 << "\n";
GeographicLib::Math::real s120 = 1, s121;
for (int i = 0; i < 20; ++i) {
GeographicLib::Math::real xa1, ya1, xa2, ya2;
GeographicLib::Math::real xb1, yb1, xb2, yb2;
gn.Forward(lat0, lon0, lata1, lona1, xa1, ya1);
gn.Forward(lat0, lon0, lata2, lona2, xa2, ya2);
gn.Forward(lat0, lon0, latb1, lonb1, xb1, yb1);
gn.Forward(lat0, lon0, latb2, lonb2, xb2, yb2);
// See Hartley and Zisserman, Multiple View Geometry, Sec. 2.2.1
vector3 va1(xa1, ya1); vector3 va2(xa2, ya2);
vector3 vb1(xb1, yb1); vector3 vb2(xb2, yb2);
// la is homogeneous representation of line A1,A2
// lb is homogeneous representation of line B1,B2
vector3 la = va1.cross(va2);
vector3 lb = vb1.cross(vb2);
// p0 is homogeneous representation of intersection of la and lb
vector3 p0 = la.cross(lb);
p0.norm();
GeographicLib::Math::real lat1, lon1;
gn.Reverse(lat0, lon0, p0._x, p0._y, lat1, lon1);
geod.Inverse(lat1, lon1, lat0, lon1, s121);
std::cout << "Increment " << s121 << " ratio " << s121/s120 << "\n";
lat0 = lat1;
lon0 = lon1;
s120 = s121;
}
std::cout << "Final result " << lat0 << " " << lon0 << "\n";
GeographicLib::Math::real azi1, azi2;
geod.Inverse(lata1, lona1, lat0, lon0, azi1, azi2);
std::cout << "Azimuths on line A " << azi2 << " ";
geod.Inverse(lat0, lon0, lata2, lona2, azi1, azi2);
std::cout << azi1 << "\n";
geod.Inverse(latb1, lonb1, lat0, lon0, azi1, azi2);
std::cout << "Azimuths on line B " << azi2 << " ";
geod.Inverse(lat0, lon0, latb2, lonb2, azi1, azi2);
std::cout << azi1 << "\n";
}

View File

@@ -0,0 +1,10 @@
#! /bin/sh
cd $HOME
for d in geographiclib \
git/geographiclib-{c,fortran,java,js,octave,python,doc}; do
(
cd $d
git ls-tree -r HEAD --name-only |
sed -e "s%^%$HOME/$d/%"
)
done

View File

@@ -0,0 +1,81 @@
#! /bin/sh
(
cat <<EOF
<deployment-project plugin="plugin.toolbox" plugin-version="1.0">
<configuration build-checksum="" file="$ROOT/geographiclib.prj" location="$ROOT" name="geographiclib" target="target.toolbox" target-name="Package Toolbox">
<param.appname>geographiclib</param.appname>
<param.authnamewatermark>Charles Karney</param.authnamewatermark>
<param.email>charles@karney.com</param.email>
<param.company />
<param.summary>MATLAB implementations of a subset of the C++ library, GeographicLib</param.summary>
<param.description>GeographicLib toolbox
Version $VERSION $DATE
EOF
cat $ROOT/geographiclib-blurb.txt
cat <<EOF
</param.description>
<param.screenshot>\${PROJECT_ROOT}/geodesic.png</param.screenshot>
<param.version>$VERSION</param.version>
<param.output>\${PROJECT_ROOT}/geographiclib.mltbx</param.output>
<param.products.name>
<item>MATLAB</item>
</param.products.name>
<param.products.id>
<item>1</item>
</param.products.id>
<param.products.version>
<item>7.9</item>
</param.products.version>
<param.platforms />
<param.guid />
<param.exclude.filters />
<param.examples>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;examples/&gt;</param.examples>
<param.demosxml />
<param.apps />
<param.docs />
<unset>
<param.company />
<param.output />
<param.platforms />
<param.exclude.filters />
<param.demosxml />
<param.apps />
<param.docs />
</unset>
<fileset.rootdir>
<file>\${PROJECT_ROOT}/geographiclib</file>
</fileset.rootdir>
<fileset.rootfiles>
<file>${PROJECT_ROOT}/geographiclib</file>
</fileset.rootfiles>
<fileset.depfun.included />
<fileset.depfun.excluded />
<fileset.package />
<build-deliverables>
<file location="$ROOT" name="geographiclib.mltbx" optional="false">$ROOT/geographiclib.mltbx</file>
</build-deliverables>
<workflow />
<matlab />
<platform>
<unix>true</unix>
<mac>false</mac>
<windows>false</windows>
<win2k>false</win2k>
<winxp>false</winxp>
<vista>false</vista>
<linux>true</linux>
<solaris>false</solaris>
<osver />
<os32>false</os32>
<os64>true</os64>
<arch>glnxa64</arch>
<matlab>true</matlab>
</platform>
</configuration>
</deployment-project>
EOF
) > $ROOT/geographiclib.prj
exit

View File

@@ -0,0 +1,472 @@
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cmath>
int cosind(int N, int /*M*/, int n, int m) {
return m * N - m * (m - 1) / 2 + n;
}
int sinind(int N, int M, int n, int m) {
return cosind(N, M, n, m) - (N + 1);
}
void storecos(std::vector<double>& C, int N, int M,
double v, int n, int m) {
if (v == 0)
return;
if (n < 0 || n > N || m < 0 || m > M)
throw std::runtime_error("Invalid coefficient");
C[cosind(N, M, n, m)] = v;
}
void storesin(std::vector<double>& S, int N, int M,
double v, int n, int m) {
if (v == 0)
return;
if (n < 0 || n > N || m <= 0 || m > M)
throw std::runtime_error("Invalid coefficient");
S[sinind(N, M, n, m)] = v;
}
void storecoeff(std::ostream& str,
const std::vector<double>& C, const std::vector<double>& S,
int M, int N) {
int K = (M + 1) * (2*N - M + 2) / 2;
int ind[2] = {N, M};
str.write(reinterpret_cast<const char*>(ind), 2 * sizeof(int));
str.write(reinterpret_cast<const char*>(&C[0]), K * sizeof(double));
str.write(reinterpret_cast<const char*>(&S[0]), (K-N-1) * sizeof(double));
}
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cerr << "Usage: reformat model outfile\n";
return 1;
}
std::string model = argv[1];
std::string file = argv[2];
try {
// model = wmm2010
//http://ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2010_Sph_Windows_Linux.zip
// unpack
// coefficients are in EMM_Sph_Windows_Linux/WMM2010.COF
// N=739, M=718
std::ofstream fout(file.c_str(), std::ios::binary);
if (model == "emm2010") {
// download
// http://ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2010_Sph_Windows_Linux.zip
// unpack
// coefficients are in EMM_Sph_Windows_Linux/EMM2010.COF
// and EMM_Sph_Windows_Linux/EMM2010SV.COF
std::string id = "EMM2010A";
fout.write(id.c_str(), 8);
for (int i = 0; i < 2; ++i) {
std::string filename = i == 0 ? "EMM_Sph_Windows_Linux/EMM2010.COF" :
"EMM_Sph_Windows_Linux/EMM2010SV.COF";
int
N = i == 0 ? 739 : 16,
M = i == 0 ? 718 : 16,
K = (M + 1) * (2*N - M + 2) / 2;
std::vector<double> C(K, 0.0);
std::vector<double> S(K - (N + 1), 0.0);
std::ifstream fin(filename.c_str());
std::string ss;
if (i == 0) std::getline(fin, ss); // Skip first line
while (std::getline(fin, ss)) {
int n, m;
double c, s;
std::istringstream is(ss);
if (!(is >> n >> m >> c >> s))
throw std::runtime_error("Short read");
storecos(C, N, M, c, n, m);
storesin(S, N, M, s, n, m);
}
storecoeff(fout, C, S, M, N);
}
} else if (model == "emm2015") {
// download
//http://www.ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2015_Sph_Linux.zip
// unpack
//
// * The only coefficients needed are EMM20{00-15}.COF and EMM2015SV.COF.
//
// * The other SV files can be ignored because the time dependence can be
// obtained using linear interpolation for dates < 2015 (or
// extrapolation for dates < 2000).
//
// * The time varying part of the field is of degree 15. This
// constitutes all the coefficients in EMM20{00-14}.COF and
// EMM2015SV.COF and a subset of the coefficients in EMM2015.COF.
//
// * To this should be added a time independent short wavelength field
// which is given by the degree > 15 terms in EMM2015.COF.
//
// * These time independent terms are of degree 729 and order 718. There
// are higher degree and order coefficients listed in the file, but
// these are zero.
//
// * The EMM2015 coefficients as used by GeographicLib compress much
// better than those for EMM2010 (660 kB instead of 3700 kB).
// Presumably this is because the EMM2015 are only given with 4 decimal
// digits.
//
// * The GeographicLib implementation produces the same results as listed
// in EMM2015_TEST_VALUES.txt
std::string id = "EMM2015A";
fout.write(id.c_str(), 8);
for (int i = 0; i <= 17; ++i) {
std::string filename;
{
std::ostringstream os;
os << "EMM2015_linux/EMM" << (2000 + std::min(15, i))
<< (i == 16 ? "SV" : "") << ".COF";
filename = os.str();
}
int
N = i == 17 ? 729 : 15,
M = i == 17 ? 718 : 15,
K = (M + 1) * (2*N - M + 2) / 2;
std::vector<double> C(K, 0.0);
std::vector<double> S(K - (N + 1), 0.0);
std::ifstream fin(filename.c_str());
std::string ss;
if (i != 16) std::getline(fin, ss); // Skip first line
while (std::getline(fin, ss)) {
int n, m;
double c, s;
std::istringstream is(ss);
if (!(is >> n >> m >> c >> s))
throw std::runtime_error("Short read " + filename + ": " + ss);
if (i == 15 && n > 15)
continue;
if (i == 17 && n <= 15)
continue;
storecos(C, N, M, c, n, m);
storesin(S, N, M, s, n, m);
}
storecoeff(fout, C, S, M, N);
}
} else if (model == "emm2017") {
// download
//https://www.ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2017_Sph_Linux.zip
// unpack
//
// * The only coefficients needed are EMM20{00-17}.COF and EMM2017SV.COF.
//
// * The other SV files can be ignored because the time dependence can be
// obtained using linear interpolation for dates < 2017 (or
// extrapolation for dates < 2000).
//
// * The time varying part of the field is of degree 15. This
// constitutes all the coefficients in EMM20{00-16}.COF and
// EMM2017SV.COF and a subset of the coefficients in EMM2017.COF.
//
// * To this should be added a time independent short wavelength field
// which is given by the degree > 15 terms in EMM2017.COF.
//
// * These time independent terms are of degree 790 and order 790.
//
// * The GeographicLib implementation produces the same results as listed
// in EMM2017TestValues.txt
std::string id = "EMM2017A";
fout.write(id.c_str(), 8);
int maxy = 17;
for (int i = 0; i <= 19; ++i) {
// i = maxy for low res components for 2000+maxy
// i = maxy+1 for SV at 2000+maxy
// i = maxy+2 for high res components for 2000+maxy
std::string filename;
{
std::ostringstream os;
os << "EMM2017_Linux/EMM" << (2000 + std::min(maxy, i))
<< (i == maxy+1 ? "SV" : "") << ".COF";
filename = os.str();
}
int
N = i == maxy+2 ? 790 : 15,
M = i == maxy+2 ? 790 : 15,
K = (M + 1) * (2*N - M + 2) / 2;
std::vector<double> C(K, 0.0);
std::vector<double> S(K - (N + 1), 0.0);
std::ifstream fin(filename.c_str());
std::string ss;
if (i != maxy+1) std::getline(fin, ss); // Skip first line
while (std::getline(fin, ss)) {
int n, m;
double c, s;
std::istringstream is(ss);
if (!(is >> n >> m >> c >> s))
throw std::runtime_error("Short read " + filename + ": " + ss);
if (i == maxy && n > 15)
continue;
if (i == maxy+2 && n <= 15)
continue;
storecos(C, N, M, c, n, m);
storesin(S, N, M, s, n, m);
}
storecoeff(fout, C, S, M, N);
}
} else if (model == "wmm2010" || model == "igrf11") {
// Download
// http://ngdc.noaa.gov/IAGA/vmod/geomag70_linux.tar.gz
// unpack
// wmm2010 coefficients are in geomag70_linux/WMM2010.COF
// igrf11 coefficients are in geomag70_linux/IGRF11.COF
std::string id = model == "wmm2010" ? "WMM2010A" : "IGRF11-A";
fout.write(id.c_str(), 8);
std::string filename = model == "wmm2010" ? "geomag70_linux/WMM2010.COF"
: "geomag70_linux-2010/IGRF11.COF";
std::ifstream fin(filename.c_str());
std::string ss;
bool start = true;
std::getline(fin, ss);
std::vector<double> C;
std::vector<double> S;
std::vector<double> C1;
std::vector<double> S1;
int N = 0, M = 0, N1 = 0, M1 = 0;
while (true) {
if (ss.size() == 0)
break;
std::istringstream is(ss);
int n, m;
double c, s, c1, s1;
if (start) {
std::string mm;
if (!(is >> mm >> mm >> N >> N1))
throw std::runtime_error("Short read on header");
M = N; M1 = N1;
int
K = (M + 1) * (2*N - M + 2) / 2,
K1 = (M1 + 1) * (2*N1 - M1 + 2) / 2;
C.resize(K);
S.resize(K - (N + 1));
C1.resize(K1);
S1.resize(K1 - (N1 + 1));
std::fill(C.begin(), C.end(), 0.0);
std::fill(S.begin(), S.end(), 0.0);
std::fill(C1.begin(), C1.end(), 0.0);
std::fill(S1.begin(), S1.end(), 0.0);
start = false;
} else {
if (!(is >> n >> m >> c >> s >> c1 >> s1))
throw std::runtime_error("Short read on data");
storecos(C, N, M, c, n, m);
storesin(S, N, M, s, n, m);
storecos(C1, N1, M1, c1, n, m);
storesin(S1, N1, M1, s1, n, m);
}
if (!std::getline(fin, ss))
ss = "";
if (ss.size() == 0 || (ss.size() >= 3 && ss.substr(0, 3) == " ")) {
if (ss.size() > 0 && N1 != 0)
throw std::runtime_error("Secular coeffs not last");
if (ss.size() == 0 && N1 == 0)
throw std::runtime_error("No secular coeffs");
storecoeff(fout, C, S, M, N);
if (ss.size() == 0)
storecoeff(fout, C1, S1, M1, N1);
start = true;
}
}
} else if (model == "wmm2015" || model == "wmm2015v2" ||
model == "wmm2020" || model == "igrf12" ||
model == "igrf13") {
// Download WMM2015COF.zip
// http://ngdc.noaa.gov/geomag/WMM/WMM_coeff.shtml
// wmm2015 coefficients are in WMM2015COF/WMM.COF
//
// Download WMM2015v2COF.zip
// https://www.ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015v2COF.zip
// wmm2015v2 coefficients are in WMM2015v2COF/WMM.COF
//
// Download WMM2020COF.zip
// http://ngdc.noaa.gov/geomag/WMM/WMM_coeff.shtml
// wmm2020 coefficients are in WMM2020COF/WMM.COF
//
// igrf12 coefficients
// http://ngdc.noaa.gov/IAGA/vmod/geomag70_linux.tar.gz
// igrf12 coefficients are in geomag70_linux/IGRF12.COF
//
// igrf13 coefficients
// https://www.ngdc.noaa.gov/IAGA/vmod/geomag70_linux.tar.gz
// igrf13 coefficients are in geomag70_linux/IGRF13.COF
std::string id = model == "wmm2015" ? "WMM2015A" :
(model == "wmm2015v2" ? "WMM2015B" :
(model == "wmm2020" ? "WMM2020A" :
(model == "igrf12" ? "IGRF12-A" : "IGRF13-A")));
fout.write(id.c_str(), 8);
std::string filename = model == "wmm2015" ? "WMM2015COF/WMM.COF"
: (model == "wmm2015v2" ? "WMM2015v2COF/WMM.COF"
: (model == "wmm2020" ? "WMM2020COF/WMM.COF"
: (model == "igrf12" ? "geomag70_linux-2015/IGRF12.COF"
: "geomag70_linux-2020/IGRF13.COF")));
std::ifstream fin(filename.c_str());
std::string ss;
bool start = true;
std::getline(fin, ss);
std::vector<double> C;
std::vector<double> S;
std::vector<double> C1;
std::vector<double> S1;
int N = 0, M = 0, N1 = 0, M1 = 0;
while (true) {
if (ss.size() == 0)
break;
std::istringstream is(ss);
int n, m;
double c, s, c1, s1;
if (start) {
if (model == "wmm2015" || model == "wmm2015v2" ||
model == "wmm2020") {
N = 12; N1 = 12;
} else {
std::string mm;
if (!(is >> mm >> mm >> N >> N1))
throw std::runtime_error("Short read on header");
}
M = N; M1 = N1;
int
K = (M + 1) * (2*N - M + 2) / 2,
K1 = (M1 + 1) * (2*N1 - M1 + 2) / 2;
C.resize(K);
S.resize(K - (N + 1));
C1.resize(K1);
S1.resize(K1 - (N1 + 1));
std::fill(C.begin(), C.end(), 0.0);
std::fill(S.begin(), S.end(), 0.0);
std::fill(C1.begin(), C1.end(), 0.0);
std::fill(S1.begin(), S1.end(), 0.0);
start = false;
} else {
if (!(is >> n >> m >> c >> s >> c1 >> s1)) {
std::cerr << ss << "\n";
throw std::runtime_error("Short read on data");
}
storecos(C, N, M, c, n, m);
storesin(S, N, M, s, n, m);
storecos(C1, N1, M1, c1, n, m);
storesin(S1, N1, M1, s1, n, m);
}
if (!std::getline(fin, ss))
ss = "";
if (model == "wmm2015" || model == "wmm2015v2" ||
model == "wmm2020") {
if (ss.size() && ss[0] == '9')
ss = "";
if (ss.size() == 0) {
storecoeff(fout, C, S, M, N);
storecoeff(fout, C1, S1, M1, N1);
}
} else {
if (ss.size() == 0 || (ss.size() >= 3 && ss.substr(0, 3) == " ")) {
if (ss.size() > 0 && N1 != 0)
throw std::runtime_error("Secular coeffs not last");
if (ss.size() == 0 && N1 == 0)
throw std::runtime_error("No secular coeffs");
storecoeff(fout, C, S, M, N);
if (ss.size() == 0)
storecoeff(fout, C1, S1, M1, N1);
start = true;
}
}
}
} else if (model == "egm2008" || model == "egm96" || model == "egm84"
|| model == "wgs84") {
std::string id = model == "egm2008" ? "EGM2008A" :
(model == "egm96" ? "EGM1996A" :
(model == "egm84" ? "EGM1984A" : "WGS1984A"));
fout.write(id.c_str(), 8);
for (int i = 0; i < 2; ++i) {
std::string filename = "../gravity/";
filename +=
model == "egm2008" ?
(i == 0 ? "EGM2008_to2190_TideFree" : "Zeta-to-N_to2160_egm2008") :
(model == "egm96" ?
(i == 0 ? "EGM96" : "CORRCOEF") :
(model == "egm84" ?
(i == 0 ? "egm180.nor" : "zeta84") :
(i == 0 ? "wgs84.cof" : "zeta84")));
std::ifstream fin(filename.c_str());
if (!fin.good())
throw std::runtime_error("File not found");
int
N = model == "egm2008" ? (i == 0 ? 2190 : 2160) :
(model == "egm96" ? 360 :
(model == "egm84" ? (i == 0 ? 180 : -1) :
(i == 0 ? 20 : -1))),
M = model == "egm2008" ? (i == 0 ? 2159 : 2160) :
(model == "egm96" ? 360 :
(model == "egm84" ? (i == 0 ? 180 : -1) :
(i == 0 ? 0 : -1))),
K = (M + 1) * (2*N - M + 2) / 2;
std::vector<double> C(K, 0.0);
std::vector<double> S(K - (N + 1), 0.0);
std::string ss;
while (std::getline(fin, ss)) {
std::string::size_type p = 0;
while (true) {
p = ss.find_first_of('D', p);
if (p < ss.size())
ss[p] = 'E';
else
break;
++p;
}
std::istringstream is(ss);
int n, m;
double c, s;
if (!(is >> n >> m >> c >> s))
throw std::runtime_error("Short read");
storecos(C, N, M, c, n, m);
storesin(S, N, M, s, n, m);
}
storecoeff(fout, C, S, M, N);
}
} else if (model == "dtm2006") {
std::string id = "DTM2006A";
fout.write(id.c_str(), 8);
int N = 2190, M = N;
int K = (M + 1) * (2*N - M + 2) / 2;
std::string filename
= "../gravity/Coeff_Height_and_Depth_to2190_DTM2006.0";
std::ifstream fin(filename.c_str());
std::vector<double> C(K, 0.0);
std::vector<double> S(K - (N + 1), 0.0);
std::string ss;
while (std::getline(fin, ss)) {
std::string::size_type p = 0;
while (true) {
p = ss.find_first_of('D', p);
if (p < ss.size())
ss[p] = 'E';
else
break;
++p;
}
std::istringstream is(ss);
int n, m;
double c, s;
if (!(is >> n >> m >> c >> s))
throw std::runtime_error("Short read");
storecos(C, N, M, c, n, m);
storesin(S, N, M, s, n, m);
}
storecoeff(fout, C, S, M, N);
} else {
std::cerr << "UNKNOWN MODEL " << model << "\n";
return 1;
}
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << "\n";
return 1;
}
return 0;
}

View File

@@ -0,0 +1,495 @@
#! /bin/sh
#
# tar.gz and zip distrib files copied to $DEVELSOURCE
# html documentation rsync'ed to $WEBDIST/htdocs/C++/$VERSION/
#
# Windows version ready to build in
# $WINDOWSBUILD/GeographicLib-$VERSION/BUILD-vc10{,-x64}
# after ./build installer is copied to
# $DEVELSOURCE/GeographicLib-$VERSION-win{32,64}.exe
#
# Built version ready to install in /usr/local in
# relc/GeographicLib-$VERSION/BUILD-system
#
# gita - check out from git, create package with cmake
# gitb - check out from git, check various builds in the non-release tree
# gitr - new release branch
# relb - release package, build with autoconf
# relc - release package, build with cmake
# relx - cmake release package inventory
# rely - autoconf release package inventory
# instb - installed files, autoconf
# instc - installed files, cmake
set -e
umask 0022
# The following files contain version information:
# pom.xml
# CMakeLists.txt (PROJECT_VERSION_* LIBVERSION_*)
# NEWS
# configure.ac (AC_INIT, GEOGRAPHICLIB_VERSION_* LT_*)
# develop/test-distribution.sh
# doc/GeographicLib.dox.in (3 places)
# maxima
# maxima/geodesic.mac
START=`date +%s`
DATE=`date +%F`
VERSION=2.1.2
SUFFIX=
DISTVERSION=$VERSION$SUFFIX
BRANCH=main
TEMP=/home/scratch/geographiclib-dist
if test `hostname` = petrel; then
DEVELSOURCE=$HOME/geographiclib
WINDEVELSOURCE=//datalake-pr-smb/vt-open/ckarney/geographiclib
WINDOWSBUILD=/var/tmp
else
DEVELSOURCE=/u/geographiclib
WINDEVELSOURCE=//datalake-pr-smb/vt-open/ckarney/geographiclib
WINDOWSBUILD=/u/temp
fi
WINDOWSBUILDWIN=//datalake-pr-smb/vt-open/ckarney/temp
GITSOURCE=file://$DEVELSOURCE
WEBDIST=/home/ckarney/web/geographiclib-web
mkdir -p $WEBDIST/htdocs/C++
NUMCPUS=4
HAVEINTEL=
test -d $TEMP || mkdir $TEMP
rm -rf $TEMP/*
mkdir $TEMP/gita # Package creation via cmake
mkdir $TEMP/gitb # Non release testing
mkdir $TEMP/gitr # For release branch
(cd $TEMP/gitr; git clone -b $BRANCH $GITSOURCE)
(cd $TEMP/gita; git clone -b $BRANCH file://$TEMP/gitr/geographiclib)
(cd $TEMP/gitb; git clone -b $BRANCH file://$TEMP/gitr/geographiclib)
echo ==============================================================
echo Make a source package in $TEMP/gita/geographiclib/BUILD
cd $TEMP/gita/geographiclib
cmake -S . -B BUILD
(cd BUILD && make dist)
# cp $TEMP/gita/geographiclib/BUILD/distrib/GeographicLib-$DISTVERSION.{zip,tar.gz} $DEVELSOURCE/data-distrib/distrib-C++/
echo ==============================================================
echo Unpack source package in $TEMP/rel bcx
mkdir $TEMP/rel{b,c,x}
tar xfpzC BUILD/distrib/GeographicLib-$DISTVERSION.tar.gz $TEMP/relb # Version for autoconf
tar xfpzC BUILD/distrib/GeographicLib-$DISTVERSION.tar.gz $TEMP/relc # Version for cmake+mvn
tar xfpzC BUILD/distrib/GeographicLib-$DISTVERSION.tar.gz $TEMP/relx # for listing
echo ==============================================================
echo Unpack devel cmake distribution in $TEMP/relx and list in $TEMP/files.x
(
cd $TEMP/relx
find . -type f | sort -u > ../files.x
)
echo ==============================================================
echo Make a release for Windows testing in $WINDOWSBUILD/GeographicLib-$VERSION
rm -rf $WINDOWSBUILD/GeographicLib-$VERSION
unzip -qq -d $WINDOWSBUILD BUILD/distrib/GeographicLib-$DISTVERSION.zip
cat > $WINDOWSBUILD/GeographicLib-$VERSION/mvn-build <<'EOF'
#! /bin/sh -exv
unset GEOGRAPHICLIB_DATA
# for v in 2019 2017 2015 2013 2012 2010; do
for v in 2019 2017 2015; do
for a in 64 32; do
echo ========== maven $v-$a ==========
rm -rf c:/scratch/geog-mvn-$v-$a
mvn -Dcmake.compiler=vc$v -Dcmake.arch=$a \
-Dcmake.project.bin.directory=c:/scratch/geog-mvn-$v-$a install
done
done
EOF
chmod +x $WINDOWSBUILD/GeographicLib-$VERSION/mvn-build
cp pom.xml $WINDOWSBUILD/GeographicLib-$VERSION/
# for ver in 10 11 12 14 15 16; do
for ver in 14 15 16; do
for arch in win32 x64; do
pkg=vc$ver-$arch
gen="Visual Studio $ver"
installer=
# N.B. update CPACK_NSIS_INSTALL_ROOT in CMakeLists.txt and
# update documentation examples if VS version for binary
# installer changes.
test "$ver" = 14 && installer=y
(
echo "#! /bin/sh -exv"
echo echo ========== cmake $pkg ==========
echo b=c:/scratch/geog-$pkg
echo rm -rf \$b \$bc //datalake-pr-smb/vt-open/ckarney/pkg-$pkg/GeographicLib-$VERSION/\*
echo 'unset GEOGRAPHICLIB_DATA'
echo cmake -G \"$gen\" -A $arch -D BUILD_BOTH_LIBS=ON -D CMAKE_INSTALL_PREFIX=//datalake-pr-smb/vt-open/ckarney/pkg-$pkg/GeographicLib-$VERSION -D PACKAGE_DEBUG_LIBS=ON -D CONVERT_WARNINGS_TO_ERRORS=ON -D EXAMPLEDIR= -S . -B \$b
echo cmake --build \$b --config Debug --target ALL_BUILD
echo cmake --build \$b --config Debug --target RUN_TESTS
echo cmake --build \$b --config Debug --target INSTALL
echo cmake --build \$b --config Release --target ALL_BUILD
echo cmake --build \$b --config Release --target exampleprograms
echo cmake --build \$b --config Release --target RUN_TESTS
echo cmake --build \$b --config Release --target INSTALL
echo cmake --build \$b --config Release --target PACKAGE
test "$installer" &&
echo cp \$b/GeographicLib-$DISTVERSION-*.exe $WINDEVELSOURCE/ ||
true
) > $WINDOWSBUILD/GeographicLib-$VERSION/build-$pkg
chmod +x $WINDOWSBUILD/GeographicLib-$VERSION/build-$pkg
done
done
cat > $WINDOWSBUILD/GeographicLib-$VERSION/test-all <<'EOF'
#! /bin/sh
(
for d in build-*; do
./$d
done
./mvn-build
) >& build.log
EOF
chmod +x $WINDOWSBUILD/GeographicLib-$VERSION/test-all
echo ==============================================================
echo Set up release branch in $TEMP/gitr/geographiclib
cd $TEMP/gitr/geographiclib
git checkout release
git config user.email charles@karney.com
git ls-files | sort > ../files.old
(
cd $TEMP/gitb/geographiclib
git ls-files | sort
) > ../files.current
cut -f3- -d/ $TEMP/files.x | sort > ../files.new
(
cd ..
comm -23 files.old files.new | grep -v gitattributes > files.delete || true
comm -23 files.new files.current > files.relonly
comm -12 files.new files.current > files.main
comm -13 files.delete files.new > files.add
comm -13 files.old files.new > files.add
comm -12 files.old files.new > files.common
)
(
S=$TEMP/relx/GeographicLib-$VERSION
C=$TEMP/gitb/geographiclib
test -s ../files.delete && xargs git rm -f < ../files.delete
cat ../files.main ../files.relonly |
sed -e 's%[^/][^/]*$%%' -e 's%/$%%' | sort -u | grep -v '^$' |
while read d; do
test -d $d || mkdir -p $d
done
while read f; do
if cmp $S/$f $f >& /dev/null; then :
else
cp -p $S/$f $f
git add $f
fi
done < ../files.relonly
while read f; do
test -d `dirname $f` || mkdir `dirname $f`
git checkout $BRANCH $f
if cmp $S/$f $f >& /dev/null; then :
else
cp -p $S/$f $f
git add $f
fi
done < ../files.main
git checkout $BRANCH .gitattributes
for i in 1 2 3 4 5; do
find -type d -empty | xargs -r rmdir
done
)
rm -rf GeographicLib-$VERSION
rm -f java/.gitignore
for ((i=0; i<7; ++i)); do
find * -type d -empty | xargs -r rmdir
done
echo ==============================================================
echo CMake build in $TEMP/relc/GeographicLib-$VERSION/BUILD install to $TEMP/instc
cd $TEMP/relc/GeographicLib-$VERSION
cmake -D BUILD_BOTH_LIBS=ON -D BUILD_DOCUMENTATION=ON -D USE_BOOST_FOR_EXAMPLES=ON -D CONVERT_WARNINGS_TO_ERRORS=ON -D CMAKE_INSTALL_PREFIX=$TEMP/instc -S . -B BUILD
(
cd BUILD
make package_source
make -j$NUMCPUS all
make test
make exampleprograms
make install
# rsync -a --delete doc/html/ $WEBDIST/htdocs/C++/$VERSION/
)
echo ==============================================================
echo List installed files fron cmake build in $TEMP/instc to $TEMP/files.c
(
cd $TEMP/instc
find . -type f | sort -u > ../files.c
)
echo ==============================================================
echo Make distribution from release tree with cmake
cd $TEMP/relc/GeographicLib-$VERSION
cmake -S . -B BUILD-dist
(cd BUILD-dist && make package_source)
echo ==============================================================
echo Unpack release cmake distribution in $TEMP/relz and list in $TEMP/files.z
mkdir $TEMP/relz
tar xfpzC BUILD-dist/GeographicLib-$VERSION.tar.gz $TEMP/relz
(
cd $TEMP/relz
find . -type f | sort -u > ../files.z
)
echo ==============================================================
echo CMake build in $TEMP/relc/GeographicLib-$VERSION/BUILD-system install to /usr/local
cmake -D BUILD_BOTH_LIBS=ON -D CONVERT_WARNINGS_TO_ERRORS=ON -S . -B BUILD-system
(cd BUILD-system && make -j$NUMCPUS all&& make test)
if test "$HAVEINTEL"; then
echo ==============================================================
echo CMake build for intel in $TEMP/relc/GeographicLib-$VERSION/BUILD-intel
env FC=ifort CC=icc CXX=icpc cmake -D BUILD_BOTH_LIBS=ON -D CONVERT_WARNINGS_TO_ERRORS=ON -S . -B BUILD-intel
(
cd BUILD-intel
make -j$NUMCPUS all
make test
make exampleprograms
)
fi
echo ==============================================================
echo Check build with configure in $TEMP/relb/GeographicLib-$VERSION/BUILD-config to $TEMP/instb
cd $TEMP/relb/GeographicLib-$VERSION
mkdir BUILD-config
cd BUILD-config
../configure --prefix=$TEMP/instb
make -j$NUMCPUS
make install
cd ..
if test "$HAVEINTEL"; then
echo ==============================================================
echo Check build with configure + intell in $TEMP/relb/GeographicLib-$VERSION/BUILD-config-intel
mkdir BUILD-config-intel
cd BUILD-config-intel
env FC=ifort CC=icc CXX=icpc ../configure
make -j$NUMCPUS
cd ..
fi
echo ==============================================================
echo Make source dist with autoconf $TEMP/relb/GeographicLib-$VERSION/BUILD-dist
mkdir BUILD-dist
cd BUILD-dist
../configure
make dist-gzip
echo ==============================================================
echo Unpack release autoconf distribution in $TEMP/rely and list in $TEMP/files.z
mkdir $TEMP/rely
tar xfpzC geographiclib-$VERSION.tar.gz $TEMP/rely
mv $TEMP/rely/{geographiclib,GeographicLib}-$VERSION
cd $TEMP/rely
find . -type f | sort -u > ../files.y
echo ==============================================================
echo List installed files fron autoconf build in $TEMP/instb to $TEMP/files.b
mv $TEMP/instb/share/doc/{geographiclib,GeographicLib}
cd $TEMP/instb
find . -type f | sort -u > ../files.b
echo ==============================================================
echo CMake build of devel tree in $TEMP/gitb/geographiclib/BUILD
cd $TEMP/gitb/geographiclib
cmake -D BUILD_BOTH_LIBS=ON -D BUILD_DOCUMENTATION=ON -D USE_BOOST_FOR_EXAMPLES=ON -D CONVERT_WARNINGS_TO_ERRORS=ON -S . -B BUILD
(cd BUILD && make -j$NUMCPUS && make -j$NUMCPUS develprograms)
cp $DEVELSOURCE/include/mpreal.h include/
# Skip 4 for now because of various boost bugs
for p in 1 3 5; do
echo ==============================================================
echo CMake build of devel tree at precision $p in $TEMP/gitb/geographiclib/BUILD-$p
mkdir BUILD-$p
cmake -D USE_BOOST_FOR_EXAMPLES=ON -D GEOGRAPHICLIB_PRECISION=$p -S . -B BUILD-$p
(
cd BUILD-$p
make -j$NUMCPUS all
if test $p -ne 1; then
make test
fi
make -j$NUMCPUS develprograms
make -j$NUMCPUS exampleprograms
)
done
echo ==============================================================
echo Compile and run little test program
cd $TEMP
cat > testprogram.cpp <<EOF
#include <iostream>
#include <iomanip>
#include <GeographicLib/Constants.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/LambertConformalConic.hpp>
int main() {
using namespace GeographicLib;
double
// These are the constants for Pennsylvania South, EPSG:3364
// https://www.spatialreference.org/ref/epsg/3364/
a = Constants::WGS84_a(), // major radius
f = 1/298.257222101, // inverse flattening (GRS80)
lat1 = DMS::Decode(40,58), // standard parallel 1
lat2 = DMS::Decode(39,56), // standard parallel 2
k1 = 1, // scale on std parallels
lat0 = DMS::Decode(39,20), // latitude of origin
lon0 = -DMS::Decode(77,45), // longitude of origin
fe = 600000, // false easting
fn = 0; // false northing
LambertConformalConic PASouth(a, f, lat1, lat2, k1);
double x0, y0;
PASouth.Forward(lon0, lat0, lon0, x0, y0); // Transform origin point
x0 -= fe; y0 -= fn; // Combine result with false origin
double lat = 39.95, lon = -75.17; // Philadelphia
double x, y;
PASouth.Forward(lon0, lat, lon, x, y);
x -= x0; y -= y0; // Philadelphia in PA South coordinates
std::cout << std::fixed << std::setprecision(3)
<< x << " " << y << "\n";
return 0;
}
EOF
for i in b c; do
cp testprogram.cpp testprogram$i.cpp
g++ -c -g -O3 -I$TEMP/inst$i/include testprogram$i.cpp
g++ -g -o testprogram$i testprogram$i.o -Wl,-rpath=$TEMP/inst$i/lib \
-L$TEMP/inst$i/lib -lGeographicLib
./testprogram$i
done
echo ==============================================================
echo Verify library versions of cmake and autoconf builds are the same and other checks
libversion=`find $TEMP/instc/lib -type f \
-name 'libGeographicLib.so.*' -printf "%f" |
sed 's/libGeographicLib\.so\.//'`
test -f $TEMP/instb/lib/libGeographicLib.so.$libversion ||
echo autoconf/cmake library so mismatch
CONFIG_FILE=$TEMP/gitr/geographiclib/configure
CONFIG_MAJOR=`grep ^GEOGRAPHICLIB_VERSION_MAJOR= $CONFIG_FILE | cut -f2 -d=`
CONFIG_MINOR=`grep ^GEOGRAPHICLIB_VERSION_MINOR= $CONFIG_FILE | cut -f2 -d=`
CONFIG_PATCH=`grep ^GEOGRAPHICLIB_VERSION_PATCH= $CONFIG_FILE | cut -f2 -d=`
CONFIG_VERSIONA=`grep ^PACKAGE_VERSION= $CONFIG_FILE | cut -f2 -d= |
cut -f2 -d\'`
CONFIG_VERSION=$CONFIG_MAJOR.$CONFIG_MINOR
test "$CONFIG_PATCH" = 0 || CONFIG_VERSION=$CONFIG_VERSION.$CONFIG_PATCH
test "$CONFIG_VERSION" = "$VERSION" || echo autoconf version number mismatch
test "$CONFIG_VERSIONA" = "$VERSION" || echo autoconf version string mismatch
cd $TEMP/relx/GeographicLib-$VERSION
(
echo Files with trailing spaces:
find . -type f | egrep -v 'config\.guess|Makefile\.in|\.m4|\.png|\.gif' |
while read f; do
tr -d '\r' < $f | grep ' $' > /dev/null && echo $f || true
done
echo
echo Files with tabs:
find . -type f |
egrep -v '[Mm]akefile|\.html|\.m4|\.png|\.gif' |
egrep -v '\.sh|depcomp|install-sh|/config\.|configure$|compile|missing' |
xargs grep -l ' ' || true
echo
echo Files with multiple newlines:
find . -type f |
egrep -v \
'/Makefile\.in|\.1\.html|\.png|\.gif|/ltmain|/config|\.m4' |
while read f; do
tr 'X\n' 'xX' < $f | grep XXX > /dev/null && echo $f || true
done
echo
echo Files with no newline at end:
find . -type f |
egrep -v '\.png|\.gif' |
while read f; do
n=`tail -1 $f | wc -l`; test $n -eq 0 && echo $f || true
done
echo
echo Files with extra newlines at end:
find . -type f |
egrep -v '/configure|/ltmain.sh|\.png|\.gif|\.1\.html' |
while read f; do
n=`tail -1 $f | wc -w`; test $n -eq 0 && echo $f || true
done
echo
) > $TEMP/badfiles.txt
cat $TEMP/badfiles.txt
cat > $TEMP/tasks.txt <<EOF
# install built version
sudo make -C $TEMP/relc/GeographicLib-$VERSION/BUILD-system install
# commit and tag release branch
cd $TEMP/gitr/geographiclib
# Check .gitignore files!
git add -A
git commit -m "Version $VERSION ($DATE)"
git tag -m "Version $VERSION ($DATE)" r$VERSION
git push
git push --tags
# tag main branch
cd $DEVELSOURCE
git tag -m "Version $VERSION ($DATE)" v$VERSION
git push --all
git push --tags
# Also to do
# post release notices
# set default download files
# make -f makefile-admin distrib-{cgi,html}
# update home brew
# dir = /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core
# branch = geographiclib/$VERSION
# file = Formula/geographiclib.rb
# brew install --build-from-source geographiclib
# commit message = geographiclib $VERSION
# update vcpkg git@github.com:microsoft/vcpkg
# dir = ports/geographiclib
# ./vcpkg install 'geographiclib[tools]'
# binaries in installed/x64-linux/tools/geographiclib
# libs in installed/x64-linux/{include,lib,debug/lib}
# ./vcpkg x-add-version geographiclib
# commit message = [geographiclib] Update to version $VERSION
# update conda-forge
# url = git@github.com:conda-forge/geographiclib-cpp-feedstock
# conda build recipe
# upload matlab packages
# update binaries for cgi applications
# trigger build on build-open
EOF
echo cat $TEMP/tasks.txt
cat $TEMP/tasks.txt
END=`date +%s`
echo Elapsed time $((END-START)) secs

9
libs/geographiclib/doc/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
html
Makefile.in
Makefile
*.tmp
*.1.html
CMakeFiles
cmake_install.cmake
done
doxygen.log

View File

@@ -0,0 +1,5 @@
Options +Indexes +FollowSymLinks
IndexOptions FancyIndexing SuppressSize SuppressDescription
IndexOrderDefault Descending Date
IndexIgnore HEADER.html FOOTER.html
ReadmeName FOOTER.html

View File

@@ -0,0 +1,73 @@
# Where the html versions of the man pages (extension .1.html) are
# found.
# Where to find the *.usage files for the --help option.
if (RELEASE)
set (MANDIR ${PROJECT_SOURCE_DIR}/man)
else ()
set (MANDIR ${PROJECT_BINARY_DIR}/man)
endif ()
# Build up a list of the .1.html files.
set (HTMLMAN)
foreach (TOOL ${TOOLS})
set (HTMLMAN ${HTMLMAN} ${MANDIR}/${TOOL}.1.html)
endforeach ()
# Run doxygen, if available
# First assemble a list of all the files the documentation uses. Add a
# dependency on htmlman (from man/CMakeLists.txt). Use html/index.html
# as the make target. To make this target, copy the non-doxygen
# generated files into html/. Run doxfile.in thru cmake's config
# process so that absolute path names are used and so that the pathnames
# are properly stripped by doxygen (via STRIP_FROM_PATH). The
# distrib-doc target copies the html directory into the source tree.
# If doxygen is not available, only the install step (from the source
# tree) is done.
file (MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html-stage)
if (BUILD_DOCUMENTATION)
configure_file (GeographicLib.dox.in GeographicLib.dox @ONLY)
configure_file (doxyfile.in doxyfile @ONLY)
file (GLOB CXXSOURCES
../src/[A-Za-z]*.cpp ../include/GeographicLib/[A-Za-z]*.hpp
../tools/[A-Za-z]*.cpp ../examples/[A-Za-z]*.cpp
../examples/[A-Za-z]*.hpp)
file (GLOB EXTRA_FILES ../maxima/[A-Za-z]*.mac
tmseries30.html geodseries30.html ../LICENSE.txt)
file (GLOB FIGURES *.png *.svg *.gif)
file (COPY ${EXTRA_FILES} DESTINATION html-stage)
add_custom_target (doc ALL
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/html/index.html)
if (NOT RELEASE)
add_dependencies (doc htmlman)
endif ()
if (CMAKE_VERSION VERSION_LESS 3.17.0)
set (RMDIR remove_directory)
else ()
set (RMDIR rm -rf)
endif ()
add_custom_command (OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/html/index.html
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doxyfile
${CMAKE_CURRENT_BINARY_DIR}/GeographicLib.dox
${CXXSOURCES} ${EXTRA_FILES} ${FIGURES} ${HTMLMAN}
COMMAND ${CMAKE_COMMAND} -E copy ${HTMLMAN} html-stage
COMMAND ${CMAKE_COMMAND} -E ${RMDIR} html
COMMAND ${CMAKE_COMMAND} -E copy_directory html-stage html
COMMAND ${DOXYGEN_EXECUTABLE} doxyfile > doxygen.log
COMMENT "Generating C++ documentation tree")
else ()
file (COPY ../LICENSE.txt DESTINATION html)
configure_file (index.html.in html/index.html)
configure_file (utilities.html.in html/utilities.html)
endif ()
if (DOCDIR)
install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
DESTINATION ${DOCDIR})
endif ()

View File

@@ -0,0 +1,3 @@
<a href="..">GeographicLib home</a>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
<html>
<head>
<title>
Index of https://geographiclib.sourceforge.io/C++
</title>
<link rel="stylesheet" type="text/css" href="../default.css">
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<h3>C++ library GeographicLib</h3>
<p>
Each numbered directory gives the documentation for that specific
version. <a href="doc">doc</a> points to the latest stable
version.
</p>

View File

@@ -0,0 +1,132 @@
EXTRAFILES = $(srcdir)/tmseries30.html $(srcdir)/geodseries30.html
FIGURES = \
$(srcdir)/gauss-krueger-graticule.png \
$(srcdir)/thompson-tm-graticule.png \
$(srcdir)/gauss-krueger-convergence-scale.png \
$(srcdir)/gauss-schreiber-graticule-a.png \
$(srcdir)/gauss-krueger-graticule-a.png \
$(srcdir)/thompson-tm-graticule-a.png \
$(srcdir)/gauss-krueger-error.png \
$(srcdir)/meridian-measures.png \
$(srcdir)/normal-gravity-potential-1.svg \
$(srcdir)/vptree.gif
HPPFILES = \
$(top_srcdir)/include/GeographicLib/Accumulator.hpp \
$(top_srcdir)/include/GeographicLib/AlbersEqualArea.hpp \
$(top_srcdir)/include/GeographicLib/AzimuthalEquidistant.hpp \
$(top_srcdir)/include/GeographicLib/CassiniSoldner.hpp \
$(top_srcdir)/include/GeographicLib/Constants.hpp \
$(top_srcdir)/include/GeographicLib/DMS.hpp \
$(top_srcdir)/include/GeographicLib/Ellipsoid.hpp \
$(top_srcdir)/include/GeographicLib/EllipticFunction.hpp \
$(top_srcdir)/include/GeographicLib/GARS.hpp \
$(top_srcdir)/include/GeographicLib/GeoCoords.hpp \
$(top_srcdir)/include/GeographicLib/Geocentric.hpp \
$(top_srcdir)/include/GeographicLib/Geodesic.hpp \
$(top_srcdir)/include/GeographicLib/GeodesicExact.hpp \
$(top_srcdir)/include/GeographicLib/GeodesicLine.hpp \
$(top_srcdir)/include/GeographicLib/GeodesicLineExact.hpp \
$(top_srcdir)/include/GeographicLib/Geohash.hpp \
$(top_srcdir)/include/GeographicLib/Geoid.hpp \
$(top_srcdir)/include/GeographicLib/Georef.hpp \
$(top_srcdir)/include/GeographicLib/Gnomonic.hpp \
$(top_srcdir)/include/GeographicLib/LambertConformalConic.hpp \
$(top_srcdir)/include/GeographicLib/LocalCartesian.hpp \
$(top_srcdir)/include/GeographicLib/Math.hpp \
$(top_srcdir)/include/GeographicLib/MGRS.hpp \
$(top_srcdir)/include/GeographicLib/OSGB.hpp \
$(top_srcdir)/include/GeographicLib/PolarStereographic.hpp \
$(top_srcdir)/include/GeographicLib/PolygonArea.hpp \
$(top_srcdir)/include/GeographicLib/TransverseMercatorExact.hpp \
$(top_srcdir)/include/GeographicLib/TransverseMercator.hpp \
$(top_srcdir)/include/GeographicLib/UTMUPS.hpp
ALLSOURCES = \
$(top_srcdir)/src/AlbersEqualArea.cpp \
$(top_srcdir)/src/AzimuthalEquidistant.cpp \
$(top_srcdir)/src/CassiniSoldner.cpp \
$(top_srcdir)/src/DMS.cpp \
$(top_srcdir)/src/Ellipsoid.cpp \
$(top_srcdir)/src/EllipticFunction.cpp \
$(top_srcdir)/src/GARS.cpp \
$(top_srcdir)/src/GeoCoords.cpp \
$(top_srcdir)/src/Geocentric.cpp \
$(top_srcdir)/src/Geodesic.cpp \
$(top_srcdir)/src/GeodesicLine.cpp \
$(top_srcdir)/src/Geohash.cpp \
$(top_srcdir)/src/Geoid.cpp \
$(top_srcdir)/src/Georef.cpp \
$(top_srcdir)/src/Gnomonic.cpp \
$(top_srcdir)/src/LambertConformalConic.cpp \
$(top_srcdir)/src/LocalCartesian.cpp \
$(top_srcdir)/src/MGRS.cpp \
$(top_srcdir)/src/OSGB.cpp \
$(top_srcdir)/src/PolarStereographic.cpp \
$(top_srcdir)/src/PolygonArea.cpp \
$(top_srcdir)/src/TransverseMercator.cpp \
$(top_srcdir)/src/TransverseMercatorExact.cpp \
$(top_srcdir)/src/UTMUPS.cpp \
$(top_srcdir)/tools/CartConvert.cpp \
$(top_srcdir)/tools/ConicProj.cpp \
$(top_srcdir)/tools/GeodesicProj.cpp \
$(top_srcdir)/tools/GeoConvert.cpp \
$(top_srcdir)/tools/GeodSolve.cpp \
$(top_srcdir)/tools/GeoidEval.cpp \
$(top_srcdir)/tools/Gravity.cpp \
$(top_srcdir)/tools/Planimeter.cpp \
$(top_srcdir)/tools/TransverseMercatorProj.cpp
MANPAGES = \
../man/CartConvert.1.html \
../man/ConicProj.1.html \
../man/GeodesicProj.1.html \
../man/GeoConvert.1.html \
../man/GeodSolve.1.html \
../man/GeoidEval.1.html \
../man/Gravity.1.html \
../man/MagneticField.1.html \
../man/Planimeter.1.html \
../man/RhumbSolve.1.html \
../man/TransverseMercatorProj.1.html
doc: html/index.html
if HAVE_DOXYGEN
manpages: $(MANPAGES)
if test -d html; then rm -rf html/*; else mkdir html; fi
cp $^ html/
touch $@
html/index.html: manpages doxyfile.in GeographicLib.dox.in \
$(HPPFILES) $(ALLSOURCES) $(EXTRAFILES) $(FIGURES)
cp -p $(EXTRAFILES) $(top_srcdir)/maxima/*.mac \
$(top_srcdir)/LICENSE.txt html/
sed -e "s%@PROJECT_VERSION@%$(VERSION)%g" \
$(srcdir)/GeographicLib.dox.in > GeographicLib.dox
sed -e "s%@PROJECT_SOURCE_DIR@%$(top_srcdir)%g" \
-e "s%@PROJECT_BINARY_DIR@%..%g" \
-e "s%@PROJECT_VERSION@%$(VERSION)%g" \
$(srcdir)/doxyfile.in | $(DOXYGEN) -
else
html/index.html: index.html.in utilities.html.in
if test -d html; then rm -rf html/*; else mkdir html; fi
cp $(top_srcdir)/LICENSE.txt html/
sed -e "s%@PROJECT_VERSION@%$(VERSION)%g" \
$(srcdir)/utilities.html.in > html/utilities.html
sed -e "s%@PROJECT_VERSION@%$(VERSION)%g" \
$(srcdir)/index.html.in > html/index.html
endif
maintainer-clean-local:
rm -rf html manpages
htmldir=$(DESTDIR)$(docdir)/html
install-doc: html/index.html
$(INSTALL) -d $(htmldir)
$(INSTALL) -m 644 `dirname $<`/*.* $(htmldir)
-test -f `dirname $<`/search/search.js && \
$(INSTALL) -d $(htmldir)/search && \
$(INSTALL) -m 644 `dirname $<`/search/*.* $(htmldir)/search || true

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
<html>
<head>
<title>GeographicLib-@PROJECT_VERSION@ documentation</title>
<meta HTTP-EQUIV="Refresh"
CONTENT="0; URL=https://geographiclib.sourceforge.io/C++/@PROJECT_VERSION@/index.html">
</head>
<body topmargin=10 leftmargin=10>
<h3>
<blockquote>
<em>
Online documentation for GeographicLib version
@PROJECT_VERSION@ is available at
<center>
<a href="https://geographiclib.sourceforge.io/C++/@PROJECT_VERSION@/index.html">
https://geographiclib.sourceforge.io/C++/@PROJECT_VERSION@/index.html</a>.
</center>
<br>
You will be redirected there. Click on the link to go there
directly.
</em>
</blockquote>
</h3>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -0,0 +1,170 @@
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" style="fill-opacity:1; color-rendering:auto; color-interpolation:auto; stroke:black; text-rendering:auto; stroke-linecap:square; stroke-miterlimit:10; stroke-opacity:1; shape-rendering:auto; fill:black; stroke-dasharray:none; font-weight:normal; stroke-width:1; font-family:'Dialog'; font-style:normal; stroke-linejoin:miter; font-size:12px; stroke-dashoffset:0; image-rendering:auto;" width="566" height="396" xmlns="http://www.w3.org/2000/svg"
><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs"
/><g
><defs id="defs1"
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1"
><path d="M0 0 L566 0 L566 396 L0 396 L0 0 Z"
/></clipPath
><font horiz-adv-x="60.009766" id="font1"
><font-face ascent="92.822266" descent="23.583984" units-per-em="100" style="font-style:normal; font-family:SansSerif; font-weight:normal;"
/><missing-glyph horiz-adv-x="60.009766" d="M4.9844 -17.6719 L4.9844 70.5156 L54.9844 70.5156 L54.9844 -17.6719 L4.9844 -17.6719 ZM10.5938 -12.1094 L49.4219 -12.1094 L49.4219 64.8906 L10.5938 64.8906 L10.5938 -12.1094 Z"
/><glyph unicode="0" horiz-adv-x="63.623047" d="M31.7812 66.4062 Q24.1719 66.4062 20.3359 58.9141 Q16.5 51.4219 16.5 36.375 Q16.5 21.3906 20.3359 13.8906 Q24.1719 6.3906 31.7812 6.3906 Q39.4531 6.3906 43.2891 13.8906 Q47.125 21.3906 47.125 36.375 Q47.125 51.4219 43.2891 58.9141 Q39.4531 66.4062 31.7812 66.4062 ZM31.7812 74.2188 Q44.0469 74.2188 50.5156 64.5234 Q56.9844 54.8281 56.9844 36.375 Q56.9844 17.9688 50.5156 8.2734 Q44.0469 -1.4219 31.7812 -1.4219 Q19.5312 -1.4219 13.0625 8.2734 Q6.5938 17.9688 6.5938 36.375 Q6.5938 54.8281 13.0625 64.5234 Q19.5312 74.2188 31.7812 74.2188 Z"
/><glyph unicode="1" horiz-adv-x="63.623047" d="M12.4062 8.2969 L28.5156 8.2969 L28.5156 63.9219 L10.9844 60.4062 L10.9844 69.3906 L28.4219 72.9062 L38.2812 72.9062 L38.2812 8.2969 L54.3906 8.2969 L54.3906 0 L12.4062 0 L12.4062 8.2969 Z"
/><glyph unicode="2" horiz-adv-x="63.623047" d="M19.1875 8.2969 L53.6094 8.2969 L53.6094 0 L7.3281 0 L7.3281 8.2969 Q12.9375 14.1094 22.6328 23.8984 Q32.3281 33.6875 34.8125 36.5312 Q39.5469 41.8438 41.4297 45.5312 Q43.3125 49.2188 43.3125 52.7812 Q43.3125 58.5938 39.2344 62.2578 Q35.1562 65.9219 28.6094 65.9219 Q23.9688 65.9219 18.8203 64.3125 Q13.6719 62.7031 7.8125 59.4219 L7.8125 69.3906 Q13.7656 71.7812 18.9453 73 Q24.125 74.2188 28.4219 74.2188 Q39.75 74.2188 46.4844 68.5547 Q53.2188 62.8906 53.2188 53.4219 Q53.2188 48.9219 51.5391 44.8984 Q49.8594 40.875 45.4062 35.4062 Q44.1875 33.9844 37.6484 27.2188 Q31.1094 20.4531 19.1875 8.2969 Z"
/><glyph unicode="3" horiz-adv-x="63.623047" d="M40.5781 39.3125 Q47.6562 37.7969 51.6328 33.0078 Q55.6094 28.2188 55.6094 21.1875 Q55.6094 10.4062 48.1875 4.4922 Q40.7656 -1.4219 27.0938 -1.4219 Q22.5156 -1.4219 17.6562 -0.5156 Q12.7969 0.3906 7.625 2.2031 L7.625 11.7188 Q11.7188 9.3281 16.6016 8.1094 Q21.4844 6.8906 26.8125 6.8906 Q36.0781 6.8906 40.9375 10.5469 Q45.7969 14.2031 45.7969 21.1875 Q45.7969 27.6406 41.2812 31.2734 Q36.7656 34.9062 28.7188 34.9062 L20.2188 34.9062 L20.2188 43.0156 L29.1094 43.0156 Q36.375 43.0156 40.2344 45.9219 Q44.0938 48.8281 44.0938 54.2969 Q44.0938 59.9062 40.1172 62.9141 Q36.1406 65.9219 28.7188 65.9219 Q24.6562 65.9219 20.0156 65.0391 Q15.375 64.1562 9.8125 62.3125 L9.8125 71.0938 Q15.4375 72.6562 20.3438 73.4375 Q25.25 74.2188 29.5938 74.2188 Q40.8281 74.2188 47.3672 69.1172 Q53.9062 64.0156 53.9062 55.3281 Q53.9062 49.2656 50.4375 45.0938 Q46.9688 40.9219 40.5781 39.3125 Z"
/><glyph unicode="R" horiz-adv-x="69.48242" d="M44.3906 34.1875 Q47.5625 33.1094 50.5625 29.5938 Q53.5625 26.0781 56.5938 19.9219 L66.6094 0 L56 0 L46.6875 18.7031 Q43.0625 26.0312 39.6719 28.4219 Q36.2812 30.8125 30.4219 30.8125 L19.6719 30.8125 L19.6719 0 L9.8125 0 L9.8125 72.9062 L32.0781 72.9062 Q44.5781 72.9062 50.7344 67.6797 Q56.8906 62.4531 56.8906 51.9062 Q56.8906 45.0156 53.6875 40.4766 Q50.4844 35.9375 44.3906 34.1875 ZM19.6719 64.7969 L19.6719 38.9219 L32.0781 38.9219 Q39.2031 38.9219 42.8438 42.2188 Q46.4844 45.5156 46.4844 51.9062 Q46.4844 58.2969 42.8438 61.5469 Q39.2031 64.7969 32.0781 64.7969 L19.6719 64.7969 Z"
/><glyph unicode="Z" horiz-adv-x="68.50586" d="M5.6094 72.9062 L62.8906 72.9062 L62.8906 65.375 L16.7969 8.2969 L64.0156 8.2969 L64.0156 0 L4.5 0 L4.5 7.5156 L50.5938 64.5938 L5.6094 64.5938 L5.6094 72.9062 Z"
/></font
></defs
><g style="fill:white; stroke:white;"
><rect x="0" y="0" width="566" style="clip-path:url(#clipPath1); stroke:none;" height="396"
/></g
><g style="fill:white; text-rendering:optimizeSpeed; color-rendering:optimizeSpeed; image-rendering:optimizeSpeed; shape-rendering:crispEdges; color-interpolation:sRGB; stroke:white;"
><rect x="0" width="566" height="396" y="0" style="stroke:none;"
/><path style="stroke:none;" d="M40 353.6667 L549 353.6667 L549 14.3333 L40 14.3333 Z"
/></g
><g style="fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; stroke-linejoin:round; color-interpolation:linearRGB; stroke:rgb(38,38,38); stroke-width:0.6667;"
><line y2="353.6667" style="fill:none;" x1="40" x2="549" y1="353.6667"
/><line y2="14.3333" style="fill:none;" x1="40" x2="549" y1="14.3333"
/><line y2="348.5767" style="fill:none;" x1="40" x2="40" y1="353.6667"
/><line y2="348.5767" style="fill:none;" x1="209.6667" x2="209.6667" y1="353.6667"
/><line y2="348.5767" style="fill:none;" x1="379.3333" x2="379.3333" y1="353.6667"
/><line y2="348.5767" style="fill:none;" x1="549" x2="549" y1="353.6667"
/><line y2="19.4233" style="fill:none;" x1="40" x2="40" y1="14.3333"
/><line y2="19.4233" style="fill:none;" x1="209.6667" x2="209.6667" y1="14.3333"
/><line y2="19.4233" style="fill:none;" x1="379.3333" x2="379.3333" y1="14.3333"
/><line y2="19.4233" style="fill:none;" x1="549" x2="549" y1="14.3333"
/></g
><g transform="translate(40,359)" style="font-size:13px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-4.5" xml:space="preserve" y="13" style="stroke:none;"
>0</text
></g
><g transform="translate(209.6667,359)" style="font-size:13px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-4.5" xml:space="preserve" y="13" style="stroke:none;"
>1</text
></g
><g transform="translate(379.3333,359)" style="font-size:13px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-4.5" xml:space="preserve" y="13" style="stroke:none;"
>2</text
></g
><g transform="translate(549,359)" style="font-size:13px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-4.5" xml:space="preserve" y="13" style="stroke:none;"
>3</text
></g
><g transform="translate(294.5002,377.3333)" style="font-size:15px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-5.5" xml:space="preserve" y="14" style="stroke:none;"
>R</text
></g
><g style="fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; stroke-linejoin:round; color-interpolation:linearRGB; stroke:rgb(38,38,38); stroke-width:0.6667;"
><line y2="14.3333" style="fill:none;" x1="40" x2="40" y1="353.6667"
/><line y2="14.3333" style="fill:none;" x1="549" x2="549" y1="353.6667"
/><line y2="353.6667" style="fill:none;" x1="40" x2="45.09" y1="353.6667"
/><line y2="184" style="fill:none;" x1="40" x2="45.09" y1="184"
/><line y2="14.3333" style="fill:none;" x1="40" x2="45.09" y1="14.3333"
/><line y2="353.6667" style="fill:none;" x1="549" x2="543.91" y1="353.6667"
/><line y2="184" style="fill:none;" x1="549" x2="543.91" y1="184"
/><line y2="14.3333" style="fill:none;" x1="549" x2="543.91" y1="14.3333"
/></g
><g transform="translate(34.6667,353.6667)" style="font-size:13px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-9" xml:space="preserve" y="4.5" style="stroke:none;"
>0</text
></g
><g transform="translate(34.6667,184)" style="font-size:13px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-9" xml:space="preserve" y="4.5" style="stroke:none;"
>1</text
></g
><g transform="translate(34.6667,14.3333)" style="font-size:13px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-9" xml:space="preserve" y="4.5" style="stroke:none;"
>2</text
></g
><g transform="translate(11.9506,150.0665)" style="font-size:15px; fill:rgb(38,38,38); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; font-family:'SansSerif'; color-interpolation:linearRGB; stroke:rgb(38,38,38);"
><text x="-5.5" xml:space="preserve" y="-4" style="stroke:none;"
>Z</text
></g
><g style="stroke-linecap:butt; fill:rgb(23,115,69); text-rendering:geometricPrecision; color-rendering:optimizeQuality; image-rendering:optimizeQuality; stroke-linejoin:round; color-interpolation:linearRGB; stroke:rgb(23,115,69); stroke-width:0.6667;"
><line y2="353.6667" style="fill:none;" x1="209.6667" x2="549" y1="353.6667"
/><path d="M207.0891 330.0967 L236.9066 323.4906 L256.7424 318.9066 L274.8645 314.4418 L289.6187 310.5099 L304.2762 306.2299 L317.1844 302.0323 L328.34 297.9586 L339.3022 293.3956 L348.4761 288.9841 L352.9553 286.5662 L357.3412 283.9844 L361.6133 281.2195 L365.7498 278.2526 L369.7166 275.0645 L372.2498 272.8081 L375.8568 269.2187 L378.1151 266.6862 L380.2427 264.0426 L382.2278 261.2908 L384.0602 258.436 L385.7365 255.4853 L387.2483 252.4479 L389.2079 247.7517 L390.3108 244.543 L391.6732 239.64 L392.7082 234.657 L393.4428 229.6212 L393.9094 224.5531 L394.1367 219.4685 L394.1503 214.3788 L393.9789 209.292 L393.6413 204.2134 L392.9643 197.461 L392.06 190.7351 L390.9589 184.0385 L389.6864 177.3728 L387.8794 169.0846 L384.1129 154.2863 L379.2791 138.0254 L373.8718 121.9427 L367.36 104.4535 L360.329 87.1661 L352.8365 70.0739 L344.192 51.6396 L335.1046 33.4208 L325.0091 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M199.4346 307.2432 L222.5868 296.6773 L237.9484 289.4711 L251.6626 282.7587 L263.7259 276.5357 L275.6195 269.9976 L285.8436 263.9542 L295.8404 257.5442 L304.1778 251.7045 L312.2437 245.494 L319.9653 238.862 L323.6691 235.3724 L327.2542 231.7591 L332.9244 225.4513 L338.1552 218.7749 L342.8771 211.7296 L347.0271 204.3329 L349.2192 199.7398 L350.5511 196.6193 L353.4236 188.6394 L355.636 180.4523 L357.2071 172.1182 L357.8586 167.069 L358.3015 161.9993 L358.5492 156.9161 L358.6119 151.8261 L358.2319 141.6546 L357.2495 131.5238 L355.451 119.7863 L353.052 108.1556 L350.1439 96.6403 L346.2891 83.6269 L341.949 70.7679 L336.5706 56.4768 L330.7442 42.3623 L324.5293 28.4157 L317.7957 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M186.9356 285.8 L215.7339 264.8197 L226.5468 256.6158 L235.8768 249.2667 L245.0422 241.7155 L254.004 233.9212 L261.4812 227.0144 L268.7327 219.8709 L275.7162 212.464 L281.2932 206.0726 L287.6489 198.1217 L292.6235 191.2507 L297.2656 184.1512 L301.5378 176.8231 L305.4045 169.2729 L308.8334 161.5158 L311.7975 153.5686 L314.278 145.4568 L316.2665 137.211 L317.7647 128.8617 L318.781 120.4412 L319.3358 111.9765 L319.4495 103.4949 L319.1543 95.0183 L318.4756 86.5621 L317.2014 76.4636 L315.4691 66.4329 L313.3279 56.4802 L310.8202 46.6158 L307.4829 35.2176 L303.7519 23.9433 L300.2244 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M169.9721 266.419 L190.9684 244.2415 L205.8005 227.9174 L212.4746 220.2301 L219.0034 212.4203 L225.3625 204.4703 L230.5068 197.7262 L235.495 190.8639 L240.3034 183.8761 L244.9132 176.7552 L249.3025 169.4952 L253.4474 162.0943 L257.326 154.5493 L260.9145 146.8634 L263.5613 140.6145 L266.5746 132.6843 L269.24 124.6319 L271.5458 116.4693 L273.1237 109.8676 L274.4573 103.2149 L275.7841 94.8368 L276.573 88.0959 L277.2211 79.638 L277.4739 72.8565 L277.4723 64.3731 L277.1278 55.8983 L276.4576 47.4421 L275.4804 39.0147 L274.213 30.6264 L272.6775 22.2839 L270.954 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M149.0597 249.6888 L164.1276 227.1081 L175.1756 210.0067 L184.9403 194.1023 L193.3939 179.3918 L201.3296 164.3967 L207.9327 150.63 L211.3464 142.8643 L213.9338 136.59 L218.6929 123.8803 L221.3652 115.8279 L223.3231 109.3314 L225.1165 102.7857 L226.7402 96.1958 L228.1875 89.5652 L229.4532 82.899 L230.5374 76.1989 L231.4366 69.4716 L232.1509 62.724 L232.6769 55.9577 L233.0179 49.1795 L233.1757 42.3945 L233.1536 35.6078 L232.9534 28.8246 L232.5785 22.0481 L231.9324 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M124.8333 236.1182 L135.4541 212.9903 L143.0664 195.9501 L149.7492 180.3556 L155.4996 166.2088 L160.9376 151.9415 L165.4605 139.1435 L169.6476 126.2336 L173.4579 113.2066 L176.8524 100.0642 L179.795 86.8149 L182.2534 73.4673 L183.9868 61.7178 L185.4719 48.2276 L186.3277 36.3815 L186.7657 24.5133 L186.7843 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M98.0294 226.1191 L108.7986 188.6114 L116.7251 159.1184 L120.01 145.9489 L123.1093 132.7335 L125.9966 119.4724 L128.3286 107.8265 L130.7501 94.4703 L132.6383 82.7463 L134.2965 70.985 L135.712 59.1932 L136.8737 47.3742 L137.773 35.5315 L138.4024 23.6718 L138.6988 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M69.4623 219.9955 L74.6093 183.0261 L78.3616 154.4271 L81.5763 127.4721 L84.0514 103.8478 L86.1431 80.1877 L87.6919 58.1854 L88.8218 36.1576 L89.4974 14.2929" style="fill:none; fill-rule:evenodd;"
/><line y2="14.3333" style="fill:none;" x1="40" x2="40" y1="217.9333"
/><path d="M422.3676 353.6667 L422.2759 343.3175 L422.0079 333.1412 L421.5634 322.9711 L420.9441 312.8101 L420.1483 302.6613 L419.1795 292.5275 L418.0394 282.4117 L416.492 270.6366 L413.3057 250.5283 L411.4648 240.5165 L409.1098 228.8755 L406.9194 218.9342 L404.164 207.3816 L401.636 197.5207 L398.4955 186.0669 L395.6434 176.2937 L392.1347 164.9481 L385.1122 144.0401 L377.4653 123.3526 L373.0998 112.3074 L368.568 101.3299 L359.0327 79.5752 L348.9019 58.0904 L337.4409 35.3686 L326.1346 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M549 277.3167 L537.1997 275.9758 L527.1079 274.6404 L517.0467 273.0931 L507.0279 271.284 L498.7295 269.5305 L490.4921 267.5038 L482.3431 265.1454 L475.9144 262.9734 L469.5926 260.5039 L463.4167 257.694 L457.4292 254.5024 L451.6809 250.8972 L446.2261 246.8618 L442.356 243.5564 L438.6912 240.0251 L434.134 234.9991 L428.9489 228.2874 L424.278 221.2084 L419.2254 212.3718 L414.6325 203.288 L410.3586 194.0487 L405.6351 183.1517 L388.2256 140.7791 L380.3361 122.0106 L373.5545 106.4589 L366.554 91.004 L357.1019 71.075 L348.0213 52.8528 L337.804 33.3055 L327.3906 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M549 200.9667 L538.9965 199.0849 L530.693 197.3465 L520.781 195.0276 L512.5743 192.8759 L504.4319 190.4994 L496.366 187.8723 L488.3951 184.9676 L482.1021 182.4272 L474.3619 178.9575 L468.2862 175.9341 L462.3309 172.6815 L456.5079 169.1949 L450.8326 165.4741 L445.315 161.5226 L439.9654 157.3488 L434.7872 152.9629 L429.7786 148.3819 L424.9414 143.6244 L420.2654 138.7058 L415.7404 133.648 L411.3579 128.4664 L406.0592 121.8409 L400.9336 115.0814 L395.959 108.2099 L386.3592 94.2209 L376.1758 78.581 L366.2198 62.7952 L336.0411 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M549 141.5833 L532.4439 137.8761 L517.6761 133.9975 L503.078 129.5217 L490.2903 124.973 L477.7332 119.8253 L471.5573 117.0122 L465.4595 114.0346 L459.4449 110.8872 L453.5235 107.572 L447.7005 104.087 L441.9794 100.4375 L432.2269 93.661 L426.8061 89.5788 L421.4955 85.3541 L411.1984 76.5111 L406.2068 71.9131 L400.1039 66.0223 L389.4675 55.0669 L378.1033 42.4692 L367.1173 29.5406 L354.7701 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M549 82.2 L537.4152 79.582 L525.8931 76.7079 L514.4423 73.5521 L504.7 70.605 L493.4291 66.8604 L483.865 63.3721 L474.4043 59.614 L465.0608 55.5759 L455.8462 51.2494 L446.7724 46.6328 L439.3292 42.5642 L430.5455 37.4199 L421.9298 32.0007 L413.4839 26.3152 L405.2126 20.3837 L397.2033 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M549 31.3 L532.4507 27.5588 L516.0151 23.3511 L499.7203 18.6276 L486.4319 14.2929" style="fill:none; fill-rule:evenodd;"
/><path d="M209.6667 353.6667 L209.4548 346.8844 L208.8205 340.1285 L207.7693 333.4247 L206.3093 326.7982 L204.4514 320.2719 L202.2091 313.8673 L199.598 307.604 L196.6351 301.4994 L193.3385 295.5682 L189.7266 289.8233 L185.8188 284.2755 L180.5466 277.6312 L176.0414 272.5563 L171.3004 267.7011 L166.3409 263.0694 L159.8591 257.5982 L154.467 253.4778 L147.4927 248.6498 L141.7427 245.0456 L134.3632 240.8628 L128.3207 237.7737 L120.6127 234.2324 L112.7517 231.0448 L104.7572 228.2087 L98.2776 226.1915 L90.0876 223.9826 L81.812 222.1195 L73.4664 220.6 L65.0659 219.4227 L56.6244 218.5864 L48.1562 218.0903 L39.9596 217.9388" style="fill:none; stroke-width:1.3333; fill-rule:evenodd; stroke:rgb(179,27,27);"
/><path d="M213.0227 353.6667 L212.8174 346.8842 L212.2032 340.1263 L211.1852 333.4176 L209.7685 326.7815 L207.9649 320.2398 L205.7862 313.8133 L203.2465 307.5207 L199.5878 299.8688 L196.2941 293.9359 L192.6929 288.1843 L188.8022 282.6245 L183.5589 275.9571 L179.0817 270.8576 L173.1598 264.7849 L168.1818 260.1729 L161.6848 254.7196 L156.2856 250.6086 L149.3074 245.7862 L142.0986 241.3154 L134.6833 237.1963 L128.6176 234.1533 L120.886 230.6638 L113.0069 227.5214 L104.9985 224.7244 L98.5106 222.7341 L90.313 220.5533 L82.0325 218.7123 L73.6839 217.2094 L65.2817 216.0427 L56.8398 215.2117 L48.3716 214.7151 L39.9596 214.5539" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M216.567 353.6667 L216.3668 346.8839 L215.7713 340.1243 L214.7838 333.4108 L213.4095 326.7658 L211.6586 320.2099 L209.5421 313.7628 L207.0716 307.4427 L203.5084 299.7456 L200.2966 293.7679 L195.8565 286.5411 L191.9843 280.9682 L186.7715 274.2771 L182.3234 269.1523 L176.442 263.0401 L171.4991 258.3904 L165.0481 252.8828 L159.6864 248.7229 L152.7555 243.8324 L145.5938 239.2871 L138.2243 235.0865 L130.669 231.2299 L122.9483 227.7161 L115.0812 224.5435 L107.0857 221.7103 L98.9785 219.2143 L90.7756 217.0538 L82.4918 215.227 L74.1419 213.7321 L65.7393 212.568 L57.2977 211.7334 L48.83 211.2276 L39.9596 211.0762" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M220.3149 353.6667 L220.1215 346.8836 L219.5447 340.1225 L218.586 333.4047 L216.8605 325.1004 L215.0705 318.5552 L212.926 312.1172 L210.437 305.8037 L206.867 298.11 L203.6591 292.1302 L199.2344 284.8938 L195.3817 279.3074 L190.2006 272.5916 L185.7827 267.4407 L179.9436 261.2881 L173.7796 255.4609 L167.3189 249.9645 L161.9544 245.8084 L155.0247 240.9162 L147.8685 236.3618 L140.5082 232.1455 L132.9644 228.2664 L125.257 224.7236 L117.4043 221.5155 L109.4235 218.6407 L101.3311 216.097 L93.1425 213.8829 L84.8721 211.9965 L74.8594 210.1633 L66.4578 208.9929 L58.0174 208.1461 L49.5507 207.622 L39.9596 207.4305" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M224.2868 353.6667 L224.0985 346.8835 L223.5386 340.1208 L222.6088 333.399 L220.9342 325.0843 L219.1951 318.5253 L216.5348 310.4712 L214.0322 304.1635 L210.4556 296.4724 L207.2535 290.4897 L202.8456 283.243 L198.015 276.2707 L192.7906 269.5883 L188.3465 264.4598 L182.4845 258.3291 L176.3068 252.5163 L169.84 247.0273 L163.1088 241.8653 L156.1372 237.0332 L148.9475 232.5316 L141.5611 228.3611 L133.9975 224.5206 L126.2755 221.0097 L118.4126 217.8266 L110.4254 214.9699 L102.3294 212.4378 L94.1393 210.2288 L85.8692 208.3412 L75.8584 206.4981 L67.4587 205.3127 L57.3292 204.3089 L48.8604 203.8208 L39.9596 203.6733" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M228.5048 353.6667 L228.3232 346.8832 L227.5869 338.4334 L226.596 331.7205 L224.8603 323.4182 L223.0839 316.8688 L220.393 308.825 L217.8785 302.5225 L214.2986 294.8327 L211.1021 288.8467 L206.7124 281.5887 L201.9095 274.5974 L196.7204 267.8876 L192.3092 262.7306 L186.4929 256.5564 L180.3644 250.6919 L173.9491 245.1424 L167.271 239.9121 L160.3529 235.0035 L153.2165 230.4183 L145.882 226.1566 L138.369 222.2183 L130.6955 218.6027 L122.8784 215.3086 L113.3315 211.7778 L105.2543 209.1858 L95.4379 206.493 L87.1699 204.5957 L77.1628 202.7322 L68.7666 201.5228 L58.6409 200.4818 L50.1743 199.9556 L39.9975 199.7328" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M232.9992 353.6667 L232.8228 346.8831 L232.1085 338.4313 L231.1431 331.7142 L229.4566 323.4019 L227.7294 316.8395 L225.1114 308.7717 L222.0014 300.8803 L218.4198 293.1915 L215.2317 287.2014 L210.8594 279.9321 L206.0857 272.9211 L200.9329 266.1833 L195.4274 259.7306 L189.5939 253.5723 L183.4572 247.7163 L177.0411 242.1678 L170.3681 236.9309 L163.4602 232.008 L156.3377 227.4009 L147.5352 222.2897 L140.0083 218.378 L132.3256 214.7816 L124.5035 211.4994 L114.9545 207.9739 L106.8785 205.3783 L97.0657 202.6725 L88.8021 200.7565 L78.8007 198.8621 L70.4094 197.6193 L60.2886 196.5299 L50.1303 195.8773 L39.9596 195.6615" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M237.7991 353.6667 L237.6277 346.8829 L236.9321 338.4294 L235.7088 330.0362 L233.9646 321.7356 L232.2035 315.182 L229.5567 307.1234 L226.4331 299.2378 L222.8515 291.5492 L218.8321 284.0793 L214.4004 276.8469 L209.5793 269.8681 L204.3921 263.1566 L198.8633 256.7235 L193.0164 250.5782 L186.8748 244.7273 L179.1474 238.1023 L172.4348 232.9161 L165.4962 228.0365 L158.3506 223.465 L149.5292 218.3867 L141.9922 214.494 L132.7498 210.2291 L124.9005 207.0124 L115.3266 203.5553 L107.235 201.0084 L97.4088 198.3514 L87.4754 196.1276 L77.4553 194.3347 L69.053 193.1686 L58.9236 192.1616 L48.7609 191.5816 L39.9596 191.4486" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M242.9434 353.6667 L242.7771 346.8827 L242.1018 338.4277 L240.9108 330.0295 L239.2141 321.7191 L237.0203 313.5254 L234.3481 305.4754 L231.2109 297.5947 L227.6276 289.9061 L223.6217 282.4301 L219.2121 275.1843 L214.4207 268.1844 L208.2012 260.127 L202.6526 253.711 L196.7957 247.5751 L190.6523 241.7262 L182.9314 235.0932 L176.231 229.8914 L167.8995 224.0437 L160.7357 219.5009 L151.9003 214.4467 L144.3574 210.5656 L135.1133 206.3042 L127.2662 203.0821 L117.698 199.6087 L109.6132 197.0402 L99.7966 194.3475 L89.8739 192.0775 L79.864 190.2281 L69.7857 188.798 L59.6569 187.7854 L49.495 187.1894 L39.9596 187.0207" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M248.4796 353.6667 L248.2268 345.1884 L247.4684 336.7403 L246.2095 328.3522 L244.4568 320.0528 L242.2257 311.8696 L239.5263 303.8281 L236.3773 295.9523 L232.7956 288.2635 L228.8 280.7812 L224.4107 273.5224 L219.6516 266.5018 L213.4774 258.4087 L207.9753 251.9532 L200.9735 244.5654 L194.8307 238.7156 L187.12 232.0708 L180.434 226.8503 L172.1261 220.9692 L163.5357 215.5088 L154.6913 210.4699 L147.1464 206.5926 L137.9048 202.3257 L128.4808 198.478 L118.897 195.0477 L109.1745 192.0327 L99.3333 189.4312 L89.3925 187.2408 L79.3701 185.4602 L69.2838 184.0874 L59.1504 183.1211 L48.9866 182.5612 L39.9596 182.4228" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M254.4655 353.6667 L254.2177 345.1881 L253.478 336.7383 L252.2496 328.3454 L250.5428 320.037 L248.3642 311.8393 L245.7293 303.7764 L242.655 295.8714 L238.4048 286.6227 L234.4193 279.1348 L229.1342 270.4365 L224.3326 263.4435 L218.1263 255.3759 L212.6087 248.934 L205.5994 241.5526 L199.4599 235.6993 L191.7619 229.0396 L185.093 223.7973 L176.8114 217.879 L168.2527 212.3691 L159.4436 207.2686 L150.4097 202.5778 L141.1749 198.2958 L131.762 194.4213 L122.192 190.9526 L112.485 187.8879 L102.6601 185.2255 L92.7353 182.9633 L81.0534 180.8272 L70.971 179.4258 L60.8413 178.4214 L50.6802 177.8106 L39.9596 177.6175" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M260.9705 353.6667 L260.7295 345.1879 L260.0068 336.7365 L258.8072 328.3395 L257.8622 323.3384 L256.7492 318.3718 L254.5316 310.1847 L251.2842 300.5383 L248.108 292.6727 L243.7595 283.4705 L239.7061 276.0189 L234.3583 267.3593 L229.5177 260.3928 L223.2807 252.3487 L217.7479 245.9188 L210.7356 238.5419 L203.3435 231.5435 L195.605 224.9307 L187.5489 218.7092 L179.2029 212.8819 L170.5936 207.4508 L161.7464 202.417 L152.6845 197.7803 L143.4305 193.5399 L134.0055 189.6945 L124.4294 186.2428 L114.7209 183.1822 L104.8978 180.5134 L94.9774 178.2313 L83.3022 176.0596 L73.2258 174.614 L61.4109 173.4145 L51.2501 172.8003 L39.9596 172.5777" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M268.0897 353.6667 L267.8539 345.1877 L266.9478 335.0498 L265.6821 326.6627 L263.5579 316.7085 L261.2979 308.5328 L258.0166 298.8979 L254.8251 291.039 L250.4715 281.8391 L246.425 274.3833 L241.0974 265.7103 L235.2846 257.3547 L229.0189 249.3337 L223.4724 242.9152 L216.4567 235.5413 L209.0732 228.5338 L201.3532 221.8995 L193.3237 215.6432 L185.0112 209.7681 L176.4407 204.2762 L166.1472 198.3543 L157.0971 193.6946 L147.8596 189.4183 L138.4545 185.5246 L127.2949 181.4635 L117.5896 178.3942 L106.1267 175.2893 L96.2001 173.0361 L84.5216 170.8797 L74.4452 169.4358 L62.6317 168.221 L50.7771 167.5101 L39.9596 167.3231" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M275.9453 353.6667 L275.7128 345.1876 L274.8238 335.0483 L273.5801 326.6576 L271.4966 316.6951 L269.2774 308.508 L266.0554 298.8528 L262.2498 289.4132 L257.8842 280.2183 L252.9893 271.2937 L247.5973 262.6609 L241.7371 254.3382 L235.439 246.3408 L228.7355 238.6812 L221.6553 231.3689 L214.2256 224.4115 L206.4724 217.8152 L198.4235 211.5837 L188.6913 204.7787 L180.0829 199.3463 L169.7592 193.4769 L160.6937 188.8472 L149.8916 183.9135 L140.46 180.0841 L129.2794 176.08 L119.563 173.0463 L108.0935 169.9652 L96.5027 167.3795 L84.813 165.2858 L74.7311 163.8809 L62.9145 162.6949 L51.0592 161.9976 L39.9596 161.8009" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M284.7035 353.6667 L284.4744 345.1875 L283.5989 335.0469 L282.0736 324.9837 L279.9138 315.0371 L277.6436 306.8643 L274.3724 297.2259 L270.5295 287.8004 L266.1436 278.6151 L261.2437 269.6934 L255.8601 261.0551 L250.0219 252.7169 L243.7595 244.6923 L237.1018 236.9927 L228.8712 228.432 L221.4517 221.4643 L212.4034 213.7738 L204.3385 207.5623 L194.6026 200.7624 L184.5462 194.446 L174.2012 188.6143 L165.1271 184.0012 L154.3243 179.0678 L143.3138 174.6191 L132.1208 170.6489 L120.7695 167.1589 L109.2822 164.1473 L97.6806 161.6091 L85.9854 159.5459 L74.2167 157.9545 L62.3938 156.833 L50.5358 156.1815 L39.9596 156.0198" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M294.6086 353.6667 L294.2811 343.4937 L293.3038 333.3625 L291.6852 323.3138 L289.4406 313.3859 L286.5901 303.6145 L283.1612 294.0312 L279.1791 284.6641 L274.6711 275.5374 L269.671 266.6718 L264.206 258.0843 L258.3067 249.7893 L250.9126 240.4966 L244.1701 232.872 L235.8649 224.3841 L228.3996 217.464 L219.319 209.8112 L209.8703 202.6158 L200.0897 195.8811 L190.0057 189.6087 L179.6477 183.7998 L169.043 178.4536 L158.2175 173.5723 L147.1951 169.1508 L135.9989 165.1908 L124.6508 161.6905 L113.1713 158.6467 L101.5807 156.0593 L88.2223 153.6602 L76.4566 152.045 L64.6378 150.8828 L52.7831 150.1719 L39.9596 149.9265" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M306.0288 353.6667 L305.7014 343.4937 L304.719 333.3628 L303.097 323.3147 L300.8506 313.3873 L298.0036 303.6153 L294.5815 294.0294 L290.6129 284.6558 L288.4344 280.0558 L285.3363 274.018 L280.2938 265.176 L277.6029 260.8558 L273.8465 255.2033 L267.8708 246.9628 L260.4157 237.7204 L252.477 228.8887 L244.0937 220.4771 L235.3033 212.4918 L226.1396 204.938 L216.6349 197.8195 L206.8166 191.1386 L196.7133 184.8969 L184.8511 178.3026 L174.2225 173.0039 L163.3855 168.1463 L152.3619 163.7282 L139.5616 159.2168 L128.2065 155.7386 L115.0775 152.2995 L103.4771 149.7545 L90.1143 147.3792 L78.3484 145.7656 L64.8399 144.4507 L52.9839 143.7636 L39.9596 143.516" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M319.5869 353.6667 L319.251 343.494 L318.2499 333.3652 L316.5957 323.3223 L314.3103 313.4037 L311.4209 303.6438 L309.7598 298.8328 L307.3302 292.4967 L303.2429 283.1744 L301.0101 278.6005 L297.8475 272.5965 L295.3398 268.1671 L291.8244 262.3619 L285.2277 252.488 L278.1017 242.9885 L270.4888 233.8734 L262.4313 225.1501 L253.9632 216.8246 L245.1168 208.9015 L239.9047 204.5561 L234.5822 200.3438 L225.0266 193.2943 L213.7489 185.7415 L203.5999 179.5751 L191.7073 173.0361 L181.0682 167.7578 L168.6703 162.2368 L157.6341 157.8493 L144.8313 153.3446 L133.4818 149.8478 L120.3655 146.3594 L107.1172 143.4106 L93.7602 141.0014 L80.3172 139.1317 L66.8102 137.8015 L53.261 137.0074 L39.9596 136.7563" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M336.4908 353.6667 L336.4009 348.5777 L336.1345 343.4949 L335.6917 338.4245 L335.0758 333.3723 L334.2868 328.3439 L333.3299 323.3448 L332.2101 318.3799 L330.4693 311.8206 L327.3542 302.1308 L325.5812 297.3599 L323.004 291.0821 L320.9188 286.4388 L317.9462 280.3384 L315.5777 275.8329 L312.2455 269.9212 L305.961 259.8451 L299.1472 250.1196 L291.8481 240.7516 L287.4758 235.5607 L282.9677 230.4887 L274.7644 221.9008 L264.939 212.5381 L254.6724 203.6615 L244.0021 195.2749 L232.9619 187.3818 L221.5807 179.9857 L209.8923 173.0887 L197.9198 166.6957 L185.6918 160.8049 L173.2325 155.423 L160.5655 150.5485 L147.7144 146.183 L134.7011 142.3265 L121.5476 138.9807 L108.2745 136.1455 L94.9028 133.8194 L81.4523 132.004 L67.9426 130.6992 L54.3934 129.9035 L39.9596 129.634" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M359.8556 353.6667 L359.7521 348.5781 L359.4399 343.498 L358.9207 338.4348 L358.2031 333.3961 L357.2903 328.389 L356.1891 323.4199 L354.9081 318.4939 L352.9349 312.0011 L351.2671 307.1921 L348.8103 300.8661 L346.8031 296.1887 L343.9239 290.0437 L341.6215 285.5048 L338.3707 279.5469 L332.2356 269.3798 L328.4944 263.7179 L324.5955 258.1633 L320.5489 252.7155 L316.3615 247.3739 L307.5999 237.0088 L298.3616 227.0663 L288.6872 217.5473 L278.6124 208.4537 L268.166 199.789 L262.8114 195.6188 L256.0026 190.5593 L244.8521 182.8208 L233.4047 175.5285 L221.6842 168.6842 L208.1967 161.5276 L195.9603 155.6555 L181.9418 149.6035 L169.2777 144.7222 L154.8263 139.7934 L141.8195 135.9148 L127.0295 132.121 L113.7628 129.2554 L98.7257 126.6035 L85.2794 124.7575 L70.0848 123.2525 L54.842 122.3567 L39.9596 122.0772" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M493.0134 353.6667 L493.1355 345.1845 L493.4969 336.7092 L494.0925 328.247 L495.0918 318.1166 L496.3745 308.018 L497.9049 297.9539 L499.6457 287.924 L501.8988 276.2632 L505.8029 258.013 L510.4042 238.18 L528.6315 164.037 L536.5447 131.0403 L543.0176 102.9333 L549.0405 75.5666" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M524.4594 353.6667 L524.5323 345.1837 L524.8106 335.0078 L525.8405 316.3738 L527.4913 297.7844 L529.8955 277.5674 L533.07 255.741 L536.9774 232.3114 L542.1658 203.9389 L549.0405 168.3724" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M40 105.5716 L48.4828 105.653 L58.6577 105.9669 L67.1295 106.408 L77.2819 107.1529 L85.7274 107.9537 L95.8392 109.1278 L105.9213 110.5343 L115.9684 112.1716 L124.3104 113.7139 L134.2797 115.7719 L144.1996 118.0591 L154.0649 120.5684 L162.2409 122.8318 L171.9942 125.7466 L181.6801 128.8787 L191.2946 132.2245 L199.2493 135.1716 L208.7233 138.8958 L218.1161 142.8202 L227.4257 146.938 L236.6505 151.2458 L245.787 155.7318 L254.8387 160.3926 L263.8039 165.2145 L280.0206 174.4495 L297.4217 185.0195 L313.1565 195.0565 L341.557 213.6253 L353.0333 220.8726 L363.2642 226.9048 L372.2633 231.6592 L378.429 234.494 L383.1593 236.373 L387.9897 237.9772 L392.9203 239.2362 L397.939 240.0682 L403.0171 240.3894 L408.0969 240.1274 L411.4496 239.6081 L414.7462 238.8117 L419.5443 237.1213 L422.6221 235.6927 L427.0334 233.1573 L429.8346 231.2432 L433.8319 228.0948 L437.6003 224.6744 L441.1599 221.037 L444.5328 217.2253 L448.7745 211.9283 L451.7861 207.8258 L455.607 202.2175 L459.2328 196.4802 L462.6855 190.6379 L465.9872 184.7087 L469.9269 177.1964 L473.6816 169.5885 L477.2734 161.9043 L480.7193 154.1522 L484.6811 144.7748 L492.1108 125.8196 L498.9789 106.6541 L505.8843 85.7053 L512.7847 62.9785 L519.6443 38.4701 L525.9012 14.2929" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M40 96.5266 L55.2674 96.7693 L72.2122 97.6108 L87.4288 98.8799 L104.2794 100.8532 L119.378 103.1318 L136.062 106.2112 L150.9805 109.4654 L167.4336 113.6053 L183.7438 118.2762 L199.9003 123.4544 L215.8968 129.1095 L233.3046 135.835 L248.9682 142.357 L264.4911 149.2048 L279.9036 156.2985 L312.1385 171.4769 L324.4971 177.0878 L336.9981 182.3746 L348.1181 186.5435 L354.5722 188.6399 L361.1111 190.4565 L367.7366 191.9211 L372.7604 192.7377 L379.5149 193.3751 L384.6032 193.462 L389.683 193.172 L394.7238 192.4769 L399.6883 191.3613 L402.9374 190.3837 L406.1254 189.2237 L410.7759 187.1582 L413.7791 185.5789 L418.1276 182.9345 L420.9203 181.0071 L424.9499 177.8988 L428.7929 174.5614 L432.4577 171.0307 L435.9579 167.3353 L439.3037 163.4992 L442.507 159.5443 L446.5757 154.1132 L450.4338 148.5312 L454.1071 142.8236 L457.6107 137.0125 L460.9617 131.1115 L464.1752 125.1341 L468.0164 117.5704 L474.4977 103.7443 L481.1435 88.1349 L487.8878 70.7322 L494.1298 53.1446 L500.4499 33.7924 L506.3322 14.2994" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M40 86.8777 L53.5718 87.0525 L67.1346 87.575 L80.6796 88.4471 L94.1982 89.6619 L107.6816 91.2178 L121.1224 93.1079 L134.5128 95.3271 L149.5091 98.203 L164.4257 101.4674 L179.2568 105.0999 L193.9988 109.0786 L210.2741 113.87 L224.8332 118.4764 L239.3176 123.3136 L285.7198 139.6746 L300.1685 144.6136 L314.7328 149.1997 L326.1836 152.3504 L332.787 153.9147 L339.4396 155.2585 L346.1397 156.3325 L352.884 157.0824 L359.6605 157.4506 L364.7488 157.437 L371.5185 156.9874 L376.561 156.2985 L381.5492 155.289 L384.8322 154.4339 L388.0746 153.4328 L392.8456 151.6598 L395.9539 150.3008 L400.4992 148.012 L403.4447 146.3289 L407.7305 143.5837 L410.4977 141.619 L414.5103 138.4886 L418.3618 135.1615 L422.0571 131.6612 L425.6014 128.0083 L429.0049 124.223 L435.4167 116.32 L438.4418 112.2259 L442.3068 106.6473 L448.649 96.6081 L455.3287 84.7925 L461.491 72.7004 L467.9027 58.842 L473.8411 44.7749 L479.966 28.9535 L485.1912 14.2929" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M40 76.5586 L51.8759 76.6774 L63.7469 77.0353 L75.6085 77.6309 L87.4559 78.4605 L99.2849 79.521 L111.0913 80.8104 L122.8713 82.3205 L134.6216 84.0477 L148.0107 86.2754 L161.3543 88.761 L174.6509 91.4876 L189.5535 94.8164 L202.7531 97.979 L217.5562 101.7252 L261.8171 113.5374 L276.6019 117.3549 L291.4596 120.8772 L303.0902 123.2763 L311.448 124.7304 L318.1668 125.6924 L324.911 126.4406 L331.6791 126.9326 L338.4623 127.1294 L343.5523 127.0565 L350.3237 126.6289 L355.3798 126.0385 L360.3985 125.1986 L363.7172 124.4945 L368.6443 123.2135 L371.885 122.2108 L378.2424 119.8389 L381.349 118.4747 L385.9079 116.2131 L388.8754 114.5673 L393.2121 111.9035 L400.1209 106.9832 L406.6259 101.542 L410.3382 98.0604 L413.9131 94.438 L420.6709 86.8268 L426.9486 78.8151 L432.7953 70.4828 L439.1374 60.4419 L445.0232 50.1279 L451.2686 38.0765 L457.0661 25.8045 L462.068 14.2929" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M40 65.4963 L51.8761 65.5998 L63.7484 65.9103 L75.6137 66.4278 L87.4685 67.1489 L99.3094 68.0668 L111.1336 69.1798 L122.9388 70.4811 L136.4046 72.1846 L158.2232 75.4116 L179.964 79.1307 L201.6379 83.2197 L243.2437 91.474 L259.9236 94.5755 L274.9934 97.0407 L288.4497 98.8104 L300.2772 99.8911 L312.1419 100.3849 L318.9269 100.3408 L324.0135 100.1253 L329.0883 99.7384 L334.146 99.1667 L342.5106 97.7652 L350.7513 95.7598 L358.8105 93.1163 L365.0864 90.5374 L371.1791 87.553 L378.5054 83.2791 L384.1145 79.4599 L390.796 74.2358 L397.1127 68.5741 L403.0714 62.539 L408.6907 56.185 L415.0193 48.2124 L419.9736 41.3273 L425.5709 32.8236 L430.8238 24.1061 L436.2453 14.2929" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M40 53.601 L60.3578 53.8589 L80.703 54.6224 L101.0238 55.8779 L123.0001 57.7527 L141.5598 59.7158 L161.7691 62.1861 L218.9033 70.1469 L235.7241 72.3695 L250.894 74.1103 L262.7214 75.1894 L276.2693 76.0055 L288.1426 76.2311 L298.3175 75.9614 L308.4669 75.1707 L316.874 74.0492 L323.5452 72.8107 L330.1487 71.2463 L336.6605 69.3359 L344.6348 66.4448 L350.8514 63.7267 L356.9 60.6506 L362.762 57.2319 L368.4204 53.4873 L373.8684 49.4408 L379.0992 45.1194 L385.3345 39.3676 L391.2388 33.2783 L396.8277 26.8971 L402.1179 20.2649 L406.4881 14.2929" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M40 40.7759 L56.9659 40.9184 L75.6227 41.3986 L92.5739 42.1196 L111.2057 43.2004 L143.3475 45.664 L207.5523 51.5412 L221.0852 52.5898 L232.9381 53.3261 L246.4996 53.8741 L258.3763 54.0065 L268.5529 53.7893 L278.7142 53.1938 L285.4703 52.5541 L292.2027 51.6905 L298.8978 50.5843 L305.5436 49.2134 L312.125 47.5592 L318.6232 45.6029 L325.0197 43.3362 L329.7364 41.4257 L335.9055 38.5957 L340.4305 36.2661 L344.8605 33.7602 L350.6088 30.1548 L354.7961 27.2602 L360.2068 23.1645 L365.4156 18.8176 L370.3644 14.2929" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M40 26.9005 L68.8413 27.1975 L97.6716 28.0526 L124.7907 29.2691 L179.0081 32.1398 L201.0471 33.0136 L212.9209 33.2749 L223.1009 33.3258 L233.2792 33.1748 L241.7557 32.8592 L253.6052 32.0686 L265.4124 30.7859 L275.4702 29.2233 L285.4398 27.1652 L295.2771 24.5541 L304.9345 21.3406 L309.6784 19.4963 L314.3578 17.4925 L320.9536 14.2929" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M422.3676 353.6667 L414.1812 340.1275 L405.048 325.83 L395.5331 311.7826 L386.6358 299.3728 L376.3709 285.8648 L366.7831 273.9805 L356.861 262.3745 L346.5995 251.067 L335.9971 240.0786 L325.0536 229.4296 L313.7708 219.1415 L303.4584 210.3161 L291.5461 200.7659 L280.6823 192.6286 L268.1626 183.888 L256.778 176.499 L243.6916 168.6316 L231.8234 162.0451 L218.2213 155.1075 L205.9208 149.371 L191.8634 143.4089 L179.1877 138.5565 L164.7428 133.6073 L151.7545 129.6676 L138.6418 126.1657 L125.4192 123.1015 L112.1017 120.4819 L97.0248 118.0675 L83.5555 116.3963 L68.3455 115.0526 L54.7917 114.3366 L39.9596 114.0761" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M422.3676 353.6667 L431.8842 336.9903 L440.7119 320.5477 L449.8909 302.3742 L458.6169 283.9795 L466.9119 265.3871 L475.441 245.0464 L483.5171 224.522 L491.1674 203.8351 L498.4173 183.0041 L505.8029 160.4282 L512.7778 137.7234 L519.8275 113.2694 L526.4666 88.6999 L532.7222 64.0321 L538.6249 39.276 L544.217 14.2929" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><line y2="353.6667" style="fill:none;" x1="209.6667" x2="141.8" y1="353.6667"
/><path d="M207.0891 330.0967 L187.2194 334.5385 L172.3615 338.0613 L160.8772 341.0863 L152.7706 343.5833 L146.4441 346.0327 L143.422 347.5726 L141.9902 348.4821 L140.6522 349.5237 L139.4576 350.7266 L138.4559 352.094 L137.6476 353.5847 L136.9133 353.6678" style="fill:none; fill-rule:evenodd;"
/><path d="M199.4346 307.2432 L180.9423 315.7614 L167.2028 322.4237 L156.7027 327.9717 L152.2947 330.5165 L147.976 333.2098 L143.7883 336.1021 L141.1013 338.1739 L138.5302 340.3876 L136.1102 342.7654 L133.8774 345.3194 L131.853 348.0416 L128.3526 353.6671" style="fill:none; fill-rule:evenodd;"
/><path d="M186.9356 285.8 L169.1226 298.8072 L156.9975 308.0881 L146.5415 316.7409 L139.0562 323.6382 L135.4887 327.2686 L132.0778 331.046 L128.8568 334.9864 L126.8298 337.7076 L124.9063 340.5029 L122.2162 344.8232 L117.4515 353.6672" style="fill:none; fill-rule:evenodd;"
/><path d="M169.9721 266.419 L154.8258 282.4525 L143.4274 295.0193 L134.6416 305.3646 L127.3503 314.7383 L121.5225 323.0836 L116.1968 331.7574 L113.7468 336.2187 L110.7045 342.2847 L108.5827 346.9112 L105.9432 353.1631 L105.3123 353.6674" style="fill:none; fill-rule:evenodd;"
/><path d="M149.0597 249.6888 L135.8942 269.4597 L126.7244 283.7346 L119.6704 295.3305 L112.9967 307.149 L107.5762 317.7155 L103.3081 326.9569 L100.6743 333.2115 L98.2123 339.5355 L93.2587 353.6666 L92.7512 353.6678" style="fill:none; fill-rule:evenodd;"
/><path d="M124.8333 236.1182 L114.2236 259.2511 L107.3388 274.7579 L101.3988 288.825 L96.4157 301.45 L91.7938 314.2117 L88.0981 325.4983 L84.3025 338.5293 L80.5627 353.3334 L80.1784 353.6675" style="fill:none; fill-rule:evenodd;"
/><path d="M98.0294 226.1191 L86.3511 266.8961 L82.3736 281.6388 L78.6182 296.4396 L75.518 309.6539 L73.0199 321.2647 L70.126 336.2577 L67.3262 352.9912 L67.0686 353.6663 L66.8138 353.667" style="fill:none; fill-rule:evenodd;"
/><path d="M69.4623 219.9955 L63.3962 263.6895 L59.3391 295.6697 L56.3967 322.656 L53.599 353.6668" style="fill:none; fill-rule:evenodd;"
/><line y2="353.6667" style="fill:none;" x1="40" x2="40" y1="217.9333"
/><path d="M195.2145 353.6667 L195.0738 348.5793 L194.4505 341.8228 L193.6605 336.795 L192.1878 330.1717 L190.7778 325.2814 L188.5077 318.887 L186.5251 314.1996 L183.5293 308.1113 L181.0325 303.6762 L177.3916 297.9502 L173.4191 292.4489 L169.1409 287.1816 L164.5822 282.1549 L159.7665 277.3738 L154.7164 272.8414 L149.4523 268.559 L143.9936 264.5274 L138.3583 260.7463 L132.5632 257.2152 L125.1177 253.1514 L119.0173 250.1785 L112.8035 247.4509 L106.488 244.9673 L98.4683 242.2035 L91.9653 240.2628 L83.7443 238.1725 L77.1051 236.7673 L68.7429 235.3427 L62.0134 234.467 L53.5653 233.7016 L46.788 233.352 L39.9596 233.264" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M183.7582 353.6667 L183.5904 348.5804 L183.0889 343.516 L182.2594 338.4949 L181.1113 333.5371 L179.6567 328.6602 L177.9097 323.8802 L175.886 319.2104 L172.7861 313.1749 L170.1817 308.8022 L166.3677 303.1903 L163.2717 299.1509 L158.8578 293.9969 L155.3509 290.3082 L150.4376 285.6278 L146.5897 282.2964 L141.2625 278.0927 L137.1325 275.1183 L131.4631 271.3889 L125.6262 267.9275 L119.6395 264.7321 L113.5193 261.8003 L107.2808 259.1296 L100.9376 256.7174 L94.5029 254.562 L87.9885 252.6607 L81.4055 251.0121 L74.7647 249.6142 L68.0764 248.4657 L61.3502 247.5653 L54.5954 246.9121 L47.8212 246.5055 L39.9596 246.3552" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M174.4859 353.6667 L174.3957 350.2749 L173.9235 345.2082 L173.0565 340.1939 L171.8105 335.26 L170.2068 330.4305 L168.2694 325.7246 L166.0245 321.1573 L163.4975 316.7397 L160.7134 312.4796 L157.6954 308.3818 L154.4646 304.4491 L149.8598 299.4651 L146.2059 295.9223 L142.3974 292.5461 L138.4482 289.3355 L132.9851 285.31 L128.7543 282.4808 L122.9543 278.9582 L118.4966 276.5014 L112.4253 273.4702 L107.7854 271.3778 L101.497 268.8269 L95.1055 266.5462 L88.6249 264.5328 L83.7136 263.1967 L77.1071 261.6452 L70.4446 260.3551 L63.7372 259.3245 L58.6832 258.721 L51.9217 258.1418 L45.1431 257.8192 L39.9596 257.7688" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M166.8823 353.6667 L166.7709 350.2758 L166.1904 345.221 L165.5367 341.8918 L164.1787 336.988 L163.0382 333.7926 L161.0058 329.1274 L159.4545 326.1099 L156.8625 321.7303 L153.9856 317.5326 L150.8563 313.519 L147.5037 309.6899 L143.9524 306.0443 L140.2238 302.58 L136.3367 299.2946 L132.3073 296.1853 L128.1496 293.2497 L123.8764 290.4848 L119.4988 287.8884 L115.0268 285.4579 L108.933 282.472 L104.275 280.4207 L97.9612 277.9334 L93.1572 276.2515 L86.6728 274.251 L81.7572 272.9306 L75.1441 271.4077 L70.1465 270.4426 L63.4425 269.3904 L58.3898 268.7763 L51.629 268.19 L46.5461 267.9243 L39.9596 267.8048" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M160.6028 353.6667 L160.4615 350.2773 L160.0417 346.9109 L159.3554 343.5886 L157.8652 338.7242 L156.5951 335.5782 L155.1288 332.5186 L153.4866 329.5496 L150.7336 325.2699 L148.7282 322.5328 L145.4984 318.5999 L143.214 316.0911 L139.6138 312.4938 L135.8291 309.091 L131.882 305.878 L127.7913 302.8498 L123.5727 300.0023 L119.2399 297.3319 L114.8048 294.8351 L110.2778 292.5088 L105.6685 290.3505 L100.985 288.3575 L96.2355 286.5279 L91.4268 284.8597 L84.9347 282.8838 L75.053 280.4452 L70.0595 279.4596 L63.3589 278.3857 L58.3075 277.7598 L51.5477 277.1631 L46.465 276.8937 L39.9596 276.7762" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M155.41 353.6667 L155.3633 351.9709 L154.994 348.5993 L154.2759 345.2843 L153.2444 342.0528 L151.9395 338.9214 L150.4006 335.8978 L148.662 332.9845 L145.7412 328.8176 L143.618 326.171 L140.2117 322.3898 L137.813 319.9901 L134.0491 316.5645 L130.1112 313.3403 L126.0222 310.3101 L121.8002 307.4676 L117.4606 304.8081 L110.0018 300.77 L105.4082 298.5781 L100.7374 296.5557 L95.998 294.7004 L91.1973 293.0098 L81.439 290.116 L71.5137 287.8615 L61.4657 286.2372 L51.3366 285.2369 L46.2539 284.9693 L39.9596 284.8618" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M151.1405 353.6667 L151.0752 351.9717 L150.5653 348.6199 L149.6042 345.3679 L148.2757 342.247 L146.6586 339.265 L144.8141 336.4175 L142.7876 333.6964 L140.6115 331.0932 L138.3094 328.6006 L134.6582 325.0555 L132.1107 322.8141 L128.1439 319.6258 L121.2033 314.7513 L113.9244 310.3974 L106.3699 306.5411 L101.7258 304.4586 L97.009 302.5461 L92.2278 300.8009 L87.3894 299.2211 L77.5679 296.5503 L69.2648 294.8157 L59.1976 293.3164 L49.0564 292.4464 L39.9596 292.2284" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M147.6857 353.6667 L147.5855 351.9739 L147.2933 350.3035 L146.8316 348.6715 L145.5069 345.5508 L143.8002 342.6198 L141.8339 339.8553 L139.68 337.2338 L137.3815 334.7382 L134.9655 332.3557 L131.1605 328.9758 L128.5214 326.8432 L124.4311 323.8147 L117.3166 319.1975 L109.8949 315.0916 L102.2224 311.4756 L94.3434 308.3344 L86.2947 305.6571 L76.4576 303.0444 L68.1443 301.3601 L58.0678 299.9231 L49.6156 299.2089 L39.9596 298.9434" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M144.9865 353.6667 L144.807 351.9826 L144.3155 350.3607 L143.6029 348.8221 L141.7842 345.9605 L139.6669 343.3099 L137.37 340.8128 L132.4186 336.1745 L127.1218 331.9339 L120.1327 327.1291 L112.8164 322.8387 L105.2328 319.0397 L97.4284 315.7173 L89.4421 312.8601 L81.3064 310.46 L73.0512 308.5104 L64.7033 307.0065 L56.2877 305.9442 L47.8282 305.3214 L39.9596 305.1496" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M143.0408 353.6667 L142.6229 352.0374 L141.7282 350.5985 L140.6642 349.2775 L138.3364 346.8095 L133.3133 342.2486 L126.6089 337.0543 L120.9804 333.2641 L113.6686 328.9654 L107.6296 325.8698 L99.8801 322.422 L93.5424 319.996 L85.4759 317.3733 L78.9258 315.5994 L70.6401 313.7836 L63.9493 312.6499 L55.5286 311.6289 L47.0662 311.0462 L39.9596 310.9243" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M141.9424 353.6667 L140.7696 352.491 L131.3182 345.2996 L125.7623 341.403 L120.0331 337.7659 L114.1364 334.4076 L108.0857 331.3351 L101.8973 328.5506 L95.5874 326.0538 L89.1713 323.8437 L82.6637 321.9188 L76.0791 320.2778 L67.7595 318.6234 L61.0487 317.6159 L54.3016 316.8884 L47.5302 316.4398 L39.9596 316.2891" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M138.5429 353.6667 L135.5478 352.0761 L121.1597 343.0869 L112.2256 338.2103 L106.1025 335.2852 L101.4283 333.2704 L96.6902 331.4113 L90.2826 329.1766 L85.4165 327.6843 L78.8588 325.9389 L72.2328 324.473 L65.5513 323.2858 L58.8262 322.3766 L52.0695 321.7451 L45.2926 321.3906 L39.9596 321.3297" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M132.2571 353.6667 L118.9607 346.1593 L112.9355 343.0365 L108.3411 340.8463 L102.1148 338.1471 L97.374 336.2952 L87.7279 333.0466 L82.8329 331.6526 L76.2423 330.0343 L71.2585 329.0012 L64.5682 327.8644 L59.523 327.1927 L52.7685 326.5377 L45.9929 326.1574 L39.9596 326.0639" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M125.5106 353.6667 L113.44 347.4614 L104.1533 343.2944 L97.8351 340.8181 L93.0336 339.1294 L83.2864 336.1983 L73.3773 333.8722 L68.374 332.9378 L61.663 331.93 L51.534 330.9284 L46.4514 330.6577 L39.9596 330.5401" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M118.1841 353.6667 L108.9537 349.3753 L99.5211 345.55 L89.8852 342.2711 L80.0709 339.5727 L70.1119 337.4701 L60.0446 335.9701 L49.9055 335.0758 L39.9596 334.7948" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M110.0959 353.6667 L100.6553 349.8605 L92.6411 347.081 L82.862 344.2575 L74.5974 342.3473 L66.2486 340.8472 L57.836 339.7611 L49.38 339.0911 L39.9596 338.8563" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M100.9436 353.6667 L92.9177 350.9204 L84.7732 348.5496 L76.5247 346.5711 L69.8629 345.2776 L61.4732 344.0269 L54.7236 343.3216 L47.9518 342.8798 L39.9596 342.7095" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M90.1477 353.6667 L83.6035 351.8702 L76.9963 350.3214 L70.335 349.0255 L65.309 348.2217 L58.5756 347.3762 L51.8148 346.7906 L45.0363 346.4659 L39.9596 346.394" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M76.2695 353.6667 L66.2485 351.8825 L57.8311 350.8329 L47.6786 350.1035 L39.9596 349.9543" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><path d="M50.7775 353.6667 L43.997 353.3881 L39.9596 353.3555" style="fill:none; fill-rule:evenodd; stroke:rgb(0,48,143);"
/><line x1="40" x2="141.8" y1="353.6667" style="fill:none; stroke:black; stroke-width:1.3333;" y2="353.6667"
/></g
></g
></svg
>

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
<html>
<head>
<title>GeographicLib-@PROJECT_VERSION@ utilities</title>
<meta HTTP-EQUIV="Refresh"
CONTENT="0; URL=https://geographiclib.sourceforge.io/C++/@PROJECT_VERSION@/utilities.html">
</head>
<body topmargin=10 leftmargin=10>
<h3>
<blockquote>
<em>
Online documentation for utilities for GeographicLib version
@PROJECT_VERSION@ is available at
<center>
<a href="https://geographiclib.sourceforge.io/C++/@PROJECT_VERSION@/utilities.html">
https://geographiclib.sourceforge.io/C++/@PROJECT_VERSION@/utilities.html</a>.
</center>
<br>
You will be redirected there. Click on the link to go there
directly.
</em>
</blockquote>
</h3>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,505 @@
/**
* \file AuxLatitude.hpp
* \brief Header for the GeographicLib::AuxLatitude and GeographicLib::AuxAngle
* classes.
*
* \note This is just sample code. It is not part of GeographicLib itself.
*
* This file is an implementation of the methods described in
* - C. F. F. Karney,
* On auxiliary latitudes,
* Technical Report, SRI International, December 2022.
* https://arxiv.org/abs/2212.05818
* .
* Copyright (c) Charles Karney (2022) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#if !defined(AUXLATITUDE_HPP)
#define AUXLATITUDE_HPP 1
#include <GeographicLib/Math.hpp>
#if !defined(GEOGRAPHICLIB_AUXLATITUDE_ORDER)
/**
* The order of the series approximation used in AuxLatitude.
* GEOGRAPHICLIB_AUXLATITUDE_ORDER can be set to one of [4, 6, 8].
**********************************************************************/
# define GEOGRAPHICLIB_AUXLATITUDE_ORDER 6
#endif
namespace GeographicLib {
/**
* \brief An accurate representation of angles.
*
* \note This is just sample code. It is not part of GeographicLib itself.
*
* This class is an implementation of the methods described in
* - C. F. F. Karney,
* On auxiliary latitudes,
* Technical Report, SRI International, December 2022.
* https://arxiv.org/abs/2212.05818
*
* An angle is represented be the \e y and \e x coordinates of a point in the
* 2d plane. The two coordinates are proportional to the sine and cosine of
* the angle. This allows angles close to the cardinal points to be
* represented accurately. Only angles in [&minus;180&deg;, 180&deg;] can be
* represented. (A possible extension would be to keep count of the number
* of turns.)
*
* @tparam T the floating-point type to use for real numbers.
**********************************************************************/
template<typename T = double>
class AuxAngle {
public:
/**
* The floating-point type for real numbers. This just connects to the
* template parameters for the class.
**********************************************************************/
typedef T real;
/**
* The constructor.
*
* @param[in] y the \e y coordinate.
* @param[in] x the \e x coordinate.
*
* \note the \e y coordinate is specified \e first.
* \warning either \e x or \e y can be infinite, but not both.
*
* The defaults (\e x = 1 and \e y = 0) are such that
* + no arguments gives an angle of 0;
* + 1 argument specifies the tangent of the angle.
**********************************************************************/
AuxAngle(real y = 0, real x = 1) : _y(y), _x(x) {}
/**
* @return the \e y component. This is the sine of the angle if the
* AuxAngle has been normalized.
**********************************************************************/
real y() const { return _y; }
/**
* @return the \e x component. This is the cosine of the angle if the
* AuxAngle has been normalized.
**********************************************************************/
real x() const { return _x; }
/**
* @return a reference to the \e y component. This allows this component
* to be altered.
**********************************************************************/
real& y() { return _y; }
/**
* @return a reference to the \e x component. This allows this component
* to be altered.
**********************************************************************/
real& x() { return _x; }
/**
* @return the AuxAngle converted to the conventional angle measured in
* degrees.
**********************************************************************/
real degrees() const;
/**
* @return the AuxAngle converted to the conventional angle measured in
* radians.
**********************************************************************/
real radians() const;
/**
* @return the tangent of the angle.
**********************************************************************/
real tan() const { return _y / _x; }
/**
* @return a new normalized AuxAngle with the point lying on the unit
* circle and the \e y and \e x components are equal to the sine and
* cosine of the angle.
**********************************************************************/
AuxAngle normalized() const;
/**
* Normalize the AuxAngle in place so that the \e y and \e x components are
* equal to the sine and cosine of the angle.
**********************************************************************/
void normalize() { *this = normalized(); }
/**
* Set the quadrant for the AuxAngle.
*
* @param[in] p the AuxAngle from which the quadrant information is taken.
* @return the new AuxAngle in the same quadrant as \e p.
**********************************************************************/
AuxAngle copyquadrant(const AuxAngle& p) const;
/**
* Add an AuxAngle.
*
* @param[in] p the AuxAngle to be added.
* @return a reference to the new AuxAngle.
*
* The addition is done in place, altering the current AuxAngle.
*
* \warning Neither *this nor \e p should have an infinite component. If
* necessary, invoke AuxAngle::normalize on these angles first.
**********************************************************************/
AuxAngle& operator+=(const AuxAngle& p);
/**
* Convert degrees to an AuxAngle.
*
* @param[in] d the angle measured in degrees.
* @return the corresponding AuxAngle.
*
* This allows a new AuxAngle to be initialized as an angle in degrees with
* @code
* AuxAngle<real> phi = AuxAngle<real>::degrees(d);
* @endcode
* This is the so-called "named constructor" idiom.
**********************************************************************/
static AuxAngle degrees(real d);
/**
* Convert radians to an AuxAngle.
*
* @param[in] r the angle measured in radians.
* @return the corresponding AuxAngle.
*
* This allows a new AuxAngle to be initialized as an angle in radians with
* @code
* AuxAngle<real> phi = AuxAngle<real>::radians(r);
* @endcode
* This is the so-called "named constructor" idiom.
**********************************************************************/
static AuxAngle radians(real r);
/**
* @return a "NaN" AuxAngle.
**********************************************************************/
static AuxAngle NaN();
/**
* Compute the absolute error in another angle.
*
* @tparam T1 the floating-point type of the other angle.
* @param[in] p the other angle
* @return the absolute error between p and *this considered as angles in
* radians.
**********************************************************************/
template<typename T1>
real AbsError(const AuxAngle<T1>& p) const;
/**
* Compute the relative error in another angle.
*
* @tparam T1 the floating-point type of the other angle.
* @param[in] p the other angle
* @return the relative error between p.tan() and this->tan().
**********************************************************************/
template<typename T1>
real RelError(const AuxAngle<T1>& p) const;
private:
real _y, _x;
};
/// \cond SKIP
template<typename T>
inline AuxAngle<T> AuxAngle<T>::degrees(real d) {
real y, x;
Math::sincosd(d, y, x);
return AuxAngle(y, x);
}
template<typename T>
inline AuxAngle<T> AuxAngle<T>::radians(real r) {
using std::sin; using std::cos;
return AuxAngle(sin(r), cos(r));
}
template<typename T>
inline T AuxAngle<T>::degrees() const {
return Math::atan2d(_y, _x);
}
template<typename T>
inline T AuxAngle<T>::radians() const {
using std::atan2; return atan2(_y, _x);
}
template<typename T> template<typename T1>
inline T AuxAngle<T>::AbsError(const AuxAngle<T1>& p) const {
using std::fabs;
return fabs((AuxAngle(-T(p.y()), T(p.x())) += *this).radians());
}
template<typename T> template<typename T1>
inline T AuxAngle<T>::RelError(const AuxAngle<T1>& p) const {
using std::fabs;
return fabs((T(p.y()) / T(p.x()) - tan()) / tan());
}
/// \endcond
/**
* \brief Conversions between auxiliary latitudes.
*
* \note This is just sample code. It is not part of GeographicLib itself.
*
* This class is an implementation of the methods described in
* - C. F. F. Karney,
* On auxiliary latitudes,
* Technical Report, SRI International, December 2022.
* https://arxiv.org/abs/2212.05818
*
* The provides accurate conversions between geographic (\e phi, &phi;),
* parametric (\e beta, &beta;), geocentric (\e theta, &theta;), rectifying
* (\e mu, &mu;), conformal (\e chi, &chi;), and authalic (\e xi, &xi;)
* latitudes for an ellipsoid of revolution. A latitude is represented by an
* AuxAngle in order to maintain precision close to the poles.
*
* The class implements two methods for the conversion:
* - Direct evaluation of the defining equations, the \e exact method. These
* equations are formulated so as to preserve relative accuracy of the
* tangent of the latitude, ensuring high accuracy near the equator and the
* poles. Newton's method is used for those conversions that can't be
* expressed in closed form.
* - Expansions in powers of &e n, the third flattening, the \e series
* method. This delivers full accuracy for abs(\e f) &le; 1/150. Here, \e
* f is the flattening of the ellipsoid.
*
* The series method is the preferred method of conversion for any conversion
* involving &mu;, &chi;, or &xi;, with abs(\e f) &le; 1/150. The equations
* for the conversions between &phi;, &beta;, and &theta; are sufficiently
* simple that the exact method should be used for such conversions and also
* for conversions with with abs(\e f) &gt; 1/150.
*
* @tparam T the floating-point type to use.
*
* Example of use:
* \include example-AuxLatitude.cpp
*
* For more information on this projection, see \ref auxlat.
**********************************************************************/
template<typename T = double>
class AuxLatitude {
public:
/**
* The floating-point type for real numbers. This just connects to the
* template parameters for the class.
**********************************************************************/
typedef T real;
/**
* The type used to represent angles.
**********************************************************************/
typedef AuxAngle<real> angle;
/**
* The different auxiliary latitudes.
**********************************************************************/
enum aux {
/**
* Geographic latitude, \e phi, &phi;
* @hideinitializer
**********************************************************************/
GEOGRAPHIC = 0,
/**
* Parametric latitude, \e beta, &beta;
* @hideinitializer
**********************************************************************/
PARAMETRIC = 1,
/**
* %Geocentric latitude, \e theta, &theta;
* @hideinitializer
**********************************************************************/
GEOCENTRIC = 2,
/**
* Rectifying latitude, \e mu, &mu;
* @hideinitializer
**********************************************************************/
RECTIFYING = 3,
/**
* Conformal latitude, \e chi, &chi;
* @hideinitializer
**********************************************************************/
CONFORMAL = 4,
/**
* Authalic latitude, \e xi, &xi;
* @hideinitializer
**********************************************************************/
AUTHALIC = 5,
/**
* The total number of auxiliary latitudes
* @hideinitializer
**********************************************************************/
AUXNUMBER = 6,
/**
* An alias for GEOGRAPHIC
* @hideinitializer
**********************************************************************/
COMMON = GEOGRAPHIC,
/**
* An alias for GEOGRAPHIC
* @hideinitializer
**********************************************************************/
GEODETIC = GEOGRAPHIC,
/**
* An alias for PARAMETRIC
* @hideinitializer
**********************************************************************/
REDUCED = PARAMETRIC,
};
/**
* Constructor
*
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
* Negative \e f gives a prolate ellipsoid.
*
* \note the constructor does not precompute the coefficients for the
* Fourier series for the series conversions. These are computed and saved
* when first needed.
**********************************************************************/
AuxLatitude(real f);
/**
* Constructor
*
* @param[in] a equatorial radius.
* @param[in] b polar semi-axis.
*
* \note the constructor does not precompute the coefficients for the
* Fourier series for the series conversions. These are computed and saved
* when first needed.
**********************************************************************/
AuxLatitude(real a, real b);
/**
* Convert between any two auxiliary latitudes.
*
* @param[in] auxin an AuxLatitude::aux indicating the type of
* auxiliary latitude \e zeta.
* @param[in] auxout an AuxLatitude::aux indicating the type of
* auxiliary latitude \e eta.
* @param[in] zeta the input auxiliary latitude.
* @param[in] series if true use the Taylor series instead of the exact
* equations [default false].
* @return the output auxiliary latitude \e eta.
*
* With \e series = true, the Fourier coefficients for a specific \e auxin
* and \e auxout are computed and saved on the first call; the saved
* coefficients are used on subsequent calls. The series method is
* accurate for abs(\e f) &le; 1/150; for other \e f, the exact method
* should be used
**********************************************************************/
angle Convert(int auxin, int auxout, const angle& zeta,
bool series = false) const;
/**
* Convert geographic latitude to an auxiliary latitude \e eta.
*
* @param[in] auxout an AuxLatitude::aux indicating the auxiliary
* latitude returned.
* @param[in] phi the geographic latitude.
* @param[out] diff optional pointer to the derivative d tan(\e eta) / d
* tan(\e phi).
* @return the auxiliary latitude \e eta.
*
* This uses the exact equations.
**********************************************************************/
angle ToAuxiliary(int auxout, const angle& phi,
real* diff = nullptr) const;
/**
* Convert an auxiliary latitude \e zeta to geographic latitude.
*
* @param[in] auxin an AuxLatitude::aux indicating the type of
* auxiliary latitude \e zeta.
* @param[in] zeta the input auxiliary latitude.
* @param[out] niter optional pointer to the number of iterations.
* @return the geographic latitude \e phi.
*
* This uses the exact equations.
**********************************************************************/
angle FromAuxiliary(int auxin, const angle& zeta,
int* niter = nullptr) const;
/**
* @return \e f, the flattening of the ellipsoid.
**********************************************************************/
real Flattening() const { return _f; }
/**
* The order of the series expansions. This is set at compile time to
* either 4, 6, or 8, by the preprocessor macro
* GEOGRAPHICLIB_AUXLATITUDE_ORDER.
* @hideinitializer
**********************************************************************/
static const int Lmax = GEOGRAPHICLIB_AUXLATITUDE_ORDER;
private:
/**
* Convert geographic latitude to parametric latitude
*
* @param[in] phi geographic latitude.
* @param[out] diff optional pointer to the derivative d tan(\e beta) / d
* tan(\e phi).
* @return \e beta, the parametric latitude
**********************************************************************/
angle Parametric(const angle& phi, real* diff = nullptr) const;
/**
* Convert geographic latitude to geocentric latitude
*
* @param[in] phi geographic latitude.
* @param[out] diff optional pointer to the derivative d tan(\e theta) / d
* tan(\e phi).
* @return \e theta, the geocentric latitude.
**********************************************************************/
angle Geocentric(const angle& phi, real* diff = nullptr) const;
/**
* Convert geographic latitude to rectifying latitude
*
* @param[in] phi geographic latitude.
* @param[out] diff optional pointer to the derivative d tan(\e mu) / d
* tan(\e phi).
* @return \e mu, the rectifying latitude.
**********************************************************************/
angle Rectifying(const angle& phi, real* diff = nullptr) const;
/**
* Convert geographic latitude to conformal latitude
*
* @param[in] phi geographic latitude.
* @param[out] diff optional pointer to the derivative d tan(\e chi) / d
* tan(\e phi).
* @return \e chi, the conformal latitude.
**********************************************************************/
angle Conformal(const angle& phi, real* diff = nullptr) const;
/**
* Convert geographic latitude to authalic latitude
*
* @param[in] phi geographic latitude.
* @param[out] diff optional pointer to the derivative d tan(\e xi) / d
* tan(\e phi).
* @return \e xi, the authalic latitude.
**********************************************************************/
angle Authalic(const angle& phi, real* diff = nullptr) const;
// Maximum number of iterations for Newton's method
static const int numit_ = 1000;
real tol_, bmin_, bmax_; // Static consts for Newton's method
// Ellipsoid parameters
real _f, _fm1, _e2, _e2m1, _e12, _e12p1, _n, _e, _e1, _n2, _q;
// To hold computed Fourier coefficients
mutable real _c[Lmax * AUXNUMBER * AUXNUMBER];
// 1d index into AUXNUMBER x AUXNUMBER data
static int ind(int auxout, int auxin) {
return (auxout >= 0 && auxout < AUXNUMBER &&
auxin >= 0 && auxin < AUXNUMBER) ?
AUXNUMBER * auxout + auxin : -1;
}
// the function sqrt(1 + tphi^2), convert tan to sec
static real sc(real tphi)
{ using std::hypot; return hypot(real(1), tphi); }
// the function tphi / sqrt(1 + tphi^2), convert tan to sin
static real sn(real tphi) {
using std::isfinite; using std::isnan; using std::copysign;
return isfinite(tphi) || isnan(tphi) ? tphi / sc(tphi) :
copysign(real(1), tphi);
}
// The symmetric elliptic integral RD
static real RD(real x, real y, real z);
// The symmetric elliptic integral RF
static real RF(real x, real y, real z);
// the function atanh(e * sphi)/e; works for e^2 = 0 and e^2 < 0
real atanhee(real tphi) const;
// the function atanh(e * sphi)/e + sphi / (1 - (e * sphi)^2);
real q(real tphi) const;
// The divided difference of (q(1) - q(sphi)) / (1 - sphi)
real Dq(real tphi) const;
// Populate [_c[Lmax * k], _c[Lmax * (k + 1)])
void fillcoeff(int auxin, int auxout, int k) const;
// Clenshaw applied to sum(c[k] * sin( (2*k+2) * zeta), i, 0, K-1)
// if alt, use the Reinsch optimizations
static real Clenshaw(real szeta, real czeta, const real c[], int K,
bool alt = true);
};
} // namespace GeographicLib
#endif // AUXLATITUDE_HPP

View File

@@ -0,0 +1,169 @@
# This CMakeLists.txt is invoked in two different ways
# (1) With "add_subdirectory (examples)" from GeographicLib's top-level
# CMakeLists.txt. This mode of invocation is flagged by the variable
#
# CALLED_FROM_TOPLEVEL
#
# In this case, the only action taken is to install the examples and
# this CMakeLists.txt in ${EXAMPLEDIR}.
# (2) As an independent invocation of
#
# cmake -S <this-directory> -B <build-directory>
#
# In this case, find_package (GeographicLib) is called and the examples
# are compiled. This mode of invocation is triggered by the
# exampleprograms target in the top-level CMakeLists.txt. In this case,
# the current version of GeographicLib is found by specifying
#
# -D GeographicLib_DIR=${PROJECT_BINARY_DIR}
cmake_minimum_required (VERSION 3.13.0)
set (EXAMPLES0
example-Accumulator.cpp
example-AlbersEqualArea.cpp
example-AzimuthalEquidistant.cpp
example-CassiniSoldner.cpp
example-CircularEngine.cpp
example-Constants.cpp
example-DMS.cpp
example-DST.cpp
example-Ellipsoid.cpp
example-EllipticFunction.cpp
example-GARS.cpp
example-GeoCoords.cpp
example-Geocentric.cpp
example-Geodesic.cpp
example-Geodesic-small.cpp
example-GeodesicExact.cpp
example-GeodesicLine.cpp
example-GeodesicLineExact.cpp
example-GeographicErr.cpp
example-Geohash.cpp
example-Geoid.cpp
example-Georef.cpp
example-Gnomonic.cpp
example-GravityCircle.cpp
example-GravityModel.cpp
example-LambertConformalConic.cpp
example-LocalCartesian.cpp
example-MGRS.cpp
example-MagneticCircle.cpp
example-MagneticModel.cpp
example-Math.cpp
example-NearestNeighbor.cpp
example-NormalGravity.cpp
example-OSGB.cpp
example-PolarStereographic.cpp
example-PolygonArea.cpp
example-Rhumb.cpp
example-RhumbLine.cpp
example-SphericalEngine.cpp
example-SphericalHarmonic.cpp
example-SphericalHarmonic1.cpp
example-SphericalHarmonic2.cpp
example-TransverseMercator.cpp
example-TransverseMercatorExact.cpp
example-UTMUPS.cpp
example-Utility.cpp
)
set (EXAMPLES1
GeoidToGTX.cpp make-egmcof.cpp JacobiConformal.cpp example-AuxLatitude.cpp)
set (EXAMPLEHEADERS JacobiConformal.hpp AuxLatitude.cpp AuxLatitude.hpp)
if (CALLED_FROM_TOPLEVEL)
if (EXAMPLEDIR)
install (FILES CMakeLists.txt ${EXAMPLES0} ${EXAMPLES1} ${EXAMPLEHEADERS}
DESTINATION ${EXAMPLEDIR})
endif ()
# No more to do in add_subdirectory mode, so exit
return ()
endif ()
project (GeographicLib-examples)
# Set a default build type for single-configuration cmake generators if
# no build type is set.
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Release)
endif ()
if (MSVC OR CMAKE_CONFIGURATION_TYPES)
# For multi-config systems and for Visual Studio, the debug version of
# the library is called Geographic_d.
set (CMAKE_DEBUG_POSTFIX "_d" CACHE STRING "The suffix for debug objects")
else ()
set (CMAKE_DEBUG_POSTFIX "" CACHE STRING "The suffix for debug objects")
endif ()
find_package (GeographicLib 2.0 REQUIRED)
include_directories (${GeographicLib_INCLUDE_DIRS})
option (USE_BOOST_FOR_EXAMPLES
"Look for Boost library when compiling examples" ON)
if (USE_BOOST_FOR_EXAMPLES)
# quad precision numbers appeared in Boost 1.54. Various
# workarounds stopped being needed with Boost 1.64.
find_package (Boost 1.64 COMPONENTS serialization)
elseif (GEOGRAPHICLIB_PRECISION EQUAL 4)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
find_package (Boost 1.64)
endif ()
endif ()
# Compile a bunch of tiny example programs. These are built with the
# "exampleprograms" target. These are mainly for including as examples
# within the doxygen documentation; however, compiling them catches some
# obvious blunders.
if (NOT GEOGRAPHICLIB_PRECISION OR GEOGRAPHICLIB_PRECISION EQUAL 2)
# These examples all assume real = double, so check
# GEOGRAPHICLIB_PRECISION. Allow GEOGRAPHICLIB_PRECISION to be unset
# to accommodate lame FindGeographicLib.cmake.
set (EXAMPLE_SOURCES ${EXAMPLES0})
if (USE_BOOST_FOR_EXAMPLES AND Boost_FOUND)
add_definitions (-DGEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION=1)
include_directories ("${Boost_INCLUDE_DIRS}")
endif ()
else ()
set (EXAMPLE_SOURCES)
endif ()
set (EXAMPLE_SOURCES ${EXAMPLE_SOURCES} ${EXAMPLES1})
set (EXAMPLES)
foreach (EXAMPLE_SOURCE ${EXAMPLE_SOURCES})
get_filename_component (EXAMPLE ${EXAMPLE_SOURCE} NAME_WE)
set (EXAMPLES ${EXAMPLES} ${EXAMPLE})
if (EXAMPLE STREQUAL "JacobiConformal")
set (EXAMPLE_SOURCE ${EXAMPLE_SOURCE} JacobiConformal.hpp)
endif ()
if (EXAMPLE STREQUAL "example-AuxLatitude")
set (EXAMPLE_SOURCE ${EXAMPLE_SOURCE} AuxLatitude.cpp AuxLatitude.hpp)
endif ()
add_executable (${EXAMPLE} ${EXAMPLE_SOURCE})
target_link_libraries (${EXAMPLE}
${GeographicLib_LIBRARIES} ${GeographicLib_HIGHPREC_LIBRARIES})
endforeach ()
if (Boost_FOUND AND GEOGRAPHICLIB_PRECISION EQUAL 2)
target_link_libraries (example-NearestNeighbor ${Boost_LIBRARIES})
endif ()
find_package (OpenMP QUIET)
if (OPENMP_FOUND OR OpenMP_FOUND)
set_target_properties (GeoidToGTX PROPERTIES
COMPILE_FLAGS ${OpenMP_CXX_FLAGS})
if (NOT WIN32)
set_target_properties (GeoidToGTX PROPERTIES
LINK_FLAGS ${OpenMP_CXX_FLAGS})
endif ()
endif ()
if (MSVC OR CMAKE_CONFIGURATION_TYPES)
# Add _d suffix for your debug versions of the tools
set_target_properties (${EXAMPLES} PROPERTIES
DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
endif ()

View File

@@ -0,0 +1,111 @@
// Write out a gtx file of geoid heights above the ellipsoid. For egm2008 at
// 1' resolution this takes about 10 mins on a 8-processor Intel 3.0 GHz
// machine using OpenMP.
//
// For the format of gtx files, see
// https://vdatum.noaa.gov/docs/gtx_info.html#dev_gtx_binary
//
// data is binary big-endian:
// south latitude edge (degrees double)
// west longitude edge (degrees double)
// delta latitude (degrees double)
// delta longitude (degrees double)
// nlat = number of latitude rows (integer)
// nlong = number of longitude columns (integer)
// nlat * nlong geoid heights (meters float)
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#if defined(_OPENMP)
#define HAVE_OPENMP 1
#else
#define HAVE_OPENMP 0
#endif
#if HAVE_OPENMP
# include <omp.h>
#endif
#include <GeographicLib/GravityModel.hpp>
#include <GeographicLib/GravityCircle.hpp>
#include <GeographicLib/Utility.hpp>
using namespace std;
using namespace GeographicLib;
int main(int argc, const char* const argv[]) {
// Hardwired for 3 args:
// 1 = the gravity model (e.g., egm2008)
// 2 = intervals per degree
// 3 = output GTX file
if (argc != 4) {
cerr << "Usage: " << argv[0]
<< " gravity-model intervals-per-degree output.gtx\n";
return 1;
}
try {
// Will need to set the precision for each thread, so save return value
int ndigits = Utility::set_digits();
string model(argv[1]);
// Number of intervals per degree
int ndeg = Utility::val<int>(string(argv[2]));
string filename(argv[3]);
GravityModel g(model);
int
nlat = 180 * ndeg + 1,
nlon = 360 * ndeg;
Math::real
delta = 1 / Math::real(ndeg), // Grid spacing
latorg = -90,
lonorg = -180;
// Write results as floats in binary mode
ofstream file(filename.c_str(), ios::binary);
// Write header
{
Math::real transform[] = {latorg, lonorg, delta, delta};
unsigned sizes[] = {unsigned(nlat), unsigned(nlon)};
Utility::writearray<double, Math::real, true>(file, transform, 4);
Utility::writearray<unsigned, unsigned, true>(file, sizes, 2);
}
// Compute and store results for nbatch latitudes at a time
const int nbatch = 64;
vector< vector<float> > N(nbatch, vector<float>(nlon));
for (int ilat0 = 0; ilat0 < nlat; ilat0 += nbatch) { // Loop over batches
int nlat0 = min(nlat, ilat0 + nbatch);
#if HAVE_OPENMP
# pragma omp parallel for
#endif
for (int ilat = ilat0; ilat < nlat0; ++ilat) { // Loop over latitudes
Utility::set_digits(ndigits); // Set the precision
Math::real
lat = latorg + (ilat / ndeg) + delta * (ilat - ndeg * (ilat / ndeg)),
h = 0;
GravityCircle c(g.Circle(lat, h, GravityModel::GEOID_HEIGHT));
for (int ilon = 0; ilon < nlon; ++ilon) { // Loop over longitudes
Math::real lon = lonorg
+ (ilon / ndeg) + delta * (ilon - ndeg * (ilon / ndeg));
N[ilat - ilat0][ilon] = float(c.GeoidHeight(lon));
} // longitude loop
} // latitude loop -- end of parallel section
for (int ilat = ilat0; ilat < nlat0; ++ilat) // write out data
Utility::writearray<float, float, true>(file, N[ilat - ilat0]);
} // batch loop
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,43 @@
// Example of using the GeographicLib::JacobiConformal class.
#include <iostream>
#include <iomanip>
#include <exception>
#include <GeographicLib/Utility.hpp>
#include "JacobiConformal.hpp"
using namespace std;
using namespace GeographicLib;
int main() {
try {
Utility::set_digits();
// These parameters were derived from the EGM2008 geoid; see 2011-07-04
// E-mail to PROJ.4 list, "Analyzing the bumps in the EGM2008 geoid". The
// longitude of the major axis is -15. These are close to the values given
// by Milan Bursa, Vladimira Fialova, "Parameters of the Earth's tri-axial
// level ellipsoid", Studia Geophysica et Geodaetica 37(1), 1-13 (1993):
//
// longitude of major axis = -14.93 +/- 0.05
// a = 6378171.36 +/- 0.30
// a/(a-c) = 297.7738 +/- 0.0003
// a/(a-b) = 91449 +/- 60
// which gives: a = 6378171.36, b = 6378101.61, c = 6356751.84
Math::real a = 6378137+35, b = 6378137-35, c = 6356752;
JacobiConformal jc(a, b, c, a-b, b-c);
cout << fixed << setprecision(1)
<< "Ellipsoid parameters: a = "
<< a << ", b = " << b << ", c = " << c << "\n"
<< setprecision(10)
<< "Quadrants: x = " << jc.x() << ", y = " << jc.y() << "\n";
cout << "Coordinates (angle x y) in degrees:\n";
for (int i = 0; i <= 90; i += 5) {
Math::real omg = i, bet = i;
cout << i << " " << jc.x(omg) << " " << jc.y(bet) << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,176 @@
/**
* \file JacobiConformal.hpp
* \brief Header for GeographicLib::JacobiConformal class
*
* \note This is just sample code. It is not part of GeographicLib
* itself.
*
* Copyright (c) Charles Karney (2014-2020) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
#if !defined(GEOGRAPHICLIB_JACOBICONFORMAL_HPP)
#define GEOGRAPHICLIB_JACOBICONFORMAL_HPP 1
#include <GeographicLib/EllipticFunction.hpp>
namespace GeographicLib {
/**
* \brief Jacobi's conformal projection of a triaxial ellipsoid
*
* <b>NOTE:</b> This is just sample code. It is not part of GeographicLib
* itself.
*
* This is a conformal projection of the ellipsoid to a plane in which
* the grid lines are straight; see Jacobi,
* <a href="https://books.google.com/books?id=ryEOAAAAQAAJ&pg=PA212">
* Vorlesungen &uuml;ber Dynamik, &sect;28</a>. The constructor takes the
* semi-axes of the ellipsoid (which must be in order). Member functions map
* the ellipsoidal coordinates &omega; and &beta; separately to \e x and \e
* y. Jacobi's coordinates have been multiplied by
* (<i>a</i><sup>2</sup>&minus;<i>c</i><sup>2</sup>)<sup>1/2</sup> /
* (2<i>b</i>) so that the customary results are returned in the cases of
* a sphere or an ellipsoid of revolution.
*
* The ellipsoid is oriented so that the large principal ellipse, \f$Z=0\f$,
* is the equator, \f$\beta=0\f$, while the small principal ellipse,
* \f$Y=0\f$, 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$.
*
* For more information on this projection, see \ref jacobi.
**********************************************************************/
class JacobiConformal {
typedef Math::real real;
real _a, _b, _c, _ab2, _bc2, _ac2;
EllipticFunction _ex, _ey;
static void norm(real& x, real& y) {
using std::hypot;
real z = hypot(x, y); x /= z; y /= z;
}
public:
/**
* Constructor for a trixial ellipsoid with semi-axes.
*
* @param[in] a the largest semi-axis.
* @param[in] b the middle semi-axis.
* @param[in] c the smallest semi-axis.
*
* The semi-axes must satisfy \e a &ge; \e b &ge; \e c > 0 and \e a >
* \e c. This form of the constructor cannot be used to specify a
* sphere (use the next constructor).
**********************************************************************/
JacobiConformal(real a, real b, real c)
: _a(a), _b(b), _c(c)
, _ab2((_a - _b) * (_a + _b))
, _bc2((_b - _c) * (_b + _c))
, _ac2((_a - _c) * (_a + _c))
, _ex(_ab2 / _ac2 * Math::sq(_c / _b), -_ab2 / Math::sq(_b),
_bc2 / _ac2 * Math::sq(_a / _b), Math::sq(_a / _b))
, _ey(_bc2 / _ac2 * Math::sq(_a / _b), +_bc2 / Math::sq(_b),
_ab2 / _ac2 * Math::sq(_c / _b), Math::sq(_c / _b))
{
using std::isfinite;
if (!(isfinite(_a) && _a >= _b && _b >= _c && _c > 0))
throw GeographicErr("JacobiConformal: axes are not in order");
if (!(_a > _c))
throw GeographicErr
("JacobiConformal: use alternate constructor for sphere");
}
/**
* Alternate constructor for a triaxial ellipsoid.
*
* @param[in] a the largest semi-axis.
* @param[in] b the middle semi-axis.
* @param[in] c the smallest semi-axis.
* @param[in] ab the relative magnitude of \e a &minus; \e b.
* @param[in] bc the relative magnitude of \e b &minus; \e c.
*
* This form can be used to specify a sphere. The semi-axes must
* satisfy \e a &ge; \e b &ge; c > 0. The ratio \e ab : \e bc must equal
* (<i>a</i>&minus;<i>b</i>) : (<i>b</i>&minus;<i>c</i>) with \e ab
* &ge; 0, \e bc &ge; 0, and \e ab + \e bc > 0.
**********************************************************************/
JacobiConformal(real a, real b, real c, real ab, real bc)
: _a(a), _b(b), _c(c)
, _ab2(ab * (_a + _b))
, _bc2(bc * (_b + _c))
, _ac2(_ab2 + _bc2)
, _ex(_ab2 / _ac2 * Math::sq(_c / _b),
-(_a - _b) * (_a + _b) / Math::sq(_b),
_bc2 / _ac2 * Math::sq(_a / _b), Math::sq(_a / _b))
, _ey(_bc2 / _ac2 * Math::sq(_a / _b),
+(_b - _c) * (_b + _c) / Math::sq(_b),
_ab2 / _ac2 * Math::sq(_c / _b), Math::sq(_c / _b))
{
using std::isfinite;
if (!(isfinite(_a) && _a >= _b && _b >= _c && _c > 0 &&
ab >= 0 && bc >= 0))
throw GeographicErr("JacobiConformal: axes are not in order");
if (!(ab + bc > 0 && isfinite(_ac2)))
throw GeographicErr("JacobiConformal: ab + bc must be positive");
}
/**
* @return the quadrant length in the \e x direction.
**********************************************************************/
Math::real x() const { return Math::sq(_a / _b) * _ex.Pi(); }
/**
* The \e x projection.
*
* @param[in] somg sin(&omega;).
* @param[in] comg cos(&omega;).
* @return \e x.
**********************************************************************/
Math::real x(real somg, real comg) const {
real somg1 = _b * somg, comg1 = _a * comg; norm(somg1, comg1);
return Math::sq(_a / _b)
* _ex.Pi(somg1, comg1, _ex.Delta(somg1, comg1));
}
/**
* The \e x projection.
*
* @param[in] omg &omega; (in degrees).
* @return \e x (in degrees).
*
* &omega; must be in [&minus;180&deg;, 180&deg;].
**********************************************************************/
Math::real x(real omg) const {
real somg, comg;
Math::sincosd(omg, somg, comg);
return x(somg, comg) / Math::degree();
}
/**
* @return the quadrant length in the \e y direction.
**********************************************************************/
Math::real y() const { return Math::sq(_c / _b) * _ey.Pi(); }
/**
* The \e y projection.
*
* @param[in] sbet sin(&beta;).
* @param[in] cbet cos(&beta;).
* @return \e y.
**********************************************************************/
Math::real y(real sbet, real cbet) const {
real sbet1 = _b * sbet, cbet1 = _c * cbet; norm(sbet1, cbet1);
return Math::sq(_c / _b)
* _ey.Pi(sbet1, cbet1, _ey.Delta(sbet1, cbet1));
}
/**
* The \e y projection.
*
* @param[in] bet &beta; (in degrees).
* @return \e y (in degrees).
*
* &beta; must be in (&minus;180&deg;, 180&deg;].
**********************************************************************/
Math::real y(real bet) const {
real sbet, cbet;
Math::sincosd(bet, sbet, cbet);
return y(sbet, cbet) / Math::degree();
}
};
} // namespace GeographicLib
#endif // GEOGRAPHICLIB_JACOBICONFORMAL_HPP

View File

@@ -0,0 +1,57 @@
#
# Makefile.am
#
# Copyright (C) 2011, Charles Karney <charles@karney.com>
EXAMPLE_FILES = \
example-Accumulator.cpp \
example-AlbersEqualArea.cpp \
example-AzimuthalEquidistant.cpp \
example-CassiniSoldner.cpp \
example-CircularEngine.cpp \
example-Constants.cpp \
example-DMS.cpp \
example-DST.cpp \
example-Ellipsoid.cpp \
example-EllipticFunction.cpp \
example-GARS.cpp \
example-GeoCoords.cpp \
example-Geocentric.cpp \
example-Geodesic.cpp \
example-Geodesic-small.cpp \
example-GeodesicExact.cpp \
example-GeodesicLine.cpp \
example-GeodesicLineExact.cpp \
example-GeographicErr.cpp \
example-Geohash.cpp \
example-Geoid.cpp \
example-Georef.cpp \
example-Gnomonic.cpp \
example-GravityCircle.cpp \
example-GravityModel.cpp \
example-LambertConformalConic.cpp \
example-LocalCartesian.cpp \
example-MGRS.cpp \
example-MagneticCircle.cpp \
example-MagneticModel.cpp \
example-Math.cpp \
example-NearestNeighbor.cpp \
example-NormalGravity.cpp \
example-OSGB.cpp \
example-PolarStereographic.cpp \
example-PolygonArea.cpp \
example-Rhumb.cpp \
example-RhumbLine.cpp \
example-SphericalEngine.cpp \
example-SphericalHarmonic.cpp \
example-SphericalHarmonic1.cpp \
example-SphericalHarmonic2.cpp \
example-TransverseMercator.cpp \
example-TransverseMercatorExact.cpp \
example-UTMUPS.cpp \
example-Utility.cpp \
GeoidToGTX.cpp \
JacobiConformal.cpp JacobiConformal.hpp \
make-egmcof.cpp
EXTRA_DIST = CMakeLists.txt $(EXAMPLE_FILES)

View File

@@ -0,0 +1,24 @@
// Example of using the GeographicLib::Accumulator class
#include <iostream>
#include <exception>
#include <GeographicLib/Accumulator.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
// Compare using Accumulator and ordinary summation for a sum of large and
// small terms.
double sum = 0;
Accumulator<> acc = 0;
sum += 1e20; sum += 1; sum += 2; sum += 100; sum += 5000; sum += -1e20;
acc += 1e20; acc += 1; acc += 2; acc += 100; acc += 5000; acc += -1e20;
cout << sum << " " << acc() << "\n";
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,39 @@
// Example of using the GeographicLib::AlbersEqualArea class
#include <iostream>
#include <exception>
#include <GeographicLib/AlbersEqualArea.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
const double
a = Constants::WGS84_a(),
f = Constants::WGS84_f(),
lat1 = 40 + 58/60.0, lat2 = 39 + 56/60.0, // standard parallels
k1 = 1, // scale
lon0 = -77 - 45/60.0; // Central meridian
// Set up basic projection
const AlbersEqualArea albers(a, f, lat1, lat2, k1);
{
// Sample conversion from geodetic to Albers Equal Area
double lat = 39.95, lon = -75.17; // Philadelphia
double x, y;
albers.Forward(lon0, lat, lon, x, y);
cout << x << " " << y << "\n";
}
{
// Sample conversion from Albers Equal Area grid to geodetic
double x = 220e3, y = -53e3;
double lat, lon;
albers.Reverse(lon0, x, y, lat, lon);
cout << lat << " " << lon << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,37 @@
// Example of using the GeographicLib::AuxLatitude class. See the paper
//
// - C. F. F. Karney,
// On auxiliary latitudes,
// Technical Report, SRI International, December 2022.
// https://arxiv.org/abs/2212.05818
#include <iostream>
#include <iomanip>
#include <exception>
#include "AuxLatitude.hpp"
using namespace std;
int main() {
try {
typedef GeographicLib::AuxLatitude<double> latitude;
typedef latitude::angle angle;
double a = 2, b = 1; // Equatorial radius and polar semi-axis
latitude aux(a, b);
bool series = false; // Don't use series method
int auxin = latitude::GEOGRAPHIC;
cout << setprecision(9) << fixed;
for (int l = 0; l <= 90; ++l) {
angle phi(angle::degrees(l));
for (int auxout = 0; auxout < latitude::AUXNUMBER; ++auxout) {
angle eta = aux.Convert(auxin, auxout, phi, series);
cout << (auxout ? " " : "") << eta.degrees();
}
cout << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,36 @@
// Example of using the GeographicLib::AzimuthalEquidistant class
#include <iostream>
#include <exception>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/AzimuthalEquidistant.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
Geodesic geod(Constants::WGS84_a(), Constants::WGS84_f());
// Alternatively: const Geodesic& geod = Geodesic::WGS84();
const double lat0 = 48 + 50/60.0, lon0 = 2 + 20/60.0; // Paris
AzimuthalEquidistant proj(geod);
{
// Sample forward calculation
double lat = 50.9, lon = 1.8; // Calais
double x, y;
proj.Forward(lat0, lon0, lat, lon, x, y);
cout << x << " " << y << "\n";
}
{
// Sample reverse calculation
double x = -38e3, y = 230e3;
double lat, lon;
proj.Reverse(lat0, lon0, x, y, lat, lon);
cout << lat << " " << lon << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,36 @@
// Example of using the GeographicLib::CassiniSoldner class
#include <iostream>
#include <exception>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/CassiniSoldner.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
Geodesic geod(Constants::WGS84_a(), Constants::WGS84_f());
// Alternatively: const Geodesic& geod = Geodesic::WGS84();
const double lat0 = 48 + 50/60.0, lon0 = 2 + 20/60.0; // Paris
CassiniSoldner proj(lat0, lon0, geod);
{
// Sample forward calculation
double lat = 50.9, lon = 1.8; // Calais
double x, y;
proj.Forward(lat, lon, x, y);
cout << x << " " << y << "\n";
}
{
// Sample reverse calculation
double x = -38e3, y = 230e3;
double lat, lon;
proj.Reverse(x, y, lat, lon);
cout << lat << " " << lon << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,35 @@
// Example of using the GeographicLib::CircularEngine class
#include <iostream>
#include <exception>
#include <vector>
#include <GeographicLib/CircularEngine.hpp>
#include <GeographicLib/SphericalHarmonic.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
// This computes the same value as example-SphericalHarmonic.cpp using a
// CircularEngine (which will be faster if many values on a circle of
// latitude are to be found).
try {
using std::hypot;
int N = 3; // The maxium degree
double ca[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; // cosine coefficients
vector<double> C(ca, ca + (N + 1) * (N + 2) / 2);
double sa[] = {6, 5, 4, 3, 2, 1}; // sine coefficients
vector<double> S(sa, sa + N * (N + 1) / 2);
double a = 1;
SphericalHarmonic h(C, S, N, a);
double x = 2, y = 3, z = 1, p = hypot(x, y);
CircularEngine circ = h.Circle(p, z, true);
double v, vx, vy, vz;
v = circ(x/p, y/p, vx, vy, vz);
cout << v << " " << vx << " " << vy << " " << vz << "\n";
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,20 @@
// Example of using the GeographicLib::Constants class
#include <iostream>
#include <exception>
#include <GeographicLib/Constants.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
cout << "WGS84 parameters:\n"
<< "a = " << Constants::WGS84_a() << " m\n"
<< "f = 1/" << 1/Constants::WGS84_f() << "\n";
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,29 @@
// Example of using the GeographicLib::DMS class
#include <iostream>
#include <string>
#include <exception>
#include <GeographicLib/DMS.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
{
string dms = "30d14'45.6\"S";
DMS::flag type;
double ang = DMS::Decode(dms, type);
cout << type << " " << ang << "\n";
}
{
double ang = -30.245715;
string dms = DMS::Encode(ang, 6, DMS::LATITUDE);
cout << dms << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,62 @@
// Example of using the GeographicLib::DST class
#include <iostream>
#include <exception>
#include <vector>
#include <GeographicLib/Math.hpp>
#include <GeographicLib/DST.hpp>
using namespace std;
using namespace GeographicLib;
class sawtooth {
private:
double _a;
public:
sawtooth(double a) : _a(a) {}
// only called for x in (0, pi/2]. DST assumes function is periodic, period
// 2*pi, is odd about 0, and is even about pi/2.
double operator()(double x) const { return _a * x; }
};
int main() {
try {
sawtooth f(Math::pi()/4);
DST dst;
int N = 5, K = 2*N;
vector<double> tx(N), txa(2*N);
dst.reset(N);
dst.transform(f, tx.data());
cout << "Transform of sawtooth based on " << N << " points\n"
<< "approx 1, -1/9, 1/25, -1/49, ...\n";
for (int i = 0; i < min(K,N); ++i) {
int j = (2*i+1)*(2*i+1)*(1-((i&1)<<1));
cout << i << " " << tx[i] << " " << tx[i]*j << "\n";
}
tx.resize(2*N);
dst.refine(f, tx.data());
cout << "Add another " << N << " points\n";
for (int i = 0; i < min(K,2*N); ++i) {
int j = (2*i+1)*(2*i+1)*(1-((i&1)<<1));
cout << i << " " << tx[i] << " " << tx[i]*j << "\n";
}
dst.reset(2*N);
dst.transform(f, txa.data());
cout << "Retransform of sawtooth based on " << 2*N << " points\n";
for (int i = 0; i < min(K,2*N); ++i) {
int j = (2*i+1)*(2*i+1)*(1-((i&1)<<1));
cout << i << " " << txa[i] << " " << txa[i]*j << "\n";
}
cout << "Table of values and integral\n";
for (int i = 0; i <= K; ++i) {
double x = i*Math::pi()/(2*K), sinx = sin(x), cosx = cos(x);
cout << x << " " << f(x) << " "
<< DST::eval(sinx, cosx, txa.data(), 2*N) << " "
<< DST::integral(sinx, cosx, txa.data(), 2*N) << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,42 @@
// Example of using the GeographicLib::Ellipsoid class
#include <iostream>
#include <iomanip>
#include <exception>
#include <GeographicLib/Ellipsoid.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
Ellipsoid wgs84(Constants::WGS84_a(), Constants::WGS84_f());
// Alternatively: const Ellipsoid& wgs84 = Ellipsoid::WGS84();
cout << "The latitude half way between the equator and the pole is "
<< wgs84.InverseRectifyingLatitude(45) << "\n";
cout << "Half the area of the ellipsoid lies between latitudes +/- "
<< wgs84.InverseAuthalicLatitude(30) << "\n";
cout << "The northernmost edge of a square Mercator map is at latitude "
<< wgs84.InverseIsometricLatitude(180) << "\n";
cout << "Table phi(deg) beta-phi xi-phi mu-phi chi-phi theta-phi (mins)\n"
<< fixed << setprecision(2);
for (int i = 0; i <= 90; i += 15) {
double phi = i,
bet = wgs84.ParametricLatitude(phi),
xi = wgs84.AuthalicLatitude(phi),
mu = wgs84.RectifyingLatitude(phi),
chi = wgs84.ConformalLatitude(phi),
theta = wgs84.GeocentricLatitude(phi);
cout << i << " "
<< (bet-phi)*60 << " "
<< (xi-phi)*60 << " "
<< (mu-phi)*60 << " "
<< (chi-phi)*60 << " "
<< (theta-phi)*60 << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,43 @@
// Example of using the GeographicLib::EllipticFunction class
#include <iostream>
#include <iomanip>
#include <exception>
#include <cmath>
#include <GeographicLib/Math.hpp>
#include <GeographicLib/EllipticFunction.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
EllipticFunction ell(0.1); // parameter m = 0.1
// See Abramowitz and Stegun, table 17.1
cout << ell.K() << " " << ell.E() << "\n";
double phi = 20, sn, cn;
Math::sincosd(phi, sn ,cn);
// See Abramowitz and Stegun, table 17.6 with
// alpha = asin(sqrt(m)) = 18.43 deg and phi = 20 deg
cout << ell.E(phi * Math::degree()) << " "
<< ell.E(sn, cn, ell.Delta(sn, cn))
<< "\n";
// See Carlson 1995, Sec 3.
cout << fixed << setprecision(16)
<< "RF(1,2,0) = " << EllipticFunction::RF(1,2) << "\n"
<< "RF(2,3,4) = " << EllipticFunction::RF(2,3,4) << "\n"
<< "RC(0,1/4) = " << EllipticFunction::RC(0,0.25) << "\n"
<< "RC(9/4,2) = " << EllipticFunction::RC(2.25,2) << "\n"
<< "RC(1/4,-2) = " << EllipticFunction::RC(0.25,-2) << "\n"
<< "RJ(0,1,2,3) = " << EllipticFunction::RJ(0,1,2,3) << "\n"
<< "RJ(2,3,4,5) = " << EllipticFunction::RJ(2,3,4,5) << "\n"
<< "RD(0,2,1) = " << EllipticFunction::RD(0,2,1) << "\n"
<< "RD(2,3,4) = " << EllipticFunction::RD(2,3,4) << "\n"
<< "RG(0,16,16) = " << EllipticFunction::RG(16,16) << "\n"
<< "RG(2,3,4) = " << EllipticFunction::RG(2,3,4) << "\n"
<< "RG(0,0.0796,4) = " << EllipticFunction::RG(0.0796,4) << "\n";
}
catch (const exception& e) {
cout << "Caught exception: " << e.what() << "\n";
}
}

View File

@@ -0,0 +1,39 @@
// Example of using the GeographicLib::GARS class
#include <iostream>
#include <iomanip>
#include <exception>
#include <string>
#include <GeographicLib/GARS.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
{
// Sample forward calculation
double lat = 57.64911, lon = 10.40744; // Jutland
string gars;
for (int prec = 0; prec <= 2; ++prec) {
GARS::Forward(lat, lon, prec, gars);
cout << prec << " " << gars << "\n";
}
}
{
// Sample reverse calculation
string gars = "381NH45";
double lat, lon;
cout << fixed;
for (int len = 5; len <= int(gars.size()); ++len) {
int prec;
GARS::Reverse(gars.substr(0, len), lat, lon, prec);
cout << prec << " " << lat << " " << lon << "\n";
}
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,26 @@
// Example of using the GeographicLib::GeoCoords class
#include <iostream>
#include <exception>
#include <GeographicLib/GeoCoords.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
// Miscellaneous conversions
double lat = 33.3, lon = 44.4;
GeoCoords c(lat, lon);
cout << c.MGRSRepresentation(-3) << "\n";
c.Reset("18TWN0050");
cout << c.DMSRepresentation() << "\n";
cout << c.Latitude() << " " << c.Longitude() << "\n";
c.Reset("1d38'W 55d30'N");
cout << c.GeoRepresentation() << "\n";
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,36 @@
// Example of using the GeographicLib::Geocentric class
#include <iostream>
#include <exception>
#include <cmath>
#include <GeographicLib/Geocentric.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
Geocentric earth(Constants::WGS84_a(), Constants::WGS84_f());
// Alternatively: const Geocentric& earth = Geocentric::WGS84();
{
// Sample forward calculation
double lat = 27.99, lon = 86.93, h = 8820; // Mt Everest
double X, Y, Z;
earth.Forward(lat, lon, h, X, Y, Z);
cout << floor(X / 1000 + 0.5) << " "
<< floor(Y / 1000 + 0.5) << " "
<< floor(Z / 1000 + 0.5) << "\n";
}
{
// Sample reverse calculation
double X = 302e3, Y = 5636e3, Z = 2980e3;
double lat, lon, h;
earth.Reverse(X, Y, Z, lat, lon, h);
cout << lat << " " << lon << " " << h << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,18 @@
// Small example of using the GeographicLib::Geodesic class
#include <iostream>
#include <GeographicLib/Geodesic.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
const Geodesic& geod = Geodesic::WGS84();
// Distance from JFK to LHR
double
lat1 = 40.6, lon1 = -73.8, // JFK Airport
lat2 = 51.6, lon2 = -0.5; // LHR Airport
double s12;
geod.Inverse(lat1, lon1, lat2, lon2, s12);
cout << s12 / 1000 << " km\n";
}

View File

@@ -0,0 +1,36 @@
// Example of using the GeographicLib::Geodesic class
#include <iostream>
#include <exception>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/Constants.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
Geodesic geod(Constants::WGS84_a(), Constants::WGS84_f());
// Alternatively: const Geodesic& geod = Geodesic::WGS84();
{
// Sample direct calculation, travelling about NE from JFK
double lat1 = 40.6, lon1 = -73.8, s12 = 5.5e6, azi1 = 51;
double lat2, lon2;
geod.Direct(lat1, lon1, azi1, s12, lat2, lon2);
cout << lat2 << " " << lon2 << "\n";
}
{
// Sample inverse calculation, JFK to LHR
double
lat1 = 40.6, lon1 = -73.8, // JFK Airport
lat2 = 51.6, lon2 = -0.5; // LHR Airport
double s12;
geod.Inverse(lat1, lon1, lat2, lon2, s12);
cout << s12 << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

View File

@@ -0,0 +1,36 @@
// Example of using the GeographicLib::GeodesicExact class
#include <iostream>
#include <exception>
#include <GeographicLib/GeodesicExact.hpp>
#include <GeographicLib/Constants.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
try {
GeodesicExact geod(Constants::WGS84_a(), Constants::WGS84_f());
// Alternatively: const GeodesicExact& geod = GeodesicExact::WGS84();
{
// Sample direct calculation, travelling about NE from JFK
double lat1 = 40.6, lon1 = -73.8, s12 = 5.5e6, azi1 = 51;
double lat2, lon2;
geod.Direct(lat1, lon1, azi1, s12, lat2, lon2);
cout << lat2 << " " << lon2 << "\n";
}
{
// Sample inverse calculation, JFK to LHR
double
lat1 = 40.6, lon1 = -73.8, // JFK Airport
lat2 = 51.6, lon2 = -0.5; // LHR Airport
double s12;
geod.Inverse(lat1, lon1, lat2, lon2, s12);
cout << s12 << "\n";
}
}
catch (const exception& e) {
cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
}

Some files were not shown because too many files have changed in this diff Show More