GeographicLib-1.49/cmake/Makefile.in0000644000771000077100000003164413165402536017166 0ustar ckarneyckarney# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Makefile.am # # Copyright (C) 2011, Charles Karney VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = cmake ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/GeographicLib/Config-ac.h CONFIG_CLEAN_FILES = geographiclib.pc CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/project.pc.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COL = @COL@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GEOGRAPHICLIB_VERSION_MAJOR = @GEOGRAPHICLIB_VERSION_MAJOR@ GEOGRAPHICLIB_VERSION_MINOR = @GEOGRAPHICLIB_VERSION_MINOR@ GEOGRAPHICLIB_VERSION_PATCH = @GEOGRAPHICLIB_VERSION_PATCH@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_AGE = @LT_AGE@ LT_CURRENT = @LT_CURRENT@ LT_REVISION = @LT_REVISION@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POD2HTML = @POD2HTML@ POD2MAN = @POD2MAN@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ cmakedir = $(datadir)/cmake/GeographicLib EXTRA_DIST = Makefile.mk CMakeLists.txt FindGeographicLib.cmake \ project-config-version.cmake.in project-config.cmake.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu cmake/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu cmake/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): geographiclib.pc: $(top_builddir)/config.status $(srcdir)/project.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile install: $(INSTALL) -d $(DESTDIR)$(cmakedir) $(INSTALL) -m 644 $(srcdir)/FindGeographicLib.cmake \ $(DESTDIR)$(cmakedir) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: GeographicLib-1.49/cmake/project-config.cmake.in0000644000771000077100000001103413165402513021423 0ustar ckarneyckarney# Configure @PROJECT_NAME@ # # Set # @PROJECT_NAME@_FOUND = @PROJECT_NAME_UPPER@_FOUND = 1 # @PROJECT_NAME@_INCLUDE_DIRS = /usr/local/include # @PROJECT_NAME@_SHARED_LIBRARIES = GeographicLib (or empty) # @PROJECT_NAME@_STATIC_LIBRARIES = GeographicLib_STATIC (or empty) # @PROJECT_NAME@_SHARED_DEFINITIONS = GEOGRAPHICLIB_SHARED_LIB=1 # @PROJECT_NAME@_STATIC_DEFINITIONS = GEOGRAPHICLIB_SHARED_LIB=0 # @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 # @PROJECT_NAME@_DEFINITIONS = ${@PROJECT_NAME@_SHARED_DEFINITIONS}, if OFF # @PROJECT_NAME@_DEFINITIONS = ${@PROJECT_NAME@_STATIC_DEFINITIONS}, if ON # If only one of the libraries is provided, then # @PROJECT_NAME@_USE_STATIC_LIBS is ignored. # # For cmake 2.8.11 or later, there's no need to include # include_directories (${GeographicLib_INCLUDE_DIRS}) # add_definitions (${GeographicLib_DEFINITIONS}) # # 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 @PROJECT_SHARED_LIBRARIES@) set (@PROJECT_NAME@_STATIC_LIBRARIES @PROJECT_STATIC_LIBRARIES@) set (@PROJECT_NAME@_SHARED_DEFINITIONS @PROJECT_SHARED_DEFINITIONS@) set (@PROJECT_NAME@_STATIC_DEFINITIONS @PROJECT_STATIC_DEFINITIONS@) # Read in the exported definition of the library include ("${_DIR}/@PROJECT_NAME_LOWER@-targets.cmake") include ("${_DIR}/@PROJECT_NAME_LOWER@-namespace-targets.cmake") 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}) set (@PROJECT_NAME@_DEFINITIONS ${@PROJECT_NAME@_STATIC_DEFINITIONS}) message (STATUS " \${@PROJECT_NAME@_LIBRARIES} set to static library") else () set (@PROJECT_NAME@_LIBRARIES ${@PROJECT_NAME@_SHARED_LIBRARIES}) set (@PROJECT_NAME@_DEFINITIONS ${@PROJECT_NAME@_SHARED_DEFINITIONS}) message (STATUS " \${@PROJECT_NAME@_LIBRARIES} set to shared library") endif () set (@PROJECT_NAME@_NETGeographicLib_LIBRARIES @NETGEOGRAPHICLIB_LIBRARIES@) # Check for the components requested. This only supports components # STATIC, SHARED, and NETGeographicLib 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 1) message (STATUS "@PROJECT_NAME@ component ${comp} found") else () set (@PROJECT_NAME@_${comp}_FOUND 0) message (WARNING "@PROJECT_NAME@ component ${comp} not found") endif () endforeach () endif () # @PROJECT_NAME@_FOUND is set to 1 automatically set (@PROJECT_NAME_UPPER@_FOUND 1) # for backwards compatibility GeographicLib-1.49/cmake/Makefile.mk0000644000771000077100000000032013165402513017145 0ustar ckarneyckarneyDEST = $(PREFIX)/share/cmake/GeographicLib INSTALL=install -b all: @: install: test -d $(DEST) || mkdir -p $(DEST) $(INSTALL) -m 644 FindGeographicLib.cmake $(DEST) clean: @: .PHONY: all install clean GeographicLib-1.49/cmake/Makefile.am0000644000771000077100000000055713165402513017147 0ustar ckarneyckarney# # Makefile.am # # Copyright (C) 2011, Charles Karney cmakedir=$(datadir)/cmake/GeographicLib install: $(INSTALL) -d $(DESTDIR)$(cmakedir) $(INSTALL) -m 644 $(srcdir)/FindGeographicLib.cmake \ $(DESTDIR)$(cmakedir) EXTRA_DIST = Makefile.mk CMakeLists.txt FindGeographicLib.cmake \ project-config-version.cmake.in project-config.cmake.in GeographicLib-1.49/cmake/project.pc.in0000644000771000077100000000046113165402513017504 0ustar ckarneyckarneyprefix=@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} -lGeographic Cflags: -I${includedir} GeographicLib-1.49/cmake/project-config-version.cmake.in0000644000771000077100000000557413165402513023122 0ustar ckarneyckarney# 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@") 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., _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 MSVC_VERSION STREQUAL "@MSVC_VERSION@") # Reject if there's a mismatch in MSVC compiler versions set (REASON "_MSC_VER = @MSVC_VERSION@") set (PACKAGE_VERSION_UNSUITABLE TRUE) elseif (NOT CMAKE_CROSSCOMPILING STREQUAL "@CMAKE_CROSSCOMPILING@") # 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@) set (@PROJECT_NAME@_NETGeographicLib_FOUND @BUILD_NETGEOGRAPHICLIB@) # 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 () GeographicLib-1.49/cmake/CMakeLists.txt0000644000771000077100000000651013165402513017646 0ustar ckarneyckarney# 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.) # 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") 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_SHARED_LIBRARIES} ${PROJECT_STATIC_LIBRARIES} ${TOOLS} FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME_LOWER}-targets.cmake") export (TARGETS ${PROJECT_SHARED_LIBRARIES} ${PROJECT_STATIC_LIBRARIES} ${TOOLS} NAMESPACE ${PROJECT_NAME}:: FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME_LOWER}-namespace-targets.cmake") # geographiclib-config.cmake for the install tree. It's installed in # ${INSTALL_CMAKE_DIR} and @PROJECT_ROOT_DIR@ is the relative # path to the root from there. (Note that the whole install tree can # be relocated.) if (COMMON_INSTALL_PATH) # Install under lib${LIB_SUFFIX} so that 32-bit and 64-bit packages # can be installed on a single machine. set (INSTALL_CMAKE_DIR "lib${LIB_SUFFIX}/cmake/${PROJECT_NAME}") set (PROJECT_ROOT_DIR "../../..") else () set (INSTALL_CMAKE_DIR "cmake") set (PROJECT_ROOT_DIR "..") endif () # @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 "${INSTALL_CMAKE_DIR}" RENAME "${PROJECT_NAME_LOWER}-config.cmake") install (FILES "${CMAKE_CURRENT_BINARY_DIR}/project-config-version.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" RENAME "${PROJECT_NAME_LOWER}-config-version.cmake") # Make information about the cmake targets (the library and the tools) # available. install (EXPORT targets FILE ${PROJECT_NAME_LOWER}-targets.cmake DESTINATION "${INSTALL_CMAKE_DIR}") install (EXPORT targets NAMESPACE ${PROJECT_NAME}:: FILE ${PROJECT_NAME_LOWER}-namespace-targets.cmake DESTINATION "${INSTALL_CMAKE_DIR}") if (MSVC AND PACKAGE_DEBUG_LIBS) install (FILES "${PROJECT_BINARY_DIR}/cmake/CMakeFiles/Export/cmake/${PROJECT_NAME_LOWER}-targets-debug.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" CONFIGURATIONS Release) endif () # Support for pkgconfig/geographiclib.pc set (prefix ${CMAKE_INSTALL_PREFIX}) set (exec_prefix "\${prefix}") set (libdir "\${exec_prefix}/lib${LIB_SUFFIX}") set (includedir "\${prefix}/include") set (bindir "\${exec_prefix}/bin") set (PACKAGE_NAME "${PROJECT_NAME}") set (PACKAGE_VERSION "${PROJECT_VERSION}") configure_file (project.pc.in geographiclib.pc @ONLY) install (FILES "${CMAKE_CURRENT_BINARY_DIR}/geographiclib.pc" DESTINATION "lib${LIB_SUFFIX}/pkgconfig") GeographicLib-1.49/cmake/FindGeographicLib.cmake0000644000771000077100000000313413165402513021407 0ustar ckarneyckarney# Look for GeographicLib # # Set # GeographicLib_FOUND = GEOGRAPHICLIB_FOUND = TRUE # GeographicLib_INCLUDE_DIRS = /usr/local/include # GeographicLib_LIBRARIES = /usr/local/lib/libGeographic.so # GeographicLib_LIBRARY_DIRS = /usr/local/lib find_library (GeographicLib_LIBRARIES Geographic 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/libGeographic.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 () 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) GeographicLib-1.49/maxima/rhumbarea.mac0000644000771000077100000001542213165402514017735 0ustar ckarneyckarney/* Compute the series expansion for the rhumb area. Copyright (c) Charles Karney (2014) and licensed under the MIT/X11 License. For more information, see https://geographiclib.sourceforge.io/ Instructions: edit the value of maxpow near the end of this file. Then load the file into maxima. Area of rhumb quad dA = c^2 sin(xi) * dlambda c = authalic radius xi = authalic latitude Express sin(xi) in terms of chi and expand for small n this can be written in terms of powers of sin(chi) Subst sin(chi) = tanh(psi) = tanh(m*lambda) Integrate over lambda to give A = c^2 * S(chi)/m S(chi) = log(sec(chi)) + sum(R[i]*cos(2*i*chi),i,0,maxpow) R[0] = + 1/3 * n - 16/45 * n^2 + 131/945 * n^3 + 691/56700 * n^4 R[1] = - 1/3 * n + 22/45 * n^2 - 356/945 * n^3 + 1772/14175 * n^4; R[2] = - 2/15 * n^2 + 106/315 * n^3 - 1747/4725 * n^4; R[3] = - 31/315 * n^3 + 104/315 * n^4; R[4] = - 41/420 * n^4; i=0 term is just the integration const so can be dropped. However including this terms gives S(0) = 0. Evaluate A between limits lam1 and lam2 gives A = c^2 * (lam2 - lam1) * (S(chi2) - S(chi1)) / (atanh(sin(chi2)) - atanh(sin(chi1))) In limit chi2 -> chi, chi1 -> chi diff(atanh(sin(chi)),chi) = sec(chi) diff(log(sec(chi)),chi) = tan(chi) c^2 * (lam2 - lam1) * [ (1-R[1]) * sin(chi) - (R[1]+2*R[2]) * sin(3*chi) - (2*R[2]+3*R[3]) * sin(5*chi) - (3*R[3]+4*R[4]) * sin(7*chi) ... ] which is expansion of c^2 * (lam2 - lam1) * sin(xi) in terms of sin(chi) Note: limit chi->0 = 0 limit chi->pi/2 = c^2 * (lam2-lam1) Express in terms of psi A = c^2 * (lam2 - lam1) * (S(chi(psi2)) - S(chi(psi2))) / (psi2 - psi1) sum(R[i]*cos(2*i*chi),i,0,maxpow) = sum(sin(chi),cos(chi)) S(chi(psi)) = log(cosh(psi)) + sum(tanh(psi),sech(psi)) (S(chi(psi2)) - S(chi(psi2))) / (psi2 - psi1) = Dlog(cosh(psi1),cosh(psi2)) * Dcosh(psi1,psi2) + Dsum(chi1,chi2) * Dgd(psi1,psi2) */ reverta(expr,var1,var2,eps,pow):=block([tauacc:1,sigacc:0,dsig], dsig:ratdisrep(taylor(expr-var1,eps,0,pow)), dsig:subst([var1=var2],dsig), for n:1 thru pow do (tauacc:trigreduce(ratdisrep(taylor( -dsig*tauacc/n,eps,0,pow))), sigacc:sigacc+expand(diff(tauacc,var2,n-1))), var2+sigacc)$ /* chi in terms of phi -- from auxlat.mac*/ chi_phi(maxpow):=block([psiv,tanchi,chiv,qq,e,atanexp,x,eps], /* Here qq = atanh(sin(phi)) = asinh(tan(phi)) */ psiv:qq-e*atanh(e*tanh(qq)), psiv:subst([e=sqrt(4*n/(1+n)^2),qq=atanh(sin(phi))], ratdisrep(taylor(psiv,e,0,2*maxpow))) +asinh(sin(phi)/cos(phi))-atanh(sin(phi)), tanchi:subst([abs(cos(phi))=cos(phi),sqrt(sin(phi)^2+cos(phi)^2)=1], ratdisrep(taylor(sinh(psiv),n,0,maxpow)))+tan(phi)-sin(phi)/cos(phi), atanexp:ratdisrep(taylor(atan(x+eps),eps,0,maxpow)), chiv:subst([x=tan(phi),eps=tanchi-tan(phi)],atanexp), chiv:subst([atan(tan(phi))=phi, tan(phi)=sin(phi)/cos(phi)], (chiv-phi)/cos(phi))*cos(phi)+phi, chiv:ratdisrep(taylor(chiv,n,0,maxpow)), expand(trigreduce(chiv)))$ /* phi in terms of chi -- from auxlat.mac */ phi_chi(maxpow):=reverta(chi_phi(maxpow),phi,chi,n,maxpow)$ /* xi in terms of phi */ xi_phi(maxpow):=block([sinxi,asinexp,x,eps,v], sinxi:(sin(phi)/2*(1/(1-e^2*sin(phi)^2) + atanh(e*sin(phi))/(e*sin(phi))))/ (1/2*(1/(1-e^2) + atanh(e)/e)), sinxi:ratdisrep(taylor(sinxi,e,0,2*maxpow)), sinxi:subst([e=2*sqrt(n)/(1+n)],sinxi), sinxi:expand(trigreduce(ratdisrep(taylor(sinxi,n,0,maxpow)))), asinexp:sqrt(1-x^2)* sum(ratsimp(diff(asin(x),x,i)/i!/sqrt(1-x^2))*eps^i,i,0,maxpow), v:subst([x=sin(phi),eps=sinxi-sin(phi)],asinexp), v:taylor(subst([sqrt(1-sin(phi)^2)=cos(phi),asin(sin(phi))=phi], v),n,0,maxpow), v:expand(ratdisrep(coeff(v,n,0))+sum( ratsimp(trigreduce(sin(phi)*ratsimp( subst([sin(phi)=sqrt(1-cos(phi)^2)], ratsimp(trigexpand(ratdisrep(coeff(v,n,i)))/sin(phi)))))) *n^i, i,1,maxpow)))$ xi_chi(maxpow):= expand(trigreduce(taylor(subst([phi=phi_chi(maxpow)],xi_phi(maxpow)), n,0,maxpow)))$ computeR(maxpow):=block([xichi,xxn,inttanh,yy,m,yyi,yyj,s], local(inttanh), xichi:xi_chi(maxpow), xxn:expand(subst([cos(chi)=sqrt(1-sin(chi)^2)], trigexpand(taylor(sin(xichi),n,0,maxpow)))), /* integrals of tanh(x)^l. Use tanh(x)^2 + sech(x)^2 = 1. */ inttanh[0](x):=x, /* Not needed -- only odd l occurs in this problem */ inttanh[1](x):=log(cosh(x)), inttanh[l](x):=inttanh[l-2](x) - tanh(x)^(l-1)/(l-1), yy:subst([sin(chi)=tanh(m*lambda)],xxn), /* psi = atanh(sin(chi)) = m*lambda sin(chi)=tanh(m*lambda) sech(m*lambda) = sqrt(1-tanh(m*lambda))^2 = cos(chi) cosh(m*lambda) = sec(chi) m=(atanh(sin(chi2))-atanh(sin(chi1)))/(lam2-lam1) */ yyi:block([v:yy/m,ii], local(ii), for j:2*maxpow+1 step -2 thru 1 do v:subst([tanh(m*lambda)^j=ii[j](m*lambda)],v), for j:2*maxpow+1 step -2 thru 1 do v:subst([ii[j](m*lambda)=inttanh[j](m*lambda)],v), expand(v)), yyj:expand(m*trigreduce( subst([tanh(m*lambda)=sin(chi),cosh(m*lambda)=sec(chi)],yyi)))/ ( (atanh(sin(chi2))-atanh(sin(chi1)))/(lam2-lam1) ), s:( (atanh(sin(chi2))-atanh(sin(chi1)))/(lam2-lam1) )*yyj-log(sec(chi)), for i:1 thru maxpow do R[i]:coeff(s,cos(2*i*chi)), R[0]:s-expand(sum(R[i]*cos(2*i*chi),i,1,maxpow)), if expand(s-sum(R[i]*cos(2*i*chi),i,0,maxpow)) # 0 then error("Left over terms in R"), if expand(trigreduce(expand( diff(sum(R[i]*cos(2*i*chi),i,0,maxpow),chi)*cos(chi)+sin(chi))))- expand(trigreduce(expand(xxn))) # 0 then error("Derivative error in R"), 'done)$ ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$ dispR(ord):=for i:1 thru ord do block([tt:ataylor(R[i],n,ord),ttt,linel:1200], print(), for j:max(i,1) step 1 thru ord do (ttt:coeff(tt,n,j), print(concat( if j = max(i,1) then concat("R[",string(i),"] = ") else " ", if ttt<0 then "- " else "+ ", string(abs(ttt)), " * ", string(n^j), if j=ord then ";" else ""))))$ codeR(minpow,maxpow):=block([tab2:" ",tab3:" "], print(" // The coefficients R[l] in the Fourier expansion of rhumb area real nx = n; switch (maxpow_) {"), for k:minpow thru maxpow do ( print(concat(tab2,"case ",string(k),":")), for m:1 thru k do block([q:nx*horner( ataylor(R[m],n,k)/n^m), linel:1200], if m>1 then print(concat(tab3,"nx *= n;")), print(concat(tab3,"c[",string(m),"] = ",string(q),";"))), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(maxpow_ >= ",string(minpow), " && maxpow_ <= ",string(maxpow),", \"Bad value of maxpow_\");")), print(" }"), 'done)$ maxpow:8$ computeR(maxpow)$ dispR(maxpow)$ /* codeR(4,maxpow)$ */ load("polyprint.mac")$ printrhumb():=block([macro:GEOGRAPHICLIB_RHUMBAREA_ORDER], array1('R,'n,1,0))$ printrhumb()$ GeographicLib-1.49/maxima/tm.mac0000644000771000077100000003066313165402514016413 0ustar ckarneyckarney/* Arbitrary precision Transverse Mercator Projection Copyright (c) Charles Karney (2009-2017) and licensed under the MIT/X11 License. For more information, see https://geographiclib.sourceforge.io/ Reference: Charles F. F. Karney, Transverse Mercator with an accuracy of a few nanometers, J. Geodesy 85(8), 475-485 (Aug. 2011). DOI 10.1007/s00190-011-0445-3 preprint https://arxiv.org/abs/1002.1417 resource page https://geographiclib.sourceforge.io/tm.html The parameters for the transformation are set by setparams(a,f,k0)$ sets the equatorial radius, inverse flattening, and central scale factor. The default is setparams(6378137b0, 1/298.257223563b0, 0.9996b0)$ appropriate for UTM applications. tm(lat,lon); takes lat and lon args (in degrees) and returns [x, y, convergence, scale] [x, y] do not include false eastings/northings but do include the scale factor k0. convergence is in degrees. ll(x,y); takes x and y args (in meters) and returns [lat, lon, convergence, scale]. Example: $ maxima Maxima 5.15.0 http://maxima.sourceforge.net Using Lisp CLISP 2.43 (2007-11-18) Distributed under the GNU Public License. See the file COPYING. Dedicated to the memory of William Schelter. The function bug_report() provides bug reporting information. (%i1) load("tm.mac")$ (%i2) tm(10b0,20b0); (%o2) [2.235209504622466691587930831718465965864199221939781808953597771095103\ 6690000464b6, 1.17529734503138466792126931904154130080533935727351398258511134\ 68541970512119385b6, 3.6194756227592979778565787394402350354250845160819430786\ 093514889500602612857052b0, 1.062074627142564335518604915718789933200854739344\ 8664109599248189291146283796933b0] (%i3) ll(%[1],%[2]); (%o3) [1.0b1, 2.0b1, 3.6194756227592979778565787394402350354250845160819430786\ 093514889500602612857053b0, 1.062074627142564335518604915718789933200854739344\ 8664109599248189291146283796933b0] (%i4) float(%o2); (%o4) [2235209.504622467, 1175297.345031385, 3.619475622759298, 1.062074627142564] (%i5) float(%o3); (%o5) [10.0, 20.0, 3.619475622759298, 1.062074627142564] This implements GeographicLib::TransverseMercatorExact (i.e., Lee, 1976) using bfloats. However fewer changes from Lee 1976 have been made since we rely more heavily on the high precision to deal with problem cases. To change the precision, change fpprec below and reload. */ fpprec:80$ load("ellint.mac")$ /* Load elliptic functions */ tol:0.1b0^fpprec$ tol1:0.1b0*sqrt(tol)$ /* For Newton's method */ tol2:sqrt(0.01*tol*tol1)$ /* Also for Newton's method but more conservative */ ahypover:log(10b0^fpprec)+2$ pi:bfloat(%pi)$ degree:pi/180$ ratprint:false$ debugprint:false$ setparams(a1,f1,k1):=(a:bfloat(a1),f:bfloat(f1),k0:bfloat(k1), e2:f*(2-f), e:sqrt(e2), kcu:kc(e2), kcv:kc(1-e2), ecu:ec(e2), ecv:ec(1-e2), n:f/(2-f), 'done)$ setparams(6378137b0, 1/298.257223563b0, 0.9996b0)$ /* WGS 84 */ /* setparams(6378388b0, 1/297b0, 0.9996b0)$ International */ /* setparams(1/ec(0.01b0), 1/(30*sqrt(11b0)+100), 1b0)$ testing, eps = 0.1*/ /* Interpret x_y(y) as x <- y, i.e., "transform quantity y to quantity x" Let phi = geodetic latitude psi = isometric latitude ( + i * lambda ) sigma = TM coords thom = Thompson coords */ /* sqrt(x^2 + y^2) -- Real only */ hypot(x,y):=sqrt(x^2 + y^2)$ /* log(1 + x) -- Real only */ log1p(x) := block([y : 1b0+x], if y = 1b0 then x else x*log(y)/(y - 1))$ /* Real only */ /* Some versions of Maxima have a buggy atanh atnh(x) := block([y : abs(x)], y : log1p(2 * y/(1 - y))/2, if x < 0 then -y else y)$ */ atnh(x) := atanh(x)$ /* exp(x)-1 -- Real only */ expm1(x) := block([y : exp(bfloat(x)),z], z : y - 1b0, if abs(x) > 1b0 then z else if z = 0b0 then x else x * z/log(y))$ /* Real only */ /* Some versions of Maxima have a buggy sinh */ snh(x) := block([u : expm1(x)], (u / (u + 1)) * (u + 2) /2); /* Real only */ psi_phi(phi):=block([s:sin(phi)], asinh(s/max(cos(phi),0.1b0*tol)) - e * atnh(e * s))$ /* Real only */ phi_psi(psi):=block([q:psi,t,dq], for i do ( t:tanh(q), dq : -(q - e * atnh(e * t) - psi) * (1 - e2 * t^2) / (1 - e2), q : q + dq, if debugprint then print(float(q), float(dq)), if abs(dq) < tol1 then return(false)), atan(snh(q)))$ psi_thom_comb(w):=block([jacr:sncndn(bfloat(realpart(w)),1-e2), jaci:sncndn(bfloat(imagpart(w)),e2),d,d1,d2], d:(1-e2)*(jaci[2]^2 + e2 * (jacr[1] * jaci[1])^2)^2, d1:sqrt(jacr[2]^2 + (1-e2) * (jacr[1] * jaci[1])^2), d2:sqrt(e2 * jacr[2]^2 + (1-e2) * jaci[2]^2), [ (if d1 > 0b0 then asinh(jacr[1]*jaci[3]/ d1) else signnum(snu) * ahypover) - (if d2 > 0b0 then e * asinh(e * jacr[1] / d2) else signnum(snu) * ahypover) + %i * (if d1 > 0b0 and d2 > 0b0 then atan2(jacr[3]*jaci[1],jacr[2]*jaci[2]) - e * atan2(e*jacr[2]*jaci[1],jacr[3]*jaci[2]) else 0), jacr[2]*jacr[3]*jaci[3]*(jaci[2]^2-e2*(jacr[1]*jaci[1])^2)/d -%i * jacr[1]*jaci[1]*jaci[2]*((jacr[3]*jaci[3])^2+e2*jacr[2]^2)/d] )$ psi_thom(w):=block([tt:psi_thom_comb(w)],tt[1])$ inv_diff_psi_thom(w):=block([tt:psi_thom_comb(w)],tt[2])$ w0a(psi):=block([lam:bfloat(imagpart(psi)),psia:bfloat(realpart(psi))], rectform(kcu/(pi/2)*( atan2(snh(psia),cos(lam)) +%i*asinh(sin(lam)/sqrt(cos(lam)^2 + snh(psia)^2)))))$ w0c(psi):=block([m,a,dlam], dlam:bfloat(imagpart(psi))-pi/2*(1-e), psi:bfloat(realpart(psi)), m:sqrt(psi^2+dlam^2)*3/(1-e2)/e, a:if m = 0b0 then 0 else atan2(dlam-psi, psi+dlam) - 0.75b0*pi, m:m^(1/3), a:a/3, m*cos(a)+%i*(m*sin(a)+kcv))$ w0d(psi):=block([psir:-realpart(psi)/e+1b0,lam:(pi/2-imagpart(psi))/e,uu,vv], uu:asinh(sin(lam)/sqrt(cos(lam)^2+snh(psir)^2))*(1+e2/2), vv:atan2(cos(lam), snh(psir)) *(1+e2/2), (-uu+kcu) + %i * (-vv+kcv))$ w0m(psi):=if realpart(psi)<-e/2*pi/2 and imagpart(psi)>pi/2*(1-2*e) and realpart(psi) < imagpart(psi)-(pi/2*(1-e)) then w0d(psi) else if realpart(psi)pi/2*(1-2*e) then w0c(psi) else w0a(psi)$ w0(psi):=w0m(psi)$ thom_psi(psi):=block([w:w0(psi),dw,v,vv], if not(abs(psi-pi/2*(1-e)*%i) < e * tol^0.6b0) then for i do ( if i > 100 then error("too many iterations"), vv:psi_thom_comb(w), v:vv[1], dw:-rectform((v-psi)*vv[2]), w:w+dw, dw:abs(dw), if debugprint then print(float(w),float(dw)), /* error is approx dw^2/2 */ if dw < tol2 then return(false) ), w )$ sigma_thom_comb(w):=block([u:bfloat(realpart(w)),v:bfloat(imagpart(w)), jacr,jaci,phi,iu,iv,den,den1,er,ei,dnr,dni], jacr:sncndn(u,1-e2),jaci:sncndn(v,e2), er:eirx(jacr[1],jacr[2],jacr[3],e2,ecu), ei:eirx(jaci[1],jaci[2],jaci[3],1-e2,ecv), den:e2*jacr[2]^2+(1-e2)*jaci[2]^2, den1:(1-e2)*(jaci[2]^2 + e2 * (jacr[1] * jaci[1])^2)^2, dnr:jacr[3]*jaci[2]*jaci[3], dni:-e2*jacr[1]*jacr[2]*jaci[1], [ er - e2*jacr[1]*jacr[2]*jacr[3]/den + %i*(v - ei + (1-e2)*jaci[1]*jaci[2]*jaci[3]/den), (dnr^2-dni^2)/den1 + %i * 2*dnr*dni/den1])$ sigma_thom(w):=block([tt:sigma_thom_comb(w)],tt[1])$ inv_diff_sigma_thom(w):=block([tt:sigma_thom_comb(w)],tt[2])$ wx0a(sigma):=rectform(sigma*kcu/ecu)$ wx0b(sigma):=block([m,aa], sigma:rectform(sigma-%i*(kcv-ecv)), m:abs(sigma)*3/(1-e2), aa:atan2(imagpart(sigma),realpart(sigma)), if aa<-pi/2 then aa:aa+2*pi, aa:aa-pi, rectform(m^(1/3)*(cos(aa/3b0)+%i*sin(aa/3b0))+%i*kcv))$ wx0c(sigma):=rectform(1/(sigma-(ecu+%i*(kcv-ecv))) + kcu+%i*kcv)$ wx0m(sigma):=block([eta:bfloat(imagpart(sigma)), xi:bfloat(realpart(sigma))], if eta > 1.25b0 * (kcv-ecv) or (xi < -0.25*ecu and xi < eta-(kcv-ecv)) then wx0c(sigma) else if (eta > 0.75b0 * (kcv-ecv) and xi < 0.25b0 * ecu) or eta > kcv-ecv or xi < 0 then wx0b(sigma) else wx0a(sigma))$ wx0(sigma):=wx0m(sigma)$ thom_sigma(sigma):=block([w:wx0(sigma),dw,v,vv], for i do ( if i > 100 then error("too many iterations"), vv:sigma_thom_comb(w), v:vv[1], dw:-rectform((v-sigma)*vv[2]), w:w+dw, dw:abs(dw), if debugprint then print(float(w),float(dw)), /* error is approx dw^2/2 */ if dw < tol2 then return(false) ), w )$ /* Lee/Thompson's method forward */ tm(phi,lam):=block([psi,thom,jacr,jaci,sigma,gam,scale,c], phi:phi*degree, lam:lam*degree, psi:psi_phi(phi), thom:thom_psi(psi+%i*lam), jacr:sncndn(bfloat(realpart(thom)),1-e2), jaci:sncndn(bfloat(imagpart(thom)),e2), sigma:sigma_thom(thom), c:cos(phi), if c > tol1 then ( gam:atan2((1-e2)*jacr[1]*jaci[1]*jaci[2], jacr[2]*jacr[3]*jaci[3]), scale:sqrt(1-e2 + e2 * c^2)/c* sqrt(((1-e2)*jaci[1]^2 + (jacr[2]*jaci[3])^2)/ (e2*jacr[2]^2 + (1-e2)*jaci[2]^2))) else (gam : lam, scale : 1b0), [imagpart(sigma)*k0*a,realpart(sigma)*k0*a,gam/degree,k0*scale])$ /* Lee/Thompson's method reverse */ ll(x,y):=block([sigma,thom,jacr,jaci,psi,lam,phi,gam,scale,c], sigma:y/(a*k0)+%i*x/(a*k0), thom:thom_sigma(sigma), jacr:sncndn(bfloat(realpart(thom)),1-e2), jaci:sncndn(bfloat(imagpart(thom)),e2), psi:psi_thom(thom), lam:bfloat(imagpart(psi)), psi:bfloat(realpart(psi)), phi:phi_psi(psi), c:cos(phi), if c > tol1 then ( gam:atan2((1-e2)*jacr[1]*jaci[1]*jaci[2], jacr[2]*jacr[3]*jaci[3]), scale:sqrt(1-e2 + e2 * c^2)/c* sqrt(((1-e2)*jaci[1]^2 + (jacr[2]*jaci[3])^2)/ (e2*jacr[2]^2 + (1-e2)*jaci[2]^2))) else (gam : lam, scale : 1b0), [phi/degree,lam/degree,gam/degree,k0*scale])$ /* Return lat/lon/x/y for a point specified in Thompson coords */ /* Pick u in [0, kcu] and v in [0, kcv] */ lltm(u,v):=block([jacr,jaci,psi,lam,phi,c,gam,scale,sigma,x,y], u:bfloat(u), v:bfloat(v), jacr:sncndn(u,1-e2), jaci:sncndn(v,e2), psi:psi_thom(u+%i*v), sigma:sigma_thom(u+%i*v), x:imagpart(sigma)*k0*a,y:realpart(sigma)*k0*a, lam:bfloat(imagpart(psi)), psi:bfloat(realpart(psi)), phi:phi_psi(psi), c:cos(phi), if c > tol1 then ( gam:atan2((1-e2)*jacr[1]*jaci[1]*jaci[2], jacr[2]*jacr[3]*jaci[3]), scale:sqrt(1-e2 + e2 * c^2)/c* sqrt(((1-e2)*jaci[1]^2 + (jacr[2]*jaci[3])^2)/ (e2*jacr[2]^2 + (1-e2)*jaci[2]^2))) else (gam : lam, scale : 1b0), [phi/degree,lam/degree,x,y,gam/degree,k0*scale])$ /* Gauss-Krueger series to order n^i forward Uses the array functions a1_a[i](n), zeta_a[i](z,n), zeta_d[i](z,n), zetap_a[i](s,n), zetap_d[i](s,n), defined in tmseries.mac. */ tms(phi,lam,i):=block([psi,xip,etap,z,sigma,sp,gam,k,b1], phi:phi*degree, lam:lam*degree, psi:psi_phi(phi), xip:atan2(snh(psi), cos(lam)), etap:asinh(sin(lam)/hypot(snh(psi),cos(lam))), k:sqrt(1 - e2*sin(phi)^2)/(cos(phi)*hypot(snh(psi),cos(lam))), gam:atan(tan(xip)*tanh(etap)), z:xip+%i*etap, b1:a1_a[i](n), sigma:rectform(b1*zeta_a[i](z,n)), sp:rectform(zeta_d[i](z,n)), gam : gam - atan2(imagpart(sp),realpart(sp)), k : k * b1 * cabs(sp), [imagpart(sigma)*k0*a,realpart(sigma)*k0*a,gam/degree,k*k0])$ /* Gauss-Krueger series to order n^i reverse */ lls(x,y,i):=block([sigma,b1,s,z,zp,xip,etap,s,c,r,gam,k,lam,psi,phi], sigma:y/(a*k0)+%i*x/(a*k0), b1:a1_a[i](n), s:rectform(sigma/b1), z:rectform(zetap_a[i](s,n)), zp:rectform(zetap_d[i](s,n)), gam : atan2(imagpart(zp), realpart(zp)), k : b1 / cabs(zp), xip:realpart(z), etap:imagpart(z), s:snh(etap), c:cos(xip), r:hypot(s, c), lam:atan2(s, c), psi : asinh(sin(xip)/r), phi :phi_psi(psi), k : k * sqrt(1 - e2*sin(phi)^2) * r/cos(phi), gam : gam + atan(tan(xip) * tanh(etap)), [phi/degree,lam/degree,gam/degree,k*k0])$ /* Approx geodesic distance valid for small displacements */ dist(phi0,lam0,phi,lam):=block([dphi,dlam,nn,hlon,hlat], dphi:(phi-phi0)*degree, dlam:(lam-lam0)*degree, phi0:phi0*degree, lam0:lam0*degree, nn : 1/sqrt(1 - e2 * sin(phi0)^2), hlon : cos(phi0) * nn, hlat : (1 - e2) * nn^3, a * hypot(dphi*hlat, dlam*hlon))$ /* Compute truncation errors for all truncation levels */ check(phi,lam):=block([vv,x,y,gam,k,vf,vb,errf,errr,err2,errlist], phi:min(90-0.01b0,phi), lam:min(90-0.01b0,lam), vv:tm(phi,lam), errlist:[], x:vv[1], y:vv[2], gam:vv[3], k:vv[4], for i:1 thru maxpow do ( vf:tms(phi,lam,i), errf:hypot(vf[1]-x,vf[2]-y)/k, errfg:abs(vf[3]-gam), errfk:abs((vf[4]-k)/k), vb:lls(x,y,i), errr:dist(phi,lam,vb[1],vb[2]), errrg:abs(vb[3]-gam), errrk:abs((vb[4]-k)/k), errlist:append(errlist, [max(errf, errr), max(errfg, errrg), max(errfk, errrk)])), errlist)$ /* Max of output of check over a set of points */ checka(lst):=block([errlist:[],errx], for i:1 thru 3*maxpow do errlist:cons(0b0,errlist), for vv in lst do ( errx:check(vv[1],vv[2]), for i:1 thru 3*maxpow do errlist[i]:max(errlist[i],errx[i])), errlist)$ GeographicLib-1.49/maxima/tmseries.mac0000644000771000077100000001644513165402514017630 0ustar ckarneyckarney/* Compute series approximations for Transverse Mercator Projection Copyright (c) Charles Karney (2009-2010) and licensed under the MIT/X11 License. For more information, see https://geographiclib.sourceforge.io/ Reference: Charles F. F. Karney, Transverse Mercator with an accuracy of a few nanometers, J. Geodesy 85(8), 475-485 (Aug. 2011). DOI 10.1007/s00190-011-0445-3 preprint https://arxiv.org/abs/1002.1417 resource page https://geographiclib.sourceforge.io/tm.html Compute coefficient for forward and inverse trigonometric series for conversion from conformal latitude to rectifying latitude. This prints out assignments which with minor editing are suitable for insertion into C++ code. (N.B. n^3 in the output means n*n*n; 3/5 means 0.6.) To run, start maxima and enter writefile("tmseries.out")$ load("tmseries.mac")$ closefile()$ With maxpow = 6, the output (after about 5 secs) is A=a/(n+1)*(1+n^2/4+n^4/64+n^6/256); alpha[1]=n/2-2*n^2/3+5*n^3/16+41*n^4/180-127*n^5/288+7891*n^6/37800; alpha[2]=13*n^2/48-3*n^3/5+557*n^4/1440+281*n^5/630-1983433*n^6/1935360; alpha[3]=61*n^3/240-103*n^4/140+15061*n^5/26880+167603*n^6/181440; alpha[4]=49561*n^4/161280-179*n^5/168+6601661*n^6/7257600; alpha[5]=34729*n^5/80640-3418889*n^6/1995840; alpha[6]=+212378941*n^6/319334400; beta[1]=n/2-2*n^2/3+37*n^3/96-n^4/360-81*n^5/512+96199*n^6/604800; beta[2]=n^2/48+n^3/15-437*n^4/1440+46*n^5/105-1118711*n^6/3870720; beta[3]=17*n^3/480-37*n^4/840-209*n^5/4480+5569*n^6/90720; beta[4]=4397*n^4/161280-11*n^5/504-830251*n^6/7257600; beta[5]=4583*n^5/161280-108847*n^6/3991680; beta[6]=+20648693*n^6/638668800; Notation of output matches that of L. Krueger, Konforme Abbildung des Erdellipsoids in der Ebene Royal Prussian Geodetic Institute, New Series 52, 172 pp. (1912). with gamma replaced by alpha. Alter maxpow to generate more or less terms for the series approximations to the forward and reverse projections. This has been tested out to maxpow = 30; but this takes a long time (see below). */ /* Timing: maxpow time 4 2s 6 5s 8 11s 10 24s 12 52s 20 813s = 14m 30 13535s = 226m */ maxpow:8$ /* Max power for forward and reverse projections */ /* Notation e = eccentricity e2 = e^2 = f*(2-f) n = third flattening = f/(2-f) phi = (complex) geodetic latitude zetap = Gauss-Schreiber TM = complex conformal latitude psi = Mercator = complex isometric latitude zeta = scaled UTM projection = complex rectifying latitude */ taylordepth:6$ triginverses:'all$ /* revert var2 = expr(var1) = series in eps to var1 = revertexpr(var2) = series in eps Require that expr(var1) = var1 to order eps^0. This throws in a trigreduce to convert to multiple angle trig functions. */ reverta(expr,var1,var2,eps,pow):=block([tauacc:1,sigacc:0,dsig], dsig:ratdisrep(taylor(expr-var1,eps,0,pow)), dsig:subst([var1=var2],dsig), for n:1 thru pow do (tauacc:trigreduce(ratdisrep(taylor( -dsig*tauacc/n,eps,0,pow))), sigacc:sigacc+expand(diff(tauacc,var2,n-1))), var2+sigacc)$ /* Expansion for atan(x+eps) for small eps. Equivalent to taylor(atan(x + eps), eps, 0, maxpow) but tidied up a bit. */ atanexp(x,eps):=''(ratdisrep(taylor(atan(x+eps),eps,0,maxpow)))$ /* Convert from n to e^2 */ e2:4*n/(1+n)^2$ /* zetap in terms of phi. The expansion of atan(sinh( asinh(tan(phi)) + e * atanh(e * sin(phi)) )) */ zetap_phi:block([psiv,tanzetap,zetapv,qq,e], /* Here qq = atanh(sin(phi)) = asinh(tan(phi)) */ psiv:qq-e*atanh(e*tanh(qq)), psiv:subst([e=sqrt(e2),qq=atanh(sin(phi))], ratdisrep(taylor(psiv,e,0,2*maxpow))) +asinh(sin(phi)/cos(phi))-atanh(sin(phi)), tanzetap:subst([abs(cos(phi))=cos(phi),sqrt(sin(phi)^2+cos(phi)^2)=1], ratdisrep(taylor(sinh(psiv),n,0,maxpow)))+tan(phi)-sin(phi)/cos(phi), zetapv:atanexp(tan(phi),tanzetap-tan(phi)), zetapv:subst([cos(phi)=sqrt(1-sin(phi)^2), tan(phi)=sin(phi)/sqrt(1-sin(phi)^2)], (zetapv-phi)/cos(phi))*cos(phi)+phi, zetapv:ratdisrep(taylor(zetapv,n,0,maxpow)), expand(trigreduce(zetapv)))$ /* phi in terms of zetap */ phi_zetap:reverta(zetap_phi,phi,zetap,n,maxpow)$ /* Mean radius of meridian */ a1:expand(integrate( ratdisrep(taylor((1+n)*(1-e2)/(1-e2*sin(phi)^2)^(3/2), n,0,maxpow)), phi, 0, %pi/2)/(%pi/2))/(1+n)$ /* zeta in terms of phi. The expansion of zeta = pi/(2*a1) * int( (1-e^2)/(1-e^2*sin(phi)^2)^(3/2) ) */ zeta_phi:block([zetav], zetav:integrate(trigreduce(ratdisrep(taylor( (1-e2)/(1-e2*sin(phi)^2)^(3/2)/a1, n,0,maxpow))),phi), expand(zetav))$ /* phi in terms of zeta */ phi_zeta:reverta(zeta_phi,phi,zeta,n,maxpow)$ /* zeta in terms of zetap */ /* This is slow. The next version speeds it up a little. zeta_zetap:expand(trigreduce(ratdisrep( taylor(subst([phi=phi_zetap],zeta_phi),n,0,maxpow))))$ */ zeta_zetap:block([phiv:phi_zetap,zetav:expand(zeta_phi),acc:0], for i:0 thru maxpow do ( phiv:ratdisrep(taylor(phiv,n,0,maxpow-i)), acc:acc + expand(n^i * trigreduce(ratdisrep(taylor( subst([phi=phiv],coeff(zetav,n,i)),n,0,maxpow-i))))), acc)$ /* zetap in terms of zeta */ /* This is slow. The next version speeds it up a little. zetap_zeta:expand(trigreduce(ratdisrep( taylor(subst([phi=phi_zeta],zetap_phi),n,0,maxpow))))$ */ zetap_zeta:block([phiv:phi_zeta,zetapv:expand(zetap_phi),acc:0], for i:0 thru maxpow do ( phiv:ratdisrep(taylor(phiv,n,0,maxpow-i)), acc:acc + expand(n^i * trigreduce(ratdisrep(taylor( subst([phi=phiv],coeff(zetapv,n,i)),n,0,maxpow-i))))), acc)$ printa1():=block([], print(concat("A=",string(a/(n+1)),"*(", string(taylor(a1*(1+n),n,0,maxpow)),");")), 0)$ printtxf():=block([alpha:zeta_zetap,t], for i:1 thru maxpow do (t:coeff(alpha,sin(2*i*zetap)), print(concat("alpha[",i,"]=",string(taylor(t,n,0,maxpow)),";")), alpha:alpha-expand(t*sin(2*i*zetap))), /* should return zero */ alpha:alpha-zetap)$ printtxr():=block([beta:zetap_zeta,t], for i:1 thru maxpow do (t:coeff(beta,sin(2*i*zeta)), print(concat("beta[",i,"]=",string(taylor(-t,n,0,maxpow)),";")), beta:beta-expand(t*sin(2*i*zeta))), /* should return zero */ beta:beta-zeta)$ printseries():=[printa1(),printtxf(),printtxr()]$ /* Define array functions which are be read by tm.mac */ defarrayfuns():=block([aa:a1*(1+n),alpha:zeta_zetap,beta:zetap_zeta,t], for i:1 thru maxpow do ( define(a1_a[i](n),ratdisrep(taylor(aa,n,0,i))/(1+n)), t:expand(ratdisrep(taylor(alpha,n,0,i))), define(zeta_a[i](zp,n), zp+sum(coeff(t,sin(2*k*zetap))*sin(2*k*zp),k,1,i)), t:diff(t,zetap), define(zeta_d[i](zp,n), 1+sum(coeff(t,cos(2*k*zetap))*cos(2*k*zp),k,1,i)), t:expand(ratdisrep(taylor(beta,n,0,i))), define(zetap_a[i](z,n), z+sum(coeff(t,sin(2*k*zeta))*sin(2*k*z),k,1,i)), t:diff(t,zeta), define(zetap_d[i](z,n), 1+sum(coeff(t,cos(2*k*zeta))*cos(2*k*z),k,1,i))))$ printseries()$ (b1:a1, for i:1 thru maxpow do (alp[i]:coeff(zeta_zetap,sin(2*i*zetap)), bet[i]:coeff(expand(-zetap_zeta),sin(2*i*zeta))))$ load("polyprint.mac")$ printtm():=block([macro:GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER], value1('(b1*(1+n)),'n,2,0), array1('alp,'n,1,0), array1('bet,'n,1,0))$ printtm()$ /* defarrayfuns()$ save("tmseries.lsp",maxpow,arrays)$ */ GeographicLib-1.49/maxima/geod.mac0000644000771000077100000004545013165402514016711 0ustar ckarneyckarney/* Compute the series expansions for the ellipsoidal geodesic problem. Copyright (c) Charles Karney (2009-2015) and licensed under the MIT/X11 License. For more information, see https://geographiclib.sourceforge.io/ References: Charles F. F. Karney, Algorithms for geodesics, J. Geodesy 87, 43-55 (2013), https://doi.org/10.1007/s00190-012-0578-z Addenda: https://geographiclib.sourceforge.io/geod-addenda.html There are 4 sections in this file (1) Functions to compute the expansions (2) Functions to print C++ code (3) Functions to display the results (4) Calls to the above. Edit the section at the end, to modify what is done. As distributed this code computes the 8th order series. This takes about 10 secs. If you want to compute accurate geodesics using geodesic.mac, then you need alse to uncomment the last line of this file so that the series get saved as geodNN.lsp. To run the code, start Maxima and enter load("geod.mac")$ */ /* EXPANSIONS FOR INTEGRALS */ taylordepth:5$ ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$ jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1], ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$ /* Express I1 = integrate( sqrt(1+k2*sin(sigma1)^2), sigma1, 0, sigma ) as a series A1 * ( sigma + sum(C1[l] * sin(2*l*sigma), l, 1, maxpow) ) valid for k2 small. It is convenient to write k2 = 4 * eps / (1 - eps)^2 and to expand (1 - eps) * I1 retaining terms up to order eps^maxpow in A1 and C1[l]. This leads to a series where half the terms drop out. */ computeI1(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps], sintegrand:sqrt(1+k2*sin(sigma)^2), /* Multiplicative factor 1/(1-eps) */ sintegrandexp:ataylor( (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand), eps,maxpow), s:trigreduce(integrate(sintegrandexp,sigma)), s:s-subst(sigma=0,s), A1:expand(subst(sigma=2*%pi,s)/(2*%pi)), tau1:ataylor(s/A1,eps,maxpow), for i:1 thru maxpow do C1[i]:coeff(tau1,sin(2*i*sigma)), if expand(tau1-sigma-sum(C1[i]*sin(2*i*sigma),i,1,maxpow)) # 0 then error("left over terms in B1"), A1:A1/(1-eps), 'done)$ /* Write tau1 = sigma + sum(C1[l] * sin(2*l*sigma), l, 1, maxpow) and revert this to obtain sigma = tau1 + sum(C1p[l] * sin(2*tau1), l, 1, maxpow) retaining terms up to order eps^maxpow in tp[l]. Write tau = sigma + B1(sigma) sigma = tau + B1p(tau) B1(sigma) = sum(C1[l] * sin(2*l*sigma), l, 1, inf) B1p(tau) = sum(C1p[l] * sin(2*tau), l, 1, inf) Then the Lagrange Inversion Theorem J. L. Lagrange, Nouvelle methode pour resoudre les equations litterales par le moyen des series, Mem. de l'Acad. Roy. des Sciences de Berlin 24, 251-326 (1768, publ. 1770), Sec. 16, https://books.google.com/books?id=YywPAAAAIAAJ&pg=PA25 gives B1p(tau) = sum( (-1)^n/n! * diff( B1(tau)^n, tau, n-1 ), n, 1, inf) Call this after computeI1(maxpow)$ */ revertI1(maxpow):=block([tau,eps,tauacc:1,sigacc:0], for n:1 thru maxpow do ( tauacc:trigreduce(ataylor( -sum(C1[j]*sin(2*j*tau),j,1,maxpow-n+1)*tauacc/n, eps,maxpow)), sigacc:sigacc+expand(diff(tauacc,tau,n-1))), for i:1 thru maxpow do C1p[i]:coeff(sigacc,sin(2*i*tau)), if expand(sigacc-sum(C1p[i]*sin(2*i*tau),i,1,maxpow)) # 0 then error("left over terms in B1p"), 'done)$ /* Express I2 = integrate( 1/sqrt(1+k2*sin(sigma1)^2), sigma1, 0, sigma ) as a series A2 * ( sigma + sum(C2[l] * sin(2*l*sigma), l, 1, maxpow) ) valid for k2 small. It is convenient to write k2 = 4 * eps / (1 - eps)^2 and to expand 1/(1 - eps) * I2 retaining terms up to order eps^maxpow in A2 and C2[l]. This leads to a series where half the terms drop out. */ computeI2(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps], sintegrand:1/sqrt(1+k2*sin(sigma)^2), /* Multiplicative factor 1/(1+eps) */ sintegrandexp:ataylor( (1+eps)*subst([k2=4*eps/(1-eps)^2],sintegrand), eps,maxpow), s:trigreduce(integrate(sintegrandexp,sigma)), s:s-subst(sigma=0,s), A2:expand(subst(sigma=2*%pi,s)/(2*%pi)), tau1:ataylor(s/A2,eps,maxpow), for i:1 thru maxpow do C2[i]:coeff(tau1,sin(2*i*sigma)), if expand(tau1-sigma-sum(C2[i]*sin(2*i*sigma),i,1,maxpow)) # 0 then error("left over terms in B2"), A2:A2/(1+eps), 'done)$ /* Express I3 = integrate( (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma1)^2)), sigma1, 0, sigma ) as a series A3 * ( sigma + sum(C3[l] * sin(2*l*sigma), l, 1, maxpow-1) ) valid for f and k2 small. It is convenient to write k2 = 4 * eps / (1 - eps)^2 and f = 2*n/(1+n) and expand in eps and n. This procedure leads to a series where the coefficients of eps^j are terminating series in n. */ computeI3(maxpow):=block([int,intexp,dlam,eta,del,eps,nu,f,z,n], maxpow:maxpow-1, int:subst([k2=4*eps/(1-eps)^2], (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma)^2))), int:subst([f=2*n/(1+n)],int), intexp:jtaylor(int,n,eps,maxpow), dlam:trigreduce(integrate(intexp,sigma)), dlam:dlam-subst(sigma=0,dlam), A3:expand(subst(sigma=2*%pi,dlam)/(2*%pi)), eta:jtaylor(dlam/A3,n,eps,maxpow), A3:jtaylor(A3,n,eps,maxpow), for i:1 thru maxpow do C3[i]:coeff(eta,sin(2*i*sigma)), if expand(eta-sigma-sum(C3[i]*sin(2*i*sigma),i,1,maxpow)) # 0 then error("left over terms in B3"), 'done)$ /* Express I4 = -integrate( (t(ep2) - t(k2*sin(sigma1)^2)) / (ep2 - k2*sin(sigma1)^2) * sin(sigma1)/2, sigma1, pi/2, sigma ) where t(x) = sqrt(1+1/x)*asinh(sqrt(x)) + x as a series sum(C4[l] * cos((2*l+1)*sigma), l, 0, maxpow-1) ) valid for ep2 and k2 small. It is convenient to write k2 = 4 * eps / (1 - eps)^2 and ep2 = 4 * n / (1 - n)^2 and to expand in eps and n. This procedure leads to a series which converges even for very eccentric ellipsoids. */ computeI4(maxpow):=block([int,t,intexp,area, x,ep2,k2], maxpow:maxpow-1, t : sqrt(1+1/x) * asinh(sqrt(x)) + x, int:-(tf(ep2) - tf(k2*sin(sigma)^2)) / (ep2 - k2*sin(sigma)^2) * sin(sigma)/2, int:subst([tf(ep2)=subst([x=ep2],t), tf(k2*sin(sigma)^2)=subst([x=k2*sin(sigma)^2],t)], int), int:subst([abs(sin(sigma))=sin(sigma)],int), int:subst([k2=4*eps/(1-eps)^2,ep2=4*n/(1-n)^2],int), intexp:jtaylor(int,n,eps,maxpow), area:trigreduce(integrate(intexp,sigma)), area:expand(area-subst(sigma=%pi/2,area)), for i:0 thru maxpow do C4[i]:coeff(area,cos((2*i+1)*sigma)), if expand(area-sum(C4[i]*cos((2*i+1)*sigma),i,0,maxpow)) # 0 then error("left over terms in I4"), 'done)$ /* Call all of the above */ computeall():=( computeI1(maxpow), revertI1(maxpow), computeI2(maxpow), computeI3(maxpow), computeI4(maxpow))$ /* FORMAT FOR C++ */ /* If nA1, nC1, nC1p, nA2, nA3, nC3 are compile-time constants indicating the required order, the compiler will include only the needed code. GEOGRAPHICLIB_STATIC_ASSERT is a macro to cause a compile-time error if the assertion is false. */ codeA1(maxpow):=block([tab2:" ",tab3:" "], print(" // The scale factor A1-1 = mean value of (d/dsigma)I1 - 1 Math::real Geodesic::A1m1f(real eps) { real eps2 = Math::sq(eps), t; switch (nA1_/2) {"), for n:0 thru entier(maxpow/2) do block([ q:horner(ataylor(subst([eps=sqrt(eps2)],A1*(1-eps)-1),eps2,n)), linel:1200], print(concat(tab2,"case ",string(n),":")), print(concat(tab3,"t = ",string(q),";")), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(nA1_ >= ",string(0), " && nA1_ <= ",string(maxpow),", \"Bad value of nA1_\");")), print(concat(tab3,"t = 0;")), print(" } return (t + eps) / (1 - eps); }"), 'done)$ codeC1(maxpow):=block([tab2:" ",tab3:" "], print(" // The coefficients C1[l] in the Fourier expansion of B1 void Geodesic::C1f(real eps, real c[]) { real eps2 = Math::sq(eps), d = eps; switch (nC1_) {"), for n:0 thru maxpow do ( print(concat(tab2,"case ",string(n),":")), for m:1 thru n do block([q:d*horner( subst([eps=sqrt(eps2)],ataylor(C1[m],eps,n)/eps^m)), linel:1200], if m>1 then print(concat(tab3,"d *= eps;")), print(concat(tab3,"c[",string(m),"] = ",string(q),";"))), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(nC1_ >= ",string(0), " && nC1_ <= ",string(maxpow),", \"Bad value of nC1_\");")), print(" } }"), 'done)$ codeC1p(maxpow):=block([tab2:" ",tab3:" "], print(" // The coefficients C1p[l] in the Fourier expansion of B1p void Geodesic::C1pf(real eps, real c[]) { real eps2 = Math::sq(eps), d = eps; switch (nC1p_) {"), for n:0 thru maxpow do ( print(concat(tab2,"case ",string(n),":")), for m:1 thru n do block([q:d*horner( subst([eps=sqrt(eps2)],ataylor(C1p[m],eps,n)/eps^m)), linel:1200], if m>1 then print(concat(tab3,"d *= eps;")), print(concat(tab3,"c[",string(m),"] = ",string(q),";"))), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(nC1p_ >= ",string(0), " && nC1p_ <= ",string(maxpow),", \"Bad value of nC1p_\");")), print(" } }"), 'done)$ codeA2(maxpow):=block([tab2:" ",tab3:" "], print(" // The scale factor A2-1 = mean value of (d/dsigma)I2 - 1 Math::real Geodesic::A2m1f(real eps) { real eps2 = Math::sq(eps), t; switch (nA2_/2) {"), for n:0 thru entier(maxpow/2) do block([ q:horner(ataylor(subst([eps=sqrt(eps2)],A2*(1+eps)-1),eps2,n)), linel:1200], print(concat(tab2,"case ",string(n),":")), print(concat(tab3,"t = ",string(q),";")), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(nA2_ >= ",string(0), " && nA2_ <= ",string(maxpow),", \"Bad value of nA2_\");")), print(concat(tab3,"t = 0;")), print(" } return (t - eps) / (1 + eps); }"), 'done)$ codeC2(maxpow):=block([tab2:" ",tab3:" "], print(" // The coefficients C2[l] in the Fourier expansion of B2 void Geodesic::C2f(real eps, real c[]) { real eps2 = Math::sq(eps), d = eps; switch (nC2_) {"), for n:0 thru maxpow do ( print(concat(tab2,"case ",string(n),":")), for m:1 thru n do block([q:d*horner( subst([eps=sqrt(eps2)],ataylor(C2[m],eps,n)/eps^m)), linel:1200], if m>1 then print(concat(tab3,"d *= eps;")), print(concat(tab3,"c[",string(m),"] = ",string(q),";"))), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(nC2_ >= ",string(0), " && nC2_ <= ",string(maxpow),", \"Bad value of nC2_\");")), print(" } }"), 'done)$ codeA3(maxpow):=block([tab2:" ",tab3:" "], print(" // The scale factor A3 = mean value of (d/dsigma)I3 void Geodesic::A3coeff() { switch (nA3_) {"), for nn:0 thru maxpow do block( [q:if nn=0 then 0 else jtaylor(subst([n=_n],A3),_n,eps,nn-1), linel:1200], print(concat(tab2,"case ",string(nn),":")), for i : 0 thru nn-1 do print(concat(tab3,"_A3x[",i,"] = ", string(horner(coeff(q,eps,i))),";")), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(nA3_ >= ",string(0), " && nA3_ <= ",string(maxpow),", \"Bad value of nA3_\");")), print(" } }"), 'done)$ codeC3(maxpow):=block([tab2:" ",tab3:" "], print(" // The coefficients C3[l] in the Fourier expansion of B3 void Geodesic::C3coeff() { switch (nC3_) {"), for nn:0 thru maxpow do block([c], print(concat(tab2,"case ",string(nn),":")), c:0, for m:1 thru nn-1 do block( [q:if nn = 0 then 0 else jtaylor(subst([n=_n],C3[m]),_n,eps,nn-1), linel:1200], for j:m thru nn-1 do ( print(concat(tab3,"_C3x[",c,"] = ", string(horner(coeff(q,eps,j))),";")), c:c+1) ), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(nC3_ >= ",string(0), " && nC3_ <= ",string(maxpow),", \"Bad value of nC3_\");")), print(" } }"), 'done)$ codeC4(maxpow):=block([tab2:" ",tab3:" "], print(" // The coefficients C4[l] in the Fourier expansion of I4 void Geodesic::C4coeff() { switch (nC4_) {"), for nn:0 thru maxpow do block([c], print(concat(tab2,"case ",string(nn),":")), c:0, for m:0 thru nn-1 do block( [q:jtaylor(subst([n=_n],C4[m]),_n,eps,nn-1), linel:1200], for j:m thru nn-1 do ( print(concat(tab3,"_C4x[",c,"] = ", string(horner(coeff(q,eps,j))),";")), c:c+1) ), print(concat(tab3,"break;"))), print(concat(tab2,"default:")), print(concat(tab3,"GEOGRAPHICLIB_STATIC_ASSERT(nC4_ >= ",string(0), " && nC4_ <= ",string(maxpow),", \"Bad value of nC4_\");")), print(" } }"), 'done)$ printcode():=( print(""), print(concat(" // Generated by Maxima on ",timedate())), print(""), codeA1(maxpow), print(""), codeC1(maxpow), print(""), codeC1p(maxpow), print(""), codeA2(maxpow), print(""), codeC2(maxpow), print(""), codeA3(maxpow), print(""), codeC3(maxpow), print(""), codeC4(maxpow))$ /* FORMAT FOR DISPLAY */ dispA1(ord):=block( [tt:ataylor(A1*(1-eps),eps,ord),ttt,linel:1200], for j:2 step 2 thru ord do (ttt:coeff(tt,eps,j), print(concat(if j = 2 then "A1 = (1 " else " ", if ttt>0 then "+ " else "- ", string(abs(ttt)), " * ", string(eps^j), if j=ord or j = ord-1 then ") / (1 - eps);" else ""))))$ dispC1(ord):=for i:1 thru ord do block([tt:ataylor(C1[i],eps,ord),ttt,linel:1200], print(), for j:i step 2 thru ord do (ttt:coeff(tt,eps,j), print(concat( if j = i then concat("C1[",string(i),"] = ") else " ", if ttt>0 then "+ " else "- ", string(abs(ttt)), " * ", string(eps^j), if j=ord or j=ord-1 then ";" else ""))))$ dispC1p(ord):=for i:1 thru ord do block([tt:ataylor(C1p[i],eps,ord),ttt,linel:1200], print(), for j:i step 2 thru ord do (ttt:coeff(tt,eps,j), print(concat( if j = i then concat("C1p[",string(i),"] = ") else " ", if ttt>0 then "+ " else "- ", string(abs(ttt)), " * ", string(eps^j), if j=ord or j=ord-1 then ";" else ""))))$ dispA2(ord):=block( [tt:ataylor(A2*(1+eps),eps,ord),ttt,linel:1200], for j:2 step 2 thru ord do (ttt:coeff(tt,eps,j), print(concat(if j = 2 then "A2 = (1 " else " ", if ttt>0 then "+ " else "- ", string(abs(ttt)), " * ", string(eps^j), if j=ord or j = ord-1 then ") / (1 + eps);" else ""))))$ dispC2(ord):=for i:1 thru ord do block([tt:ataylor(C2[i],eps,ord),ttt,linel:1200], print(), for j:i step 2 thru ord do (ttt:coeff(tt,eps,j), print(concat( if j = i then concat("C2[",string(i),"] = ") else " ", if ttt>0 then "+ " else "- ", string(abs(ttt)), " * ", string(eps^j), if j=ord or j=ord-1 then ";" else ""))))$ dispA3(ord):=(ord:ord-1,block( [tt:jtaylor(A3,n,eps,ord),ttt,t4,linel:1200,s], for j:1 thru ord do (ttt:expand(coeff(tt,eps,j)), if ttt # 0 then block([a:taylor(ttt+n^(ord+1),n,0,ord+1),paren,s], paren : is(length(a) > 2), s:if j=1 then "A3 = 1" else " ", if subst([n=1],part(a,1)) > 0 then s:concat(s," + ") else (s:concat(s," - "), a:-a), if paren then s:concat(s,"("), for k:1 thru length(a)-1 do block([term:part(a,k),nn], nn:subst([n=1],term), term:term/nn, if nn > 0 and k > 1 then s:concat(s," + ") else if nn < 0 then (s:concat(s," - "), nn:-nn), if lopow(term,n) = 0 then s:concat(s,string(nn)) else ( if nn # 1 then s:concat(s,string(nn)," * "), s:concat(s,string(term)) )), if paren then s:concat(s,")"), s:concat(s," * ", string(eps^j)), print(concat(s,if j = ord then ";" else ""))))))$ dispC3(ord):=(ord:ord-1,for i:1 thru ord do block([tt:jtaylor(C3[i],eps,n,ord), ttt,t4,linel:1200], for j:i thru ord do ( ttt:coeff(tt,eps,j), if ttt # 0 then block([a:taylor(ttt+n^(ord+1),n,0,ord+1),paren,s], paren : is(length(a) > 2), s:if j = i then concat("C3[",i,"] = ") else " ", if subst([n=1],part(a,1)) > 0 then s:concat(s,"+ ") else (s:concat(s,"- "), a:-a), if paren then s:concat(s,"("), for k:1 thru length(a)-1 do block([term:part(a,k),nn], nn:subst([n=1],term), term:term/nn, if nn > 0 and k > 1 then s:concat(s," + ") else if nn < 0 then (s:concat(s," - "), nn:-nn), if lopow(term,n) = 0 then s:concat(s,string(nn)) else ( if nn # 1 then s:concat(s,string(nn)," * "), s:concat(s,string(term)) )), if paren then s:concat(s,")"), s:concat(s," * ", string(eps^j)), print(concat(s,if j = ord then ";" else ""))))))$ dispC4(ord):=(ord:ord-1,for i:0 thru ord do block([tt:jtaylor(C4[i],n,eps,ord), ttt,t4,linel:1200], for j:i thru ord do ( ttt:coeff(tt,eps,j), if ttt # 0 then block([a:taylor(ttt+n^(ord+1),n,0,ord+1),paren,s], paren : is(length(a) > 2), s:if j = i then concat("C4[",i,"] = ") else " ", if subst([n=1],part(a,1)) > 0 then s:concat(s,"+ ") else (s:concat(s,"- "), a:-a), if paren then s:concat(s,"("), for k:1 thru length(a)-1 do block([term:part(a,k),nn], nn:subst([n=1],term), term:term/nn, if nn > 0 and k > 1 then s:concat(s," + ") else if nn < 0 then (s:concat(s," - "), nn:-nn), if lopow(term,n) = 0 then s:concat(s,string(nn)) else ( if nn # 1 then s:concat(s,string(nn)," * "), s:concat(s,string(term)) )), if paren then s:concat(s,")"), if j>0 then s:concat(s," * ", string(eps^j)), print(concat(s,if j = ord then ";" else ""))))))$ dispseries():=( print(""), print(concat("// Generated by Maxima on ",timedate())), print(""), dispA1(maxpow), print(""), dispC1(maxpow), print(""), dispC1p(maxpow), print(""), dispA2(maxpow), print(""), dispC2(maxpow), print(""), dispA3(maxpow), print(""), dispC3(maxpow), print(""), dispC4(maxpow), print(""))$ /* CALL THE FUNCTIONS */ /* Timings for computeall(n) n time(s) 8 8 10 19 12 43 20 571 30 6671 (111m) */ maxpow:8$ computeall()$ /* printcode()$ */ dispseries()$ load("polyprint.mac")$ printgeod():= block([macro:if simplenum then "GEOGRAPHICLIB_GEODESIC_ORDER" else "GEOGRAPHICLIB_GEODESICEXACT_ORDER"], value1('(A1*(1-eps)-1),'eps,2,0), array1('C1,'eps,2,0), array1('C1p,'eps,2,0), value1('(A2*(1+eps)-1),'eps,2,0), array1('C2,eps,2,0), value2('A3,'n,'eps,1), array2('C3,'n,'eps,1), array2('C4,'n,'eps,1))$ printgeod()$ /* Save the values needed for geodesic.mac This is commented out here to avoid accidentally overwriting files in a user's directory. */ /* (file:concat("geod",maxpow,".lsp"), save(file, values, arrays))$ */ GeographicLib-1.49/maxima/auxlat.mac0000644000771000077100000002107313165402514017264 0ustar ckarneyckarney/* Compute series expansions for the auxiliary latitudes. Copyright (c) Charles Karney (2014-2017) and licensed under the MIT/X11 License. For more information, see https://geographiclib.sourceforge.io/ This maxima program compute the coefficients for trigonometric series relating the six latitudes phi geographic beta parametric theta geocentric mu rectifying chi conformal xi authalic All 30 inter-relations are found. The coefficients are expressed as Taylor series in the third flattening n. This generates the series given on the page https://geographiclib.sourceforge.io/html/auxlat.html Instructions: * [optional] edit to set the desired value of maxpow (currently 8) * start maxima and run batch("auxlat.mac")$ writefile("auxlat.txt")$ dispall()$ closefile()$ Timings: maxpow time(s) 6 13 8 41 10 114 12 293 14 708 16 1629 */ /* revert var2 = expr(var1) = series in eps to var1 = revertexpr(var2) = series in eps Require that expr(var1) = var1 to order eps^0. This throws in a trigreduce to convert to multiple angle trig functions. */ maxpow:8$ reverta(expr,var1,var2,eps,pow):=block([tauacc:1,sigacc:0,dsig], dsig:ratdisrep(taylor(expr-var1,eps,0,pow)), dsig:subst([var1=var2],dsig), for n:1 thru pow do (tauacc:trigreduce(ratdisrep(taylor( -dsig*tauacc/n,eps,0,pow))), sigacc:sigacc+expand(diff(tauacc,var2,n-1))), var2+sigacc)$ /* beta in terms of phi */ beta_phi:phi+sum((-n)^j/j*sin(2*j*phi),j,1,maxpow)$ /* Alt: beta_phi:taylor(atan((1-n)/(1+n)*tan(phi)),n,0,maxpow)$ beta_phi:subst([atan(tan(phi))=phi,tan(phi)=sin(phi)/cos(phi)], ratdisrep(beta_phi))$ beta_phi:trigreduce(ratsimp(beta_phi))$ */ /* phi in terms of beta */ phi_beta:subst([n=-n,phi=beta],beta_phi)$ /* Alt: beta_phi:reverta(beta_phi,phi,beta,n,maxpow)$ */ /* theta in terms of beta */ theta_beta:subst([phi=beta],beta_phi)$ /* theta in terms of phi */ theta_phi:subst([beta=beta_phi],theta_beta)$ theta_phi:trigreduce(taylor(theta_phi,n,0,maxpow))$ /* phi in terms of theta */ phi_theta:subst([n=-n,phi=theta],theta_phi)$ /* chi in terms of phi */ atanexp(x,eps):=''(ratdisrep(taylor(atan(x+eps),eps,0,maxpow)))$ chi_phi:block([psiv,tanchi,chiv,qq,e], /* Here qq = atanh(sin(phi)) = asinh(tan(phi)) */ psiv:qq-e*atanh(e*tanh(qq)), psiv:subst([e=sqrt(4*n/(1+n)^2),qq=atanh(sin(phi))], ratdisrep(taylor(psiv,e,0,2*maxpow))) +asinh(sin(phi)/cos(phi))-atanh(sin(phi)), tanchi:subst([abs(cos(phi))=cos(phi),sqrt(sin(phi)^2+cos(phi)^2)=1], ratdisrep(taylor(sinh(psiv),n,0,maxpow)))+tan(phi)-sin(phi)/cos(phi), chiv:atanexp(tan(phi),tanchi-tan(phi)), chiv:subst([atan(tan(phi))=phi, tan(phi)=sin(phi)/cos(phi)], (chiv-phi)/cos(phi))*cos(phi)+phi, chiv:ratdisrep(taylor(chiv,n,0,maxpow)), expand(trigreduce(chiv)))$ /* phi in terms of chi */ phi_chi:reverta(chi_phi,phi,chi,n,maxpow)$ df[i]:=if i<0 then df[i+2]/(i+2) else i!!$ /* df[-1] = 1; df[-3] = -1 */ c(k,maxpow):=sum(n^(k+2*j)*(df[2*j-3]*df[2*j+2*k-3])/(df[2*j]*df[2*j+2*k]), j,0,(maxpow-k)/2)$ /* mu in terms of beta */ mu_beta:expand(ratdisrep( taylor(beta+sum(c(i,maxpow)/i*sin(2*i*beta),i,1,maxpow)/c(0,maxpow), n,0,maxpow)))$ /* beta in terms of mu */ beta_mu:reverta(mu_beta,beta,mu,n,maxpow)$ asinexp(x,eps):=''(sqrt(1-x^2)* sum(ratsimp(diff(asin(x),x,i)/i!/sqrt(1-x^2))*eps^i,i,0,maxpow))$ sinxi:(sin(phi)/2*(1/(1-e^2*sin(phi)^2) + atanh(e*sin(phi))/(e*sin(phi))))/ (1/2*(1/(1-e^2) + atanh(e)/e))$ sinxi:ratdisrep(taylor(sinxi,e,0,2*maxpow))$ sinxi:subst([e=2*sqrt(n)/(1+n)],sinxi)$ sinxi:expand(trigreduce(ratdisrep(taylor(sinxi,n,0,maxpow))))$ xi_phi:asinexp(sin(phi),sinxi-sin(phi))$ xi_phi:taylor(subst([sqrt(1-sin(phi)^2)=cos(phi),asin(sin(phi))=phi], xi_phi),n,0,maxpow)$ xi_phi:expand(ratdisrep(coeff(xi_phi,n,0))+sum( ratsimp(trigreduce(sin(phi)*ratsimp( subst([sin(phi)=sqrt(1-cos(phi)^2)], ratsimp(trigexpand(ratdisrep(coeff(xi_phi,n,i)))/sin(phi))))))*n^i, i,1,maxpow))$ phi_xi:reverta(xi_phi,phi,xi,n,maxpow)$ mu_phi:expand(trigreduce(taylor(subst([beta=beta_phi],mu_beta),n,0,maxpow)))$ phi_mu:expand(trigreduce(taylor(subst([beta=beta_mu],phi_beta),n,0,maxpow)))$ chi_mu:expand(trigreduce(taylor(subst([phi=phi_mu],chi_phi),n,0,maxpow)))$ mu_chi:expand(trigreduce(taylor(subst([phi=phi_chi],mu_phi),n,0,maxpow)))$ beta_chi:expand(trigreduce(taylor(subst([phi=phi_chi],beta_phi),n,0,maxpow)))$ chi_beta:expand(trigreduce(taylor(subst([phi=phi_beta],chi_phi),n,0,maxpow)))$ beta_theta:expand(trigreduce (taylor(subst([phi=phi_theta],beta_phi),n,0,maxpow)))$ beta_xi:expand(trigreduce(taylor(subst([phi=phi_xi],beta_phi),n,0,maxpow)))$ chi_theta:expand(trigreduce (taylor(subst([phi=phi_theta],chi_phi),n,0,maxpow)))$ chi_xi:expand(trigreduce(taylor(subst([phi=phi_xi],chi_phi),n,0,maxpow)))$ mu_theta:expand(trigreduce(taylor(subst([phi=phi_theta],mu_phi),n,0,maxpow)))$ mu_xi:expand(trigreduce(taylor(subst([phi=phi_xi],mu_phi),n,0,maxpow)))$ theta_chi:expand(trigreduce (taylor(subst([phi=phi_chi],theta_phi),n,0,maxpow)))$ theta_mu:expand(trigreduce(taylor(subst([phi=phi_mu],theta_phi),n,0,maxpow)))$ theta_xi:expand(trigreduce(taylor(subst([phi=phi_xi],theta_phi),n,0,maxpow)))$ xi_beta:expand(trigreduce(taylor(subst([phi=phi_beta],xi_phi),n,0,maxpow)))$ xi_chi:expand(trigreduce(taylor(subst([phi=phi_chi],xi_phi),n,0,maxpow)))$ xi_mu:expand(trigreduce(taylor(subst([phi=phi_mu],xi_phi),n,0,maxpow)))$ xi_theta:expand(trigreduce(taylor(subst([phi=phi_theta],xi_phi),n,0,maxpow)))$ norm(x):=block([z:subst([n=0],x)], z+sum(coeff(expand(x),sin(2*i*z))*sin(2*i*z),i,1,maxpow))$ ( tx[beta,chi]:norm(beta_chi), tx[beta,mu]:norm(beta_mu), tx[beta,phi]:norm(beta_phi), tx[beta,theta]:norm(beta_theta), tx[beta,xi]:norm(beta_xi), tx[chi,beta]:norm(chi_beta), tx[chi,mu]:norm(chi_mu), tx[chi,phi]:norm(chi_phi), tx[chi,theta]:norm(chi_theta), tx[chi,xi]:norm(chi_xi), tx[mu,beta]:norm(mu_beta), tx[mu,chi]:norm(mu_chi), tx[mu,phi]:norm(mu_phi), tx[mu,theta]:norm(mu_theta), tx[mu,xi]:norm(mu_xi), tx[phi,beta]:norm(phi_beta), tx[phi,chi]:norm(phi_chi), tx[phi,mu]:norm(phi_mu), tx[phi,theta]:norm(phi_theta), tx[phi,xi]:norm(phi_xi), tx[theta,beta]:norm(theta_beta), tx[theta,chi]:norm(theta_chi), tx[theta,mu]:norm(theta_mu), tx[theta,phi]:norm(theta_phi), tx[theta,xi]:norm(theta_xi), tx[xi,beta]:norm(xi_beta), tx[xi,chi]:norm(xi_chi), tx[xi,mu]:norm(xi_mu), tx[xi,phi]:norm(xi_phi), tx[xi,theta]:norm(xi_theta))$ ll1:[ [beta,phi], [theta,phi], [theta,beta], [mu,phi], [mu,beta], [mu,theta]]$ ll2:[ [chi,phi], [chi,beta], [chi,theta], [chi,mu], [xi,phi], [xi,beta], [xi,theta], [xi,mu], [xi,chi]]$ tt[i,j]:=if i=j then [] else block([v:tx[i,j],x:j,l:[]], for i:1 thru maxpow do block([l1:[],c:coeff(v,sin(2*i*x))], for j:i thru maxpow do l1:endcons(coeff(c,n,j),l1), l:endcons(l1,l)), l)$ texa(i,j,pow):=block([x:j,y:i,v:tt[i,j],s:"\\",sn:"\\sin "], x:concat(s,x), y:concat(s,y), print(concat(y, "-", x, "&=\\textstyle{}")), for k:1 thru pow do block([t:v[k],sgn,nterm:0,str:""], sgn:0, for l:1 thru pow-k+1 do block([m:t[l]], if m # 0 then (nterm:nterm+1, if sgn = 0 then sgn:if m>0 then 1 else -1) ), t:sgn*t, if sgn # 0 then block([f:true], str:concat(str,if sgn > 0 then "+" else "-"), if nterm > 1 then str:concat(str,"\\bigl("), for l:1 thru pow-k+1 do block([c:t[l]], if c # 0 then (sgn:if c > 0 then 1 else -1, c:sgn*c, if not f and nterm > 1 then str:concat(str,if sgn > 0 then "+" else "-"), f:false, if c # 1 then if integerp(c) then str:concat(str,c) else str:concat(str,"\\frac{",num(c),"}{",denom(c),"}"), if l+k-1 > 1 then str:concat(str,"n^{",l+k-1,"}") else str:concat(str,"n"))), if nterm > 1 then str:concat(str,"\\bigr)"), str:concat(str,sn,2*k,x)), print(str)), print(concat(if v[pow+1][1] < 0 then "-" else "+","\\ldots\\\\")))$ cf(i,j):= ( print(concat("

&",i,"; − &",j,";:
")), for x in tt[i,j] do block([str:"   ["], for i:1 thru length(x) do str:concat(str,string(x[i]),if i"), print(str)), print(""))$ disptex(ll,pow):= block([linel:1000], print("\\f["), print("\\begin{align}"), for xx in ll do (texa(xx[1],xx[2],pow),texa(xx[2],xx[1],pow)), print("\\end{align}"), print("\\f]"))$ dispcoeffs(ll):= block([linel:1000], for xx in ll do (cf(xx[1],xx[2]),cf(xx[2],xx[1])))$ dispall():=( print(""), disptex(ll1,4), print(""), disptex(ll2,3), print(""), dispcoeffs(append(ll1,ll2)), print(""))$ GeographicLib-1.49/maxima/geodesic.mac0000644000771000077100000014202213165402514017546 0ustar ckarneyckarney/* Solve the direct and inverse geodesic problems accurately. Copyright (c) Charles Karney (2013-2017) and licensed under the MIT/X11 License. For more information, see https://geographiclib.sourceforge.io/ References: Charles F. F. Karney, Algorithms for geodesics, J. Geodesy 87, 43-55 (2013), https://doi.org/10.1007/s00190-012-0578-z Addenda: https://geographiclib.sourceforge.io/geod-addenda.html This program solves the geodesic problem either using series expansions (exact : false) or using elliptic integrals (exact : true). Elliptic integrals give reliably high accuracy (especially when f is large). Note that the area calculation always uses the series expansion (I don't know how to express the integrals in terms of elliptic integrals). Before running this file, you need to compute and save the series expansions by editing geod.mac setting maxpow appropriately (near the end of the file) and uncommenting the last line (to save the results). If you're testing the accuracy of the series expansions (exact : false) or if you're interested in accurate results for the area, that pick a largish value of maxpow (e.g., 20). This program can truncate the series to a smaller power. If you just want to compute accurate geodesics and are not interested in the area, then use elliptic integrals (exact : true) and leave maxpow at some small value (6 or 8). To use this program, (1) Edit the file name for the series "geod30.lsp" to reflect the value of maxpow that you used. (2) Set fpprec (the number of decimal digits of precision). (3) Set exact (true for elliptic integrals, false for series). (4) If exact = false, set the order of the series you want to use, by replacing the "20" in min(maxpow,20) below. (5) Start maxima and run load("geodesic.mac")$ (If you want to change fpprec, exact, or the order of the series, you should edit this file and run this command again.) (6) Define an ellipsoid with g:geod_init(radius, flattening)$ The ellipsoids wgs84 and grs80 are pre-defined. (7) To solve a direct problem, run geod_direct(ellipsoid, lat1, lon1, azi1, s12); e.g., geod_direct(wgs84, -30, 0, 45, 1b7); This returns a list, [a12, lat2, lon2, azi2, s12, m12, M12, M21, S12], e.g., [9.00979560785581153132573611946234278938679821643464129576496b1, 3.795350501490084914310911431201705948430953526031024848204b1, 6.3403810943391419431089434638892210208040664981080107562114b1, 5.09217379721155238753530133334186917347878103616352193700526b1,1.0b7, 6.35984161356437923135381788735707599997546833534230510111197b6, -1.42475315175601879366432145888870774855600761387337970018946b-3, -7.47724030796032158868881196081763293754486469000152919698785b-4, 4.18229766667689593851692491830627309580972454148317773382384b12] (8) To solve an inverse problem, run geod_inverse(ellipsoid, lat1, lon1, lat2, lon2); e.g., geod_inverse(wgs84, -30, 0, 29.9b0, 179.9b0); This returns a list, [a12, s12, azi1, azi2, m12, M12, M21, S12], e.g., [1.79898924051433853264945993266804037171884583041584874134816b2, 1.99920903023269266279365620501124020214744990997998731526732b7, 1.70994569965518052741917124376016361591705298855243347424863b2, 8.99634915141674951478756137150809390696858860117887233257945b0, 6.04691725017600149958466836698242794713940408239599801996017b4, -9.95488849775559128989753386111595867497859420132749768254471b-1, -1.00448979492598025351148808245250847420628601706577993586242b0, -1.14721359300439474273586680489951630835335433189068889945966b14] (9) Use geod_polygonarea(ellipsoid, points) to compute polygon areas. (10) The interface is copied from the C library for geodesics which is documented at https://geographiclib.sourceforge.io/html/C/index.html */ /* The corresponding version of GeographicLib */ geod_version:[1,49,0]$ /* Load series created by geod.mac (NEED TO UNCOMMENT THE LAST LINE OF geod.mac TO GENERATE THIS FILE). */ load("geod30.lsp")$ /* Edit to reflect precision and order of the series to be used */ ( fpprec:60, exact:true, GEOGRAPHICLIB_GEODESIC_ORDER:if exact then maxpow else min(maxpow,20))$ if exact then load("ellint.mac")$ ( nA1 :GEOGRAPHICLIB_GEODESIC_ORDER, nC1 :GEOGRAPHICLIB_GEODESIC_ORDER, nC1p :GEOGRAPHICLIB_GEODESIC_ORDER, nA2 :GEOGRAPHICLIB_GEODESIC_ORDER, nC2 :GEOGRAPHICLIB_GEODESIC_ORDER, nA3 :GEOGRAPHICLIB_GEODESIC_ORDER, nA3x :nA3, nC3 :GEOGRAPHICLIB_GEODESIC_ORDER, nC3x :((nC3 * (nC3 - 1)) / 2), nC4 :GEOGRAPHICLIB_GEODESIC_ORDER, nC4x :((nC4 * (nC4 + 1)) / 2) )$ taylordepth:5$ jtaylor(expr,var1,var2,ord):=expand(subst([zz=1], ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord))))$ ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$ if not exact then ( A1m1f(eps):=''((horner(ataylor(A1*(1-eps)-1,eps,nA1)) +eps)/(1-eps)), C1f(eps):=''(block([l:[]],for i:1 thru nC1 do l:endcons(horner(ataylor(C1[i],eps,nC1)),l),l)), C1pf(eps):=''(block([l:[]],for i:1 thru nC1p do l:endcons(horner(ataylor(C1p[i],eps,nC1p)),l),l)), A2m1f(eps):=''((horner(ataylor(A2*(1+eps)-1,eps,nA2)) -eps)/(1+eps)), C2f(eps):=''(block([l:[]],for i:1 thru nC2 do l:endcons(horner(ataylor(C2[i],eps,nC2)),l),l)), A3coeff(n):= ''(block([q:jtaylor(A3,n,eps,nA3-1),l:[]], for i:0 thru nA3-1 do l:endcons(horner(coeff(q,eps,i)),l), l)), C3coeff(n):= ''(block([q,l:[]], for m:1 thru nC3-1 do ( q:jtaylor(C3[m],n,eps,nC3-1), for j:m thru nC3-1 do l:endcons(horner(coeff(q,eps,j)),l)), l)))$ C4coeff(n):= ''(block([q,l:[]], for m:0 thru nC4-1 do ( q:jtaylor(C4[m],n,eps,nC4-1), for j:m thru nC4-1 do l:endcons(horner(coeff(q,eps,j)),l)), l))$ ( digits:floor((fpprec-1)*log(10.0)/log(2.0)), epsilon : 0.5b0^(digits - 1), realmin : 0.1b0^(3*fpprec), pi : bfloat(%pi), maxit1 : 100, maxit2 : maxit1 + digits + 10, tiny : sqrt(realmin), tol0 : epsilon, tol1 : 200 * tol0, tol2 : sqrt(tol0), tolb : tol0 * tol2, xthresh : 1000 * tol2, degree : pi/180, NaN : 'nan )$ sq(x):=x^2$ hypotx(x, y):=sqrt(x * x + y * y)$ /* doesn't handle -0.0 */ copysign(x, y):=abs(x) * (if y < 0b0 then -1 else 1)$ /* pow(x,y):=x^y$ cbrtx(x) := block([y:pow(abs(x), 1/3b0)], if x < 0b0 then -y else y)$ */ cbrtx(x):=x^(1/3)$ sumx(u, v):=block([s,up,vpp,t], s : u + v, up : s - v, vpp : s - up, up : up-u, vpp : vpp-v, t : -(up + vpp), [s,t])$ swapx(x, y):=[y,x]$ norm2(x, y):=block([r : hypotx(x, y)], [x/r, y/r])$ AngNormalize(x):=block([y:x-360b0*floor(x/360b0+0.5)], if y <= -180b0 then y+360b0 else if y <= 180b0 then y else y-360b0)$ AngDiff(x, y) := block([t,d,r:sumx(AngNormalize(-x),AngNormalize(y))], d:AngNormalize(r[1]), t:r[2], sumx(if d = 180b0 and t > 0b0 then -180b0 else d, t))$ AngRound(x) := block([z:1/16b0, y:abs(x)], if x = 0b0 then return(x), y : if y < z then z - (z - y) else y, if x < 0b0 then -y else y)$ sincosdx(x):=block([r,q:floor(x/90b0 + 0.5),s,c], r:(x-q*90b0)*degree, s:sin(r), c:cos(r), q:mod(q,4), r: if q = 0 then [ s, c] elseif q = 1 then [ c, -s] elseif q = 2 then [-s, -c] else [-c, s], if x # 0b0 then r:0b0+r, r)$ atan2dx(y,x):=block([q,xx,yy,ang], if abs(y) > abs(x) then (xx:y, yy:x, q:2) else (xx:x, yy:y, q:0), if xx < 0 then (xx:-xx, q:q+1), ang:atan2(yy, xx) / degree, if q = 0 then ang elseif q = 1 then (if y >= 0b0 then 180b0 else -180b0) - ang elseif q = 2 then 90 - ang else -90 + ang)$ /* Indices in geodesic struct */ block([i:0], g_a:(i:i+1), g_f:(i:i+1), g_f1:(i:i+1), g_e2:(i:i+1), g_ep2:(i:i+1), g_n:(i:i+1), g_b:(i:i+1), g_c2:(i:i+1), g_etol2:(i:i+1), g_A3x:(i:i+1), g_C3x:(i:i+1), g_C4x:(i:i+1) )$ geod_init(a, f):= (a:bfloat(a),f:bfloat(f), block([f1,e2,ep2,n,b,c2,etol2], f1:1-f, e2:f*(2-f), ep2:e2/f1^2, n:f/(2-f), b:a*f1, c2 : (sq(a) + sq(b) * (if e2 = 0b0 then 1b0 else (if e2 > 0b0 then atanh(sqrt(e2)) else atan(sqrt(-e2))) / sqrt(abs(e2))))/2, /* authalic radius squared */ /* The sig12 threshold for "really short". Using the auxiliary sphere solution with dnm computed at (bet1 + bet2) / 2, the relative error in the azimuth consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2. (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000. For a given f and sig12, the max error occurs for lines near the pole. If the old rule for computing dnm = (dn1 + dn2)/2 is used, then the error increases by a factor of 2.) Setting this equal to epsilon gives sig12 = etol2. Here 0.1 is a safety factor (error decreased by 100) and max(0.001, abs(f)) stops etol2 getting too large in the nearly spherical case. */ etol2 : 0.1b0 * tol2 / sqrt( max(0.001b0, abs(f)) * min(1b0, 1-f/2) / 2 ), [ a, f, f1, e2, ep2, n, b, c2, etol2, if exact then [] else bfloat(A3coeff(n)), if exact then [] else bfloat(C3coeff(n)), bfloat(C4coeff(n))]))$ /* Indices into geodesicline struct */ block([i:0], l_lat1:(i:i+1), l_lon1:(i:i+1), l_azi1:(i:i+1), l_a:(i:i+1), l_f:(i:i+1), l_b:(i:i+1), l_c2:(i:i+1), l_f1:(i:i+1), l_salp0:(i:i+1), l_calp0:(i:i+1), l_k2:(i:i+1), l_salp1:(i:i+1), l_calp1:(i:i+1), l_ssig1:(i:i+1), l_csig1:(i:i+1), l_dn1:(i:i+1), l_stau1:(i:i+1), l_ctau1:(i:i+1), l_somg1:(i:i+1), l_comg1:(i:i+1), if exact then (l_e2:(i:i+1), l_cchi1:(i:i+1), l_A4:(i:i+1), l_B41:(i:i+1), l_E0:(i:i+1), l_D0:(i:i+1), l_H0:(i:i+1), l_E1:(i:i+1), l_D1:(i:i+1), l_H1:(i:i+1), l_C4a:(i:i+1), l_E:(i:i+1), e_k2:1, e_alpha2:2, e_ec:3, e_dc:4, e_hc:5) else (l_A1m1:(i:i+1), l_A2m1:(i:i+1), l_A3c:(i:i+1), l_B11:(i:i+1), l_B21:(i:i+1), l_B31:(i:i+1), l_A4:(i:i+1), l_B41:(i:i+1), l_C1a:(i:i+1), l_C1pa:(i:i+1), l_C2a:(i:i+1), l_C3a:(i:i+1), l_C4a:(i:i+1) ))$ Ef(k2, alpha2):=if exact then [k2, alpha2, ec(k2), dc(k2), hc(k2, alpha2)] else []$ geod_lineinit(g,lat1,lon1,azi1):=block([a, f, b, c2, f1, salp0, calp0, k2, salp1, calp1, ssig1, csig1, dn1, stau1, ctau1, somg1, comg1, A1m1, A2m1, A3c, B11, B21, B31, A4, B41, C1a, C1pa, C2a, C3a, C4a, cbet1, sbet1, eps, e2, cchi1, A4, B41, E0, D0, H0, E1, D1, H1, C4a, E], lat1:bfloat(lat1),lon1:bfloat(lon1), azi1:bfloat(azi1), a : g[g_a], f : g[g_f], b : g[g_b], c2 : g[g_c2], f1 : g[g_f1], e2 : g[g_e2], lat1 : lat1, /* If caps is 0 assume the standard direct calculation caps = (caps ? caps : GEOD_DISTANCE_IN | GEOD_LONGITUDE) | GEOD_LATITUDE | GEOD_AZIMUTH, Always allow latitude and azimuth Guard against underflow in salp0 */ azi1 : AngNormalize(azi1), /* Don't normalize lon1... */ block([t:sincosdx(AngRound(azi1))], salp1:t[1], calp1:t[2]), block([t:sincosdx(AngRound(lat1))], sbet1:t[1], cbet1:t[2]), sbet1 : f1 * sbet1, block([t:norm2(sbet1, cbet1)], sbet1:t[1], cbet1:t[2]), /* Ensure cbet1 = +epsilon at poles */ cbet1 = max(tiny, cbet1), dn1 : sqrt(1 + g[g_ep2] * sq(sbet1)), /* 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 : hypotx(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 : if sbet1 # 0b0 or calp1 # 0b0 then cbet1 * calp1 else 1b0, /* Without normalization we have schi1 = somg1. */ cchi1 : f1 * dn1 * comg1, /* sig1 in (-pi, pi] */ block([t:norm2(ssig1, csig1)], ssig1:t[1], csig1:t[2]), /* norm2 (somg1, comg1); -- don't need to normalize! norm2 (schi1, cchi1); -- don't need to normalize! */ k2 : sq(calp0) * g[g_ep2], eps : k2 / (2 * (1 + sqrt(1 + k2)) + k2), E:Ef(-k2,-g[g_ep2]), block([s,c], if exact then (E0 : E[e_ec]/(pi/2), E1 : deltae(ssig1,csig1,dn1,E[e_k2],E[e_ec]), s:sin(E1),c:cos(E1)) else ( A1m1 : A1m1f(eps), C1a : C1f(eps), B11 : SinCosSeries(true, ssig1, csig1, C1a), 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 exact then (D0 : E[e_dc]/(pi/2), D1 : deltad(ssig1, csig1, dn1, E[e_k2], E[e_dc]), H0 : E[e_hc]/(pi/2), H1 : deltah(ssig1, csig1, dn1, E[e_k2], E[e_alpha2], E[e_hc])) else ( C1pa: C1pf(eps), A2m1 : A2m1f(eps), C2a : C2f(eps), B21 : SinCosSeries(true, ssig1, csig1, C2a), C3a : C3f(g, eps), A3c : -f * salp0 * A3f(g, eps), B31 : SinCosSeries(true, ssig1, csig1, C3a)), C4a : C4f(g, eps), /* Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0) */ A4 : sq(a) * calp0 * salp0 * e2, B41 : SinCosSeries(false, ssig1, csig1, C4a), if exact then [ lat1, lon1, azi1, a, f, b, c2, f1, salp0, calp0, k2, salp1, calp1, ssig1, csig1, dn1, stau1, ctau1, somg1, comg1, e2, cchi1, A4, B41, E0, D0, H0, E1, D1, H1, C4a, E] else [ lat1, lon1, azi1, a, f, b, c2, f1, salp0, calp0, k2, salp1, calp1, ssig1, csig1, dn1, stau1, ctau1, somg1, comg1, A1m1, A2m1, A3c, B11, B21, B31, A4, B41, C1a, C1pa, C2a, C3a, C4a] )$ /* Return [a12, lat2, lon2, azi2, s12, m12, M12, M21, S12] */ geod_genposition(l, arcmode, s12_a12):=block( [ lat2 : 0, lon2 : 0, azi2 : 0, s12 : 0, m12 : 0, M12 : 0, M21 : 0, S12 : 0, /* Avoid warning about uninitialized B12. */ sig12, ssig12, csig12, B12 : 0, E2 : 0, AB1 : 0, omg12, lam12, lon12, ssig2, csig2, sbet2, cbet2, somg2, comg2, salp2, calp2, dn2, E], s12_a12 : bfloat(s12_a12), if (arcmode) then ( /* Interpret s12_a12 as spherical arc length */ sig12 : s12_a12 * degree, block([t:sincosdx(s12_a12)], ssig12:t[1], csig12:t[2])) else block([tau12 : s12_a12 / (l[l_b] * (if exact then l[l_E0] else (1 + l[l_A1m1]))),s,c], /* Interpret s12_a12 as distance */ s : sin(tau12), c : cos(tau12), /* tau2 = tau1 + tau12 */ if exact then (E2 : - deltaeinv(l[l_stau1] * c + l[l_ctau1] * s, l[l_ctau1] * c - l[l_stau1] * s, l[l_E][e_k2], l[l_E][e_ec]), sig12 : tau12 - (E2 - l[l_E1]), ssig12 : sin(sig12), csig12 : cos(sig12)) else (B12 : - SinCosSeries(true, l[l_stau1] * c + l[l_ctau1] * s, l[l_ctau1] * c - l[l_stau1] * s, l[l_C1pa]), sig12 : tau12 - (B12 - l[l_B11]), ssig12 : sin(sig12), csig12 : cos(sig12), if abs(l[l_f]) > 0.01 then block( /* Reverted distance series is inaccurate for |f| > 1/100, so correct sig12 with 1 Newton iteration. The following table shows the approximate maximum error for a = WGS_a() and various f relative to GeodesicExact. erri = the error in the inverse solution (nm) errd = the error in the direct solution (series only) (nm) errda = the error in the direct solution (series + 1 Newton) (nm) f erri errd errda -1/5 12e6 1.2e9 69e6 -1/10 123e3 12e6 765e3 -1/20 1110 108e3 7155 -1/50 18.63 200.9 27.12 -1/100 18.63 23.78 23.37 -1/150 18.63 21.05 20.26 1/150 22.35 24.73 25.83 1/100 22.35 25.03 25.31 1/50 29.80 231.9 30.44 1/20 5376 146e3 10e3 1/10 829e3 22e6 1.5e6 1/5 157e6 3.8e9 280e6 */ [ssig2 : l[l_ssig1] * csig12 + l[l_csig1] * ssig12, csig2 : l[l_csig1] * csig12 - l[l_ssig1] * ssig12, serr], B12 : SinCosSeries(true, ssig2, csig2, l[l_C1a]), serr : (1 + l[l_A1m1]) * (sig12 + (B12 - l[l_B11])) - s12_a12 / l[l_b], sig12 : sig12 - serr / sqrt(1 + l[l_k2] * sq(ssig2)), ssig12 : sin(sig12), csig12 : cos(sig12) /* Update B12 below */ ))), /* sig2 = sig1 + sig12 */ ssig2 : l[l_ssig1] * csig12 + l[l_csig1] * ssig12, csig2 : l[l_csig1] * csig12 - l[l_ssig1] * ssig12, dn2 : sqrt(1 + l[l_k2] * sq(ssig2)), if exact then (if arcmode then E2 : deltae(ssig2, csig2, dn2, l[l_E][e_k2], l[l_E][e_ec]), AB1 : l[l_E0] * (E2 - l[l_E1])) else (if arcmode or abs(l[l_f]) > 0.01b0 then B12 : SinCosSeries(true, ssig2, csig2, l[l_C1a]), AB1 : (1 + l[l_A1m1]) * (B12 - l[l_B11])), /* sin(bet2) = cos(alp0) * sin(sig2) */ sbet2 : l[l_calp0] * ssig2, /* Alt: cbet2 = hypot(csig2, salp0 * ssig2); */ cbet2 : hypotx(l[l_salp0], l[l_calp0] * csig2), if cbet2 = 0b0 then /* I.e., salp0 = 0, csig2 = 0. Break the degeneracy in this case */ cbet2 : csig2 : tiny, if not exact then ( /* tan(omg2) = sin(alp0) * tan(sig2) */ somg2 : l[l_salp0] * ssig2, comg2 : csig2), /* No need to normalize */ /* tan(alp0) = cos(sig2)*tan(alp2) */ salp2 : l[l_salp0], calp2 : l[l_calp0] * csig2, /* No need to normalize */ E : copysign(1b0, l[l_salp0]), if not exact then /* omg12 = omg2 - omg1 */ omg12 : E * (sig12 - (atan2( ssig2, csig2) - atan2( l[l_ssig1], l[l_csig1])) + (atan2(E*somg2, comg2) - atan2(E*l[l_somg1], l[l_comg1]))), s12 : if arcmode then l[l_b] * ((if exact then l[l_E0] else (1 + l[l_A1m1])) * sig12 + AB1) else s12_a12, if exact then block([somg2:l[l_salp0] * ssig2, comg2 : csig2, /* No need to normalize */ cchi2], /* Without normalization we have schi2 = somg2. */ cchi2 : l[l_f1] * dn2 * comg2, lam12 : E * (sig12 - (atan2( ssig2, csig2) - atan2( l[l_ssig1], l[l_csig1])) + (atan2(E*somg2, cchi2) - atan2(E*l[l_somg1], l[l_cchi1]))) - l[l_e2]/l[l_f1] * l[l_salp0] * l[l_H0] * (sig12 + deltah(ssig2, csig2, dn2, l[l_E][e_k2], l[l_E][e_alpha2], l[l_E][e_hc]) - l[l_H1] ) ) else lam12 : omg12 + l[l_A3c] * ( sig12 + (SinCosSeries(true, ssig2, csig2, l[l_C3a]) - l[l_B31])), lon12 : lam12 / degree, /* Don't normalize lon2... */ lon2 : l[l_lon1] + lon12, lat2 : atan2dx(sbet2, l[l_f1] * cbet2), azi2 : atan2dx(salp2, calp2), block([B22, AB2, J12], if exact then J12 : l[l_k2] * l[l_D0] * (sig12 + deltad(ssig2, csig2, dn2, l[l_E][e_k2], l[l_E][e_dc]) - l[l_D1]) else ( B22 : SinCosSeries(true, ssig2, csig2, l[l_C2a]), AB2 : (1 + l[l_A2m1]) * (B22 - l[l_B21]), J12 : (l[l_A1m1] - l[l_A2m1]) * sig12 + (AB1 - AB2)), /* Add parens around (csig1 * ssig2) and (ssig1 * csig2) to ensure accurate cancellation in the case of coincident points. */ m12 : l[l_b] * ((dn2 * (l[l_csig1] * ssig2) - l[l_dn1] * (l[l_ssig1] * csig2)) - l[l_csig1] * csig2 * J12), block([t : l[l_k2] * (ssig2 - l[l_ssig1]) * (ssig2 + l[l_ssig1]) / (l[l_dn1] + dn2)], M12 : csig12 + (t * ssig2 - csig2 * J12) * l[l_ssig1] / l[l_dn1], M21 : csig12 - (t * l[l_ssig1] - l[l_csig1] * J12) * ssig2 / dn2)), block([ B42 : SinCosSeries(false, ssig2, csig2, l[l_C4a]), salp12, calp12], if l[l_calp0] = 0b0 or l[l_salp0] = 0b0 then ( /* alp12 = alp2 - alp1, used in atan2 so no need to normalize */ salp12 : salp2 * l[l_calp1] - calp2 * l[l_salp1], calp12 : calp2 * l[l_calp1] + salp2 * l[l_salp1]) 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 : l[l_calp0] * l[l_salp0] * ( if csig12 <= 0b0 then l[l_csig1] * (1 - csig12) + ssig12 * l[l_ssig1] else ssig12 * (l[l_csig1] * ssig12 / (1 + csig12) + l[l_ssig1])), calp12 : sq(l[l_salp0]) + sq(l[l_calp0]) * l[l_csig1] * csig2), S12 : l[l_c2] * atan2(salp12, calp12) + l[l_A4] * (B42 - l[l_B41])), [if arcmode then s12_a12 else sig12 / degree, lat2, lon2, azi2, s12, m12, M12, M21, S12])$ geod_position(l, s12) := geod_genposition(l, false, s12)$ geod_gendirect(g, lat1, lon1, azi1, arcmode, s12_a12):= block([l:geod_lineinit(g, lat1, lon1, azi1)], geod_genposition(l, arcmode, s12_a12))$ geod_direct(g, lat1, lon1, azi1, s12):= geod_gendirect(g, lat1, lon1, azi1, false, s12)$ /* Return [a12, s12, azi1, azi2, m12, M12, M21, S12] */ geod_geninverse(g, lat1, lon1, lat2, lon2):=block( [s12 : 0b0, azi1 : 0b0, azi2 : 0b0, m12 : 0b0, M12 : 0b0, M21 : 0b0, S12 : 0b0, lon12, lon12s, latsign, lonsign, swapp, sbet1, cbet1, sbet2, cbet2, s12x : 0b0, m12x : 0b0, dn1, dn2, lam12, slam12, clam12, a12 : 0b0, sig12, calp1 : 0b0, salp1 : 0b0, calp2 : 0b0, salp2 : 0b0, meridian, omg12 : 0b0, somg12 : 2b0, comg12, /* Initialize for the meridian. No longitude calculation is done in this case to let the parameter default to 0. */ E : Ef(-g[g_ep2], 0b0)], lat1:bfloat(lat1),lon1:bfloat(lon1), lat2:bfloat(lat2),lon2:bfloat(lon2), /* Compute longitude difference (AngDiff does this carefully). Result is in [-180, 180] but -180 is only for west-going geodesics. 180 is for east-going and meridional geodesics. */ lon12 : AngDiff(lon1, lon2), lon12s:lon12[2], lon12:lon12[1], /* Make longitude difference positive. */ lonsign : if lon12 >= 0b0 then 1 else -1, /* If very close to being on the same half-meridian, then make it so. */ lon12 : lonsign * AngRound(lon12), lon12s : AngRound((180 - lon12) - lonsign * lon12s), lam12 : lon12 * degree, if lon12 > 90 then block([t:sincosdx(lon12s)], slam12:t[1], clam12:-t[2]) else block([t:sincosdx(lon12)], slam12:t[1], clam12:t[2]), /* If really close to the equator, treat as on equator. */ lat1 : AngRound(lat1), lat2 : AngRound(lat2), /* Swap points so that point with higher (abs) latitude is point 1 */ swapp : if abs(lat1) >= abs(lat2) then 1 else -1, if swapp < 0 then (lonsign : -lonsign, block([t:swapx(lat1, lat2)], lat1:t[1], lat2:t[2])), /* Make lat1 <= 0 */ latsign : if lat1 < 0b0 then 1 else -1, lat1 : lat1 * latsign, lat2 : lat2 * latsign, /* Now we have 0 <= lon12 <= 180 -90 <= lat1 <= 0 lat1 <= lat2 <= -lat1 longsign, swapp, latsign register the transformation to bring the coordinates to this canonical form. In all cases, 1 means no change was made. We make these transformations so that there are few cases to check, e.g., on verifying quadrants in atan2. In addition, this enforces some symmetries in the results returned. */ block([t:sincosdx(lat1)], sbet1:t[1], cbet1:t[2]), sbet1 : g[g_f1] * sbet1, block([t:norm2(sbet1, cbet1)], sbet1:t[1], cbet1:t[2]), /* Ensure cbet1 = +epsilon at poles */ cbet1 = max(tiny, cbet1), block([t:sincosdx(lat2)], sbet2:t[1], cbet2:t[2]), sbet2 : g[g_f1] * sbet2, block([t:norm2(sbet2, cbet2)], sbet2:t[1], cbet2:t[2]), /* Ensure cbet2 = +epsilon at poles */ cbet2 = max(tiny, cbet2), /* If cbet1 < -sbet1, then cbet2 - cbet1 is a sensitive measure of the |bet1| - |bet2|. Alternatively (cbet1 >= -sbet1), abs(sbet2) + sbet1 is a better measure. This logic is used in assigning calp2 in Lambda12. Sometimes these quantities vanish and in that case we force bet2 = +/- bet1 exactly. An example where is is necessary is the inverse problem 48.522876735459 0 -48.52287673545898293 179.599720456223079643 which failed with Visual Studio 10 (Release and Debug) */ if cbet1 < -sbet1 then ( if cbet2 = cbet1 then sbet2 : if sbet2 < 0b0 then sbet1 else -sbet1 ) else ( if abs(sbet2) = -sbet1 then cbet2 : cbet1 ), dn1 : sqrt(1 + g[g_ep2] * sq(sbet1)), dn2 : sqrt(1 + g[g_ep2] * sq(sbet2)), meridian : is(lat1 = -90b0 or slam12 = 0b0), if meridian then block( /* Endpoints are on a single full meridian, so the geodesic might lie on a meridian. */ [ ssig1, csig1, ssig2, csig2], calp1 : clam12, salp1 : slam12, /* Head to the target longitude */ calp2 : 1b0, salp2 : 0b0, /* At the target we're heading north */ /* tan(bet) : tan(sig) * cos(alp) */ ssig1 : sbet1, csig1 : calp1 * cbet1, ssig2 : sbet2, csig2 : calp2 * cbet2, /* sig12 = sig2 - sig1 */ sig12 : atan2(0b0 + max(0b0, csig1 * ssig2 - ssig1 * csig2), csig1 * csig2 + ssig1 * ssig2), block([r], r:Lengths(g, g[g_n], E, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2), s12x:r[1], m12x:r[2], M12:r[4], M21:r[5]), /* Add the check for sig12 since zero length geodesics might yield m12 < 0. Test case was echo 20.001 0 20.001 0 | GeodTest -i In fact, we will have sig12 > pi/2 for meridional geodesic which is not a shortest path. */ if sig12 < 1b0 or m12x >= 0b0 then ( if sig12 < 3 * tiny then sig12 : m12x : s12x : 0b0, m12x : m12x * g[g_b], s12x : s12x * g[g_b], a12 : sig12 / degree ) else /* m12 < 0, i.e., prolate and too close to anti-podal */ meridian : false ), if not meridian and sbet1 = 0b0 and /* and sbet2 == 0 */ /* Mimic the way Lambda12 works with calp1 = 0 */ (g[g_f] <= 0b0 or lon12s >= g[g_f] * 180) then ( /* Geodesic runs along equator */ calp1 : calp2 : 0b0, salp1 : salp2 : 1b0, s12x : g[g_a] * lam12, sig12 : omg12 : lam12 / g[g_f1], m12x : g[g_b] * sin(sig12), M12 : M21 : cos(sig12), a12 : lon12 / g[g_f1] ) else if not meridian then block([dnm], /* Now point1 and point2 belong within a hemisphere bounded by a meridian and geodesic is neither meridional or equatorial. Figure a starting point for Newton's method */ block([r], r : InverseStart(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2, lam12, slam12, clam12), sig12:r[1], salp1:r[2], calp1:r[3], salp2:r[4], calp2:r[5], dnm:r[6]), if sig12 >= 0b0 then ( /* Short lines (InverseStart sets salp2, calp2, dnm) */ s12x : sig12 * g[g_b] * dnm, m12x : sq(dnm) * g[g_b] * sin(sig12 / dnm), M12 : M21 : cos(sig12 / dnm), a12 : sig12 / degree, omg12 : lam12 / (g[g_f1] * dnm)) else block( /* Newton's method. This is a straightforward solution of f(alp1) = lambda12(alp1) - lam12 = 0 with one wrinkle. f(alp) has exactly one root in the interval (0, pi) and its derivative is positive at the root. Thus f(alp) is positive for alp > alp1 and negative for alp < alp1. During the course of the iteration, a range (alp1a, alp1b) is maintained which brackets the root and with each evaluation of f(alp) the range is shrunk, if possible. Newton's method is restarted whenever the derivative of f is negative (because the new value of alp1 is then further from the solution) or if the new estimate of alp1 lies outside (0,pi); in this case, the new starting guess is taken to be (alp1a + alp1b) / 2. */ [ssig1 : 0b0, csig1 : 0b0, ssig2 : 0b0, csig2 : 0b0, eps : 0b0, domg12 : 0b0, numit : 0, /* Bracketing range */ salp1a : tiny, calp1a : 1b0, salp1b : tiny, calp1b : -1b0, tripn : false, tripb : false, contflag, dv, v], for i:0 thru maxit2-1 do ( contflag:false, numit:i, /* the WGS84 test set: mean : 1.47, sd = 1.25, max = 16 WGS84 and random input: mean = 2.85, sd = 0.60 */ block([r], r : Lambda12(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1, slam12, clam12, is(numit < maxit1)), v : r[1], salp2:r[2], calp2:r[3], sig12:r[4], ssig1:r[5], csig1:r[6], ssig2:r[7], csig2:r[8], if exact then E:r[9] else eps:r[9], domg12:r[10], dv:r[11]), /* 2 * tol0 is approximately 1 ulp for a number in [0, pi]. */ /* Reversed test to allow escape with NaNs */ if tripb or not(abs(v) >= (if tripn then 8 else 1) * tol0) then return(true), /* Update bracketing values */ if v > 0b0 and (numit > maxit1 or calp1/salp1 > calp1b/salp1b) then ( salp1b : salp1, calp1b : calp1 ) else if v < 0b0 and (numit > maxit1 or calp1/salp1 < calp1a/salp1a) then ( salp1a : salp1, calp1a : calp1 ), if numit < maxit1 and dv > 0b0 then block( [dalp1, sdalp1, cdalp1,nsalp1], dalp1 : -v/dv, sdalp1 : sin(dalp1), cdalp1 : cos(dalp1), nsalp1 : salp1 * cdalp1 + calp1 * sdalp1, if nsalp1 > 0b0 and abs(dalp1) < pi then ( calp1 : calp1 * cdalp1 - salp1 * sdalp1, salp1 : nsalp1, block([t:norm2(salp1, calp1)], salp1:t[1], calp1:t[2]), /* In some regimes we don't get quadratic convergence because slope -> 0. So use convergence conditions based on epsilon instead of sqrt(epsilon). */ tripn : is(abs(v) <= 16 * tol0), contflag:true ) ), if not contflag then ( /* Either dv was not positive or updated value was outside legal range. Use the midpoint of the bracket as the next estimate. This mechanism is not needed for the WGS84 ellipsoid, but it does catch problems with more eccentric ellipsoids. Its efficacy is such for the WGS84 test set with the starting guess set to alp1 = 90deg: the WGS84 test set: mean = 5.21, sd = 3.93, max = 24 WGS84 and random input: mean = 4.74, sd = 0.99 */ salp1 : (salp1a + salp1b)/2, calp1 : (calp1a + calp1b)/2, block([t:norm2(salp1, calp1)], salp1:t[1], calp1:t[2]), tripn : false, tripb : is(abs(salp1a - salp1) + (calp1a - calp1) < tolb or abs(salp1 - salp1b) + (calp1 - calp1b) < tolb)) ), block([r], r:Lengths(g, eps, E, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2), s12x:r[1], m12x:r[2], M12:r[4], M21:r[5]), m12x : m12x * g[g_b], s12x : s12x * g[g_b], a12 : sig12 / degree, block([sdomg12 : sin(domg12), cdomg12 : cos(domg12)], somg12 : slam12 * cdomg12 - clam12 * sdomg12, comg12 : clam12 * cdomg12 + slam12 * sdomg12) ) ), s12 : 0b0 + s12x, /* Convert -0 to 0 */ m12 : 0b0 + m12x, /* Convert -0 to 0 */ block( /* From Lambda12: sin(alp1) * cos(bet1) = sin(alp0) */ [ salp0 : salp1 * cbet1, calp0 : hypotx(calp1, salp1 * sbet1), /* calp0 > 0 */ alp12], if calp0 # 0b0 and salp0 # 0b0 then block( /* From Lambda12: tan(bet) = tan(sig) * cos(alp) */ [ssig1 : sbet1, csig1 : calp1 * cbet1, ssig2 : sbet2, csig2 : calp2 * cbet2, k2 : sq(calp0) * g[g_ep2], eps, /* Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0). */ A4 : sq(g[g_a]) * calp0 * salp0 * g[g_e2], Ca, B41, B42], eps : k2 / (2 * (1 + sqrt(1 + k2)) + k2), block([t:norm2(ssig1, csig1)], ssig1:t[1], csig1:t[2]), block([t:norm2(ssig2, csig2)], ssig2:t[1], csig2:t[2]), Ca : C4f(g, eps), B41 : SinCosSeries(false, ssig1, csig1, Ca), B42 : SinCosSeries(false, ssig2, csig2, Ca), S12 : A4 * (B42 - B41)) else S12 : 0, /* Avoid problems with indeterminate sig1, sig2 on equator */ if not meridian and somg12 > 1 then (somg12 : sin(omg12), comg12 : cos(omg12)), if not meridian and /* omg12 < 3/4 * pi */ comg12 > -0.7071b0 and /* Long difference not too big */ sbet2 - sbet1 < 1.75b0 then block( /* Lat difference not too big */ /* Use tan(Gamma/2) = tan(omg12/2) * (tan(bet1/2)+tan(bet2/2))/(1+tan(bet1/2)*tan(bet2/2)) with tan(x/2) = sin(x)/(1+cos(x)) */ [domg12 : 1 + comg12, dbet1 : 1 + cbet1, dbet2 : 1 + cbet2], alp12 : 2 * atan2( somg12 * ( sbet1 * dbet2 + sbet2 * dbet1 ), domg12 * ( sbet1 * sbet2 + dbet1 * dbet2 ) )) else block( /* 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 = 0b0 and calp12 < 0b0 then ( salp12 : tiny * calp1, calp12 : -1b0), alp12 : atan2(salp12, calp12) ), S12 : S12 + g[g_c2] * alp12, S12 : S12 * swapp * lonsign * latsign, /* Convert -0 to 0 */ S12 : S12 + 0b0 ), /* Convert calp, salp to azimuth accounting for lonsign, swapp, latsign. */ if swapp < 0 then ( block([t:swapx(salp1, salp2)], salp1:t[1], salp2:t[2]), block([t:swapx(calp1, calp2)], calp1:t[1], calp2:t[2]), block([t:swapx(M12, M21)], M12:t[1], M21:t[2])), salp1 : salp1 * swapp * lonsign, calp1 : calp1 * swapp * latsign, salp2 : salp2 * swapp * lonsign, calp2 : calp2 * swapp * latsign, azi1 : atan2dx(salp1, calp1), azi2 : atan2dx(salp2, calp2), [a12, s12, azi1, azi2, m12, M12, M21, S12] )$ geod_inverse(g, lat1, lon1, lat2, lon2):= geod_geninverse(g, lat1, lon1, lat2, lon2)$ SinCosSeries(sinp, sinx, cosx, c):=block([n:length(c), ar, y0, y1, n2, k], /* Evaluate * y = sinp ? sum(c[i] * sin( 2*i * x), i, 1, n) : * sum(c[i] * cos((2*i-1) * x), i, 1, n) * using Clenshaw summation. where n = length(c) * Approx operation count = (n + 5) mult and (2 * n + 2) add */ /* 2 * cos(2 * x) */ ar : 2 * (cosx - sinx) * (cosx + sinx), /* accumulators for sum */ if mod(n, 2)=1 then (y0 : c[n], n2 : n - 1) else (y0 : 0b0, n2 : n), y1 : 0b0, /* Now n2 is even */ for k : n2 thru 1 step -2 do ( /* Unroll loop x 2, so accumulators return to their original role */ y1 : ar * y0 - y1 + c[k], y0 : ar * y1 - y0 + c[k-1]), if sinp then 2 * sinx * cosx * y0 /* sin(2 * x) * y0 */ else cosx * (y0 - y1) /* cos(x) * (y0 - y1) */ )$ /* Return [s12b, m12b, m0, M12, M21] */ Lengths(g, eps, E, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2):= block([Ca, s12b : 0b0, m12b : 0b0, m0 : 0b0, M12 : 0b0, M21 : 0b0, A1m1, AB1, A2m1, AB2, J12], /* Return m12b = (reduced length)/b; also calculate s12b = distance/b, and m0 = coefficient of secular term in expression for reduced length. */ if exact then ( m0 : - E[e_k2] * E[e_dc] / (pi/2), J12 : m0 * (sig12 + deltad(ssig2, csig2, dn2, E[e_k2], E[e_dc]) - deltad(ssig1, csig1, dn1, E[e_k2], E[e_dc])) ) else ( A1m1 : A1m1f(eps), Ca : C1f(eps), AB1 : (1 + A1m1) * (SinCosSeries(true, ssig2, csig2, Ca) - SinCosSeries(true, ssig1, csig1, Ca)), A2m1 : A2m1f(eps), Ca : C2f(eps), AB2 : (1 + A2m1) * (SinCosSeries(true, ssig2, csig2, Ca) - SinCosSeries(true, ssig1, csig1, Ca)), m0 : A1m1 - A2m1, J12 : m0 * sig12 + (AB1 - AB2)), /* Missing a factor of b. Add parens around (csig1 * ssig2) and (ssig1 * csig2) to ensure accurate cancellation in the case of coincident points. */ m12b : dn2 * (csig1 * ssig2) - dn1 * (ssig1 * csig2) - csig1 * csig2 * J12, /* Missing a factor of b */ s12b : if exact then E[e_ec] / (pi/2) * (sig12 + deltae(ssig2, csig2, dn2, E[e_k2], E[e_ec]) - deltae(ssig1, csig1, dn1, E[e_k2], E[e_ec])) else (1 + A1m1) * sig12 + AB1, block([csig12 : csig1 * csig2 + ssig1 * ssig2, t : g[g_ep2] * (cbet1 - cbet2) * (cbet1 + cbet2) / (dn1 + dn2)], M12 : csig12 + (t * ssig2 - csig2 * J12) * ssig1 / dn1, M21 : csig12 - (t * ssig1 - csig1 * J12) * ssig2 / dn2 ), [s12b, m12b, m0, M12, M21])$ Astroid(x, y):= block( /* Solve k^4+2*k^3-(x^2+y^2-1)*k^2-2*y^2*k-y^2 = 0 for positive root k. This solution is adapted from Geocentric::Reverse. */ [k, p : sq(x), q : sq(y), r], r : (p + q - 1) / 6, if not(q = 0b0 and r <= 0b0) then block( /* Avoid possible division by zero when r = 0 by multiplying equations for s and t by r^3 and r, resp. */ [S : p * q / 4, /* S = r^3 * s */ r2 : sq(r), r3, disc, u, v, uv, w], r3 : r * r2, /* The discriminant of the quadratic equation for T3. This is zero on the evolute curve p^(1/3)+q^(1/3) = 1 */ disc : S * (S + 2 * r3), u : r, v, uv, w, if disc >= 0b0 then block([T3 : S + r3, T], /* Pick the sign on the sqrt to maximize abs(T3). This minimizes loss of precision due to cancellation. The result is unchanged because of the way the T is used in definition of u. */ /* T3 = (r * t)^3 */ T3 : T3 + (if T3 < 0b0 then -sqrt(disc) else sqrt(disc)), /* N.B. cbrtx always returns the real root. cbrtx(-8) = -2. */ T : cbrtx(T3), /* T = r * t */ /* T can be zero, but then r2 / T -> 0. */ u : u + T + (if T # 0b0 then r2 / T else 0b0)) else block( /* T is complex, but the way u is defined the result is real. */ [ang : atan2(sqrt(-disc), -(S + r3))], /* There are three possible cube roots. We choose the root which avoids cancellation. Note that disc < 0 implies that r < 0. */ u : u + 2 * r * cos(ang / 3)), v : sqrt(sq(u) + q), /* guaranteed positive */ /* Avoid loss of accuracy when u < 0. */ uv : if u < 0b0 then q / (v - u) else u + v, /* u+v, guaranteed positive */ w : (uv - q) / (2 * v), /* positive? */ /* Rearrange expression for k to avoid loss of accuracy due to subtraction. Division by 0 not possible because uv > 0, w >= 0. */ k : uv / (sqrt(uv + sq(w)) + w)) /* guaranteed positive */ else /* q == 0 && r <= 0 */ /* y = 0 with |x| <= 1. Handle this case directly. for y small, positive root is k = abs(y)/sqrt(1-x^2) */ k : 0b0, k)$ /* Return [sig12, salp1, calp1, salp2, calp2, dnm] */ InverseStart(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2, lam12, slam12, clam12):=block( [ salp1 : 0b0, calp1 : 0b0, salp2 : 0b0, calp2 : 0b0, dnm : 0b0, /* Return a starting point for Newton's method in salp1 and calp1 (function value is -1). If Newton's method doesn't need to be used, return also salp2 and calp2 and function value is sig12. */ sig12 : -1b0, /* Return value */ /* bet12 = bet2 - bet1 in [0, pi); bet12a = bet2 + bet1 in (-pi, 0] */ sbet12 : sbet2 * cbet1 - cbet2 * sbet1, cbet12 : cbet2 * cbet1 + sbet2 * sbet1, sbet12a : sbet2 * cbet1 + cbet2 * sbet1, shortline, somg12, comg12, ssig12, csig12, E:[]], shortline : is(cbet12 >= 0b0 and sbet12 < 0.5b0 and cbet2 * lam12 < 0.5b0), if shortline then block([sbetm2 : sq(sbet1 + sbet2), omg12], /* sin((bet1+bet2)/2)^2 * = (sbet1 + sbet2)^2 / ((sbet1 + sbet2)^2 + (cbet1 + cbet2)^2) */ sbetm2 : sbetm2 / (sbetm2 + sq(cbet1 + cbet2)), dnm : sqrt(1 + g[g_ep2] * sbetm2), omg12 : lam12 / (g[g_f1] * dnm), somg12 : sin(omg12), comg12 : cos(omg12)) else (somg12 : slam12, comg12 : clam12), salp1 : cbet2 * somg12, calp1 : if comg12 >= 0b0 then sbet12 + cbet2 * sbet1 * sq(somg12) / (1 + comg12) else sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12), ssig12 : hypotx(salp1, calp1), csig12 : sbet1 * sbet2 + cbet1 * cbet2 * comg12, if shortline and ssig12 < g[g_etol2] then ( /* really short lines */ salp2 : cbet1 * somg12, calp2 : sbet12 - cbet1 * sbet2 * (if comg12 >= 0 then sq(somg12) / (1 + comg12) else 1 - comg12), block([t:norm2(salp2, calp2)], salp2:t[1], calp2:t[2]), /* Set return value */ sig12 : atan2(ssig12, csig12)) else if abs(g[g_n]) > 0.1b0 or /* No astroid calc if too eccentric */ csig12 >= 0 or ssig12 >= 6 * abs(g[g_n]) * pi * sq(cbet1) then true /* Nothing to do, zeroth order spherical approximation is OK */ else block( /* Scale lam12 and bet2 to x, y coordinate system where antipodal point is at origin and singular point is at y = 0, x = -1. */ [y, lamscale, betscale,x, lam12x], lam12x : atan2(-slam12, -clam12), /* lam12 - pi */ if g[g_f] >= 0 then ( /* In fact f == 0 does not get here */ /* x = dlong, y = dlat */ if exact then block([k2 : sq(sbet1) * g[g_ep2]], E : Ef(-k2, -g[g_ep2]), lamscale : g[g_e2]/g[g_f1] * cbet1 * 2 * E[e_hc]) else block([k2 : sq(sbet1) * g[g_ep2],eps], eps : k2 / (2 * (1 + sqrt(1 + k2)) + k2), lamscale : g[g_f] * cbet1 * A3f(g, eps) * pi), betscale : lamscale * cbet1, x : lam12x / lamscale, y : sbet12a / betscale) else block( /* f < 0 */ /* x = dlat, y = dlong */ [cbet12a : cbet2 * cbet1 - sbet2 * sbet1,bet12a,m12b, m0], bet12a : atan2(sbet12a, cbet12a), /* In the case of lon12 = 180, this repeats a calculation made in * Inverse. */ block([r], r:Lengths(g, g[g_n], E, pi + bet12a, sbet1, -cbet1, dn1, sbet2, cbet2, dn2, cbet1, cbet2), m12b:r[2], m0:r[3]), x : -1 + m12b / (cbet1 * cbet2 * m0 * pi), betscale : if x < -0.01b0 then sbet12a / x else -g[g_f] * sq(cbet1) * pi, lamscale : betscale / cbet1, y : lam12x / lamscale), if y > -tol1 and x > -1 - xthresh then ( /* strip near cut */ if g[g_f] >= 0b0 then ( salp1 : min(1b0, -x), calp1 : - sqrt(1 - sq(salp1))) else ( calp1 : max(if x > -tol1 then 0b0 else -1b0, x), salp1 : sqrt(1 - sq(calp1)))) else block( /* Estimate alp1, by solving the astroid problem. Could estimate alpha1 = theta + pi/2, directly, i.e., calp1 = y/k; salp1 = -x/(1+k); for f >= 0 calp1 = x/(1+k); salp1 = -y/k; for f < 0 (need to check) However, it's better to estimate omg12 from astroid and use spherical formula to compute alp1. This reduces the mean number of Newton iterations for astroid cases from 2.24 (min 0, max 6) to 2.12 (min 0 max 5). The changes in the number of iterations are as follows: change percent 1 5 0 78 -1 16 -2 0.6 -3 0.04 -4 0.002 The histogram of iterations is (m = number of iterations estimating alp1 directly, n = number of iterations estimating via omg12, total number of trials = 148605): iter m n 0 148 186 1 13046 13845 2 93315 102225 3 36189 32341 4 5396 7 5 455 1 6 56 0 Because omg12 is near pi, estimate work with omg12a = pi - omg12 */ [k : Astroid(x, y),omg12a], omg12a : lamscale * ( if g[g_f] >= 0b0 then -x * k/(1 + k) else -y * (1 + k)/k ), somg12 : sin(omg12a), comg12 : -cos(omg12a), /* Update spherical estimate of alp1 using omg12 instead of lam12 */ salp1 : cbet2 * somg12, calp1 : sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12))), if salp1 > 0 then /* Sanity check on starting guess */ block([t:norm2(salp1, calp1)], salp1:t[1], calp1:t[2]) else ( salp1 : 1b0, calp1 : 0b0 ), [sig12, salp1, calp1, salp2, calp2, dnm] )$ /* Return [lam12, salp2, calp2, sig12, ssig1, csig1, ssig2, csig2, (E or eps), domg12, dlam12] */ Lambda12(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1, slam120, clam120, diffp):= block([salp2 : 0b0, calp2 : 0b0, sig12 : 0b0, ssig1 : 0b0, csig1 : 0b0, ssig2 : 0b0, csig2 : 0b0, eps : 0b0, E : [], domg12 : 0b0, somg12 : 0b0, comg12 : 0b0, dlam12 : 0b0, salp0, calp0, somg1, comg1, somg2, comg2, cchi1, cchi2, lam12, B312, k2, Ca, eta], if sbet1 = 0b0 and calp1 = 0b0 then /* Break degeneracy of equatorial line. This case has already been handled. */ calp1 : -tiny, /* sin(alp1) * cos(bet1) = sin(alp0) */ salp0 : salp1 * cbet1, calp0 : hypotx(calp1, salp1 * sbet1), /* calp0 > 0 */ /* tan(bet1) = tan(sig1) * cos(alp1) tan(omg1) = sin(alp0) * tan(sig1) = tan(omg1)=tan(alp1)*sin(bet1) */ ssig1 : sbet1, somg1 : salp0 * sbet1, csig1 : comg1 : calp1 * cbet1, /* Without normalization we have schi1 = somg1. */ if exact then cchi1 : g[g_f1] * dn1 * comg1, block([t:norm2(ssig1, csig1)], ssig1:t[1], csig1:t[2]), /* norm2 (&somg1, &comg1); -- don't need to normalize! */ /* Enforce symmetries in the case abs(bet2) = -bet1. Need to be careful about this case, since this can yield singularities in the Newton iteration. sin(alp2) * cos(bet2) = sin(alp0) */ salp2 : if cbet2 # cbet1 then salp0 / cbet2 else salp1, /* calp2 = sqrt(1 - sq(salp2)) = sqrt(sq(calp0) - sq(sbet2)) / cbet2 and subst for calp0 and rearrange to give; choose positive sqrt to give alp2 in [0, pi/2]. */ calp2 : if cbet2 # cbet1 or abs(sbet2) # -sbet1 then sqrt(sq(calp1 * cbet1) + (if cbet1 < -sbet1 then (cbet2 - cbet1) * (cbet1 + cbet2) else (sbet1 - sbet2) * (sbet1 + sbet2))) / cbet2 else abs(calp1), /* tan(bet2) = tan(sig2) * cos(alp2) tan(omg2) = sin(alp0) * tan(sig2). */ ssig2 : sbet2, somg2 : salp0 * sbet2, csig2 : comg2 : calp2 * cbet2, /* Without normalization we have schi2 = somg2. */ if exact then cchi2 : g[g_f1] * dn2 * comg2, block([t:norm2(ssig2, csig2)], ssig2:t[1], csig2:t[2]), /* norm2(&somg2, &comg2); -- don't need to normalize! */ /* sig12 = sig2 - sig1, limit to [0, pi] */ sig12 : atan2(0b0 + max(0b0, csig1 * ssig2 - ssig1 * csig2), csig1 * csig2 + ssig1 * ssig2), /* omg12 = omg2 - omg1, limit to [0, pi] */ somg12 : 0b0 + max(0b0, comg1 * somg2 - somg1 * comg2), comg12 : comg1 * comg2 + somg1 * somg2, k2 : sq(calp0) * g[g_ep2], if exact then block([schi12, cchi12, deta12], E : Ef(-k2, -g[g_ep2]), schi12 : 0b0 + max(0b0, cchi1 * somg2 - somg1 * cchi2), cchi12 : cchi1 * cchi2 + somg1 * somg2, /* eta = chi12 - lam120 */ eta : atan2(schi12 * clam120 - cchi12 * slam120, cchi12 * clam120 + schi12 * slam120), deta12 : -g[g_e2]/g[g_f1] * salp0 * E[e_hc] / (pi/2) * (sig12 + deltah(ssig2, csig2, dn2, E[e_k2], E[e_alpha2], E[e_hc]) - deltah(ssig1, csig1, dn1, E[e_k2], E[e_alpha2], E[e_hc]) ), lam12 : eta + deta12, domg12 : deta12 + atan2(schi12 * comg12 - cchi12 * somg12, cchi12 * comg12 + schi12 * somg12)) else ( /* eta = omg12 - lam120 */ eta : atan2(somg12 * clam120 - comg12 * slam120, comg12 * clam120 + somg12 * slam120), eps : k2 / (2 * (1 + sqrt(1 + k2)) + k2), Ca : C3f(g, eps), B312 : (SinCosSeries(true, ssig2, csig2, Ca) - SinCosSeries(true, ssig1, csig1, Ca)), domg12 : -g[g_f] * A3f(g, eps) * salp0 * (sig12 + B312), lam12 : eta + domg12), if diffp then ( if calp2 = 0b0 then dlam12 : - 2 * g[g_f1] * dn1 / sbet1 else (block([r], r:Lengths(g, eps, E, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2), dlam12:r[2]), dlam12 : dlam12 * g[g_f1] / (calp2 * cbet2))), [lam12, salp2, calp2, sig12, ssig1, csig1, ssig2, csig2, if exact then E else eps, domg12, dlam12])$ A3f(g, eps):=block( /* Evaluate sum(A3x[k] * eps^k, k, 0, nA3x-1) by Horner's method */ [v : 0b0], for i:nA3x step -1 thru 1 do v : eps * v + g[g_A3x][i], v)$ C3f(g, eps):=block( /* Evaluate C3 coeffs by Horner's method * Elements c[1] thru c[nC3 - 1] are set */ [i, j, k, mult : 1b0, c : makelist(0, i, 1, nC3-1)], j : nC3x, for k : nC3-1 step -1 thru 1 do block( [t : 0b0], for i : nC3 - k step -1 thru 1 do ( t : eps * t + g[g_C3x][j], j : j - 1), c[k] : t), for k:1 thru nC3-1 do ( mult : mult * eps, c[k] : c[k] * mult), c)$ C4f(g, eps):=block( /* Evaluate C4 coeffs by Horner's method * Elements c[1] thru c[nC4] are set */ [i, j, k, mult : 1b0, c : makelist(0, i, 1, nC4)], j : nC4x, for k : nC4-1 step -1 thru 0 do block( [t : 0b0], for i : nC4 - k step -1 thru 1 do ( t : eps * t + g[g_C4x][j], j : j - 1), c[k+1] : t), for k : 2 thru nC4 do ( mult : mult * eps, c[k] : c[k] * mult), c)$ transit(lon1, lon2):=block([lon12], /* Return 1 or -1 if crossing prime meridian in east or west direction. * Otherwise return zero. */ /* Compute lon12 the same way as Geodesic::Inverse. */ lon1 : AngNormalize(lon1), lon2 : AngNormalize(lon2), lon12 : AngDiff(lon1, lon2)[1], if lon1 <= 0b0 and lon2 > 0b0 and lon12 > 0b0 then 1 else (if lon2 <= 0b0 and lon1 > 0b0 and lon12 < 0b0 then -1 else 0))$ /* Return [P, A, mins, maxs] */ geod_polygonarea(g, points) := block([n:length(points), crossings : 0, area0 : 4 * pi * g[g_c2], A : 0, P : 0, mins : g[g_a] * 100, maxs : 0b0], for i : 1 thru n do block( [ s12, S12, r ], r:geod_geninverse(g, points[i][1], points[i][2], points[mod(i,n)+1][1], points[mod(i,n)+1][2]), s12:r[2], S12:r[8], if s12 > maxs then maxs:s12, if s12 < mins then mins:s12, P : P + s12, /* The minus sign is due to the counter-clockwise convention */ A : A - S12, crossings : crossings + transit(points[i][2], points[mod(i,n)+1][2])), if mod(crossings, 2) = 1 then A : A + (if A < 0b0 then 1 else -1) * area0/2, /* Put area in (-area0/2, area0/2] */ if A > area0/2 then A : A - area0 else if A <= -area0/2 then A : A + area0, [P, A, mins, maxs])$ wgs84:geod_init(6378137b0, 1/298.257223563b0)$ flat(a, GM, omega, J2):=block( [e2:3*J2, K : 2 * (a*omega)^2 * a / (15 * GM), e2a, q0], for j:0 thru 100 do ( e2a:e2,q0:qf(e2/(1-e2)), e2:3*J2+K*e2*sqrt(e2)/q0, if e2 = e2a then return(done)), e2/(1+sqrt(1-e2)))$ qf(ep2):=block([ep,fpprec:3*fpprec],ep:sqrt(ep2), ((1 + 3/ep2) * atan(ep) - 3/ep)/2)$ /* 1/298.257222100882711243162836607614495 */ fgrs80:flat(6378137b0, 3986005b8, 7292115b-11, 108263b-8)$ grs80:geod_init(6378137b0, fgrs80)$ GeographicLib-1.49/maxima/ellint.mac0000644000771000077100000002006513165402514017255 0ustar ckarneyckarney/* Implementation of methods given in B. C. Carlson Computation of elliptic integrals Numerical Algorithms 10, 13-26 (1995) Copyright (c) Charles Karney (2009-2013) and licensed under the MIT/X11 License. For more information, see https://geographiclib.sourceforge.io/ */ /* fpprec:120$ Should be set outside */ etol:0.1b0^fpprec$ /* For Carlson */ tolRF : (3 * etol)^(1/8b0)$ tolRD : (etol/5)^(1/8b0)$ tolRG0 : 2.7b0 * sqrt(etol)$ tolJAC:sqrt(etol)$ /* For Bulirsch */ pi:bfloat(%pi)$ atan2x(y,x) := -atan2(-y, x)$ /* fix atan2(0b0,-1b0) = -pi */ rf(x,y,z) := block([a0:(x+y+z)/3, q,x0:x,y0:y,z0:z, an,ln,xx,yy,zz,e2,e3,mul:1b0], q:max(abs(a0-x),abs(a0-y),abs(a0-z))/tolRF, an:a0, while q >= mul * abs(an) do ( ln:sqrt(x0)*sqrt(y0)+sqrt(y0)*sqrt(z0)+sqrt(z0)*sqrt(x0), an:(an+ln)/4, x0:(x0+ln)/4, y0:(y0+ln)/4, z0:(z0+ln)/4, mul:mul*4), xx:(a0-x)/(mul*an), yy:(a0-y)/(mul*an), zz:-xx-yy, e2:xx*yy-zz^2, e3:xx*yy*zz, (e3 * (6930 * e3 + e2 * (15015 * e2 - 16380) + 17160) + e2 * ((10010 - 5775 * e2) * e2 - 24024) + 240240) / (240240 * sqrt(an)))$ rd(x,y,z) := block([a0:(x+y+3*z)/5, q,x0:x,y0:y,z0:z, an,ln,xx,yy,zz,e2,e3,e4,e5,s:0b0,mul:1b0], q:max(abs(a0-x),abs(a0-y),abs(a0-z))/tolRD, an:a0, while q >= mul*abs(an) do ( ln:sqrt(x0)*sqrt(y0)+sqrt(y0)*sqrt(z0)+sqrt(z0)*sqrt(x0), s:s+1/(mul*sqrt(z0)*(z0+ln)), an:(an+ln)/4, x0:(x0+ln)/4, y0:(y0+ln)/4, z0:(z0+ln)/4, mul:4*mul), xx:(a0-x)/(mul*an), yy:(a0-y)/(mul*an), zz:-(xx+yy)/3, e2:xx*yy-6*zz^2, e3:(3*xx*yy-8*zz^2)*zz, e4:3*(xx*yy-zz^2)*zz^2, e5:xx*yy*zz^3, ((471240 - 540540 * e2) * e5 + (612612 * e2 - 540540 * e3 - 556920) * e4 + e3 * (306306 * e3 + e2 * (675675 * e2 - 706860) + 680680) + e2 * ((417690 - 255255 * e2) * e2 - 875160) + 4084080) / (4084080 * mul * an * sqrt(an)) + 3 * s)$ /* R_G(x,y,0) */ rg0(x,y) := block([x0:sqrt(max(x,y)),y0:sqrt(min(x,y)),xn,yn, t,s:0b0,mul:0.25b0], xn:x0, yn:y0, while abs(xn-yn) > tolRG0 * xn do ( t:(xn+yn)/2, yn:sqrt(xn*yn), xn:t, mul : 2*mul, s:s+mul*(xn-yn)^2), ((x0+y0)^2/4 - s)*pi/(2*(xn+yn)) )$ rg(x, y, z) := ( if z = 0b0 then (z:y, y:0b0), (z * rf(x, y, z) - (x-z) * (y-z) * rd(x, y, z) / 3 + sqrt(x * y / z)) / 2)$ rj(x, y, z, p) := block([A0:(x + y + z + 2*p)/5,An,delta:(p-x) * (p-y) * (p-z), Q,x0:x,y0:y,z0:z,p0:p,mul:1b0,mul3:1b0,s:0b0,X,Y,Z,P,E2,E3,E4,E5], An : A0, Q : max(abs(A0-x), abs(A0-y), abs(A0-z), abs(A0-p)) / tolRD, while Q >= mul * abs(An) do block([lam,d0,e0], lam : sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0), d0 : (sqrt(p0)+sqrt(x0)) * (sqrt(p0)+sqrt(y0)) * (sqrt(p0)+sqrt(z0)), e0 : delta/(mul3 * d0^2), s : s + rc(1b0, 1b0 + e0)/(mul * d0), An : (An + lam)/4, x0 : (x0 + lam)/4, y0 : (y0 + lam)/4, z0 : (z0 + lam)/4, p0 : (p0 + lam)/4, mul : 4*mul, mul3 : 64*mul3), X : (A0 - x) / (mul * An), Y : (A0 - y) / (mul * An), Z : (A0 - z) / (mul * An), P : -(X + Y + Z) / 2, E2 : X*Y + X*Z + Y*Z - 3*P*P, E3 : X*Y*Z + 2*P * (E2 + 2*P*P), E4 : (2*X*Y*Z + P * (E2 + 3*P*P)) * P, E5 : X*Y*Z*P*P, ((471240 - 540540 * E2) * E5 + (612612 * E2 - 540540 * E3 - 556920) * E4 + E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) + E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) / (4084080 * mul * An * sqrt(An)) + 6 * s)$ rd(x, y, z) := block([A0:(x + y + 3*z)/5,An,Q,x0:x,y0:y,z0:z, mul:1b0,s:0b0,X,Y,Z,E2,E3,E4,E5], An : A0, Q : max(abs(A0-x), abs(A0-y), abs(A0-z)) / tolRD, while Q >= mul * abs(An) do block([lam], lam : sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0), s : s + 1/(mul * sqrt(z0) * (z0 + lam)), An : (An + lam)/4, x0 : (x0 + lam)/4, y0 : (y0 + lam)/4, z0 : (z0 + lam)/4, mul : 4*mul), X : (A0 - x) / (mul * An), Y : (A0 - y) / (mul * An), Z : -(X + Y) / 3, E2 : X*Y - 6*Z*Z, E3 : (3*X*Y - 8*Z*Z)*Z, E4 : 3 * (X*Y - Z*Z) * Z*Z, E5 : X*Y*Z*Z*Z, ((471240 - 540540 * E2) * E5 + (612612 * E2 - 540540 * E3 - 556920) * E4 + E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) + E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) / (4084080 * mul * An * sqrt(An)) + 3 * s)$ rc(x, y):=if x < y then atan(sqrt((y - x) / x)) / sqrt(y - x) else ( if x = y and y > 0b0 then 1 / sqrt(y) else atanh( if y > 0b0 then sqrt((x - y) / x) else sqrt(x / (x - y)) ) / sqrt(x - y) )$ /* k^2 = m */ ec(k2):=2*rg0(1b0-k2,1b0)$ kc(k2):=rf(0b0,1b0-k2,1b0)$ dc(k2):=rd(0b0,1b0-k2,1b0)/3$ pic(k2,alpha2):=if alpha2 # 0b0 then kc(k2)+alpha2*rj(0b0,1b0-k2,1b0,1b0-alpha2)/3 else kc(k2)$ gc(k2,alpha2):=if alpha2 # 0b0 then (if k2 # 1b0 then kc(k2) + (alpha2-k2)*rj(0b0,1b0-k2,1b0,1b0-alpha2)/3 else rc(1b0,1b0-alpha2)) else ec(k2)$ hc(k2,alpha2):=if alpha2 # 0b0 then (if k2 # 1b0 then kc(k2) - (1b0-alpha2)*rj(0b0,1b0-k2,1b0,1b0-alpha2)/3 else rc(1b0,1b0-alpha2)) else kc(k2) - dc(k2)$ /* Implementation of methods given in Roland Bulirsch Numerical Calculation of Elliptic Integrals and Elliptic Functions Numericshe Mathematik 7, 78-90 (1965) */ sncndn(x,mc):=block([bo, a, b, c, d, l, sn, cn, dn, m, n], local(m, n), if mc # 0 then ( bo:is(mc < 0b0), if bo then ( d:1-mc, mc:-mc/d, d:sqrt(d), x:d*x), dn:a:1, for i:0 thru 12 do ( l:i, m[i]:a, n[i]:mc:sqrt(mc), c:(a+mc)/2, if abs(a-mc)<=tolJAC*a then return(false), mc:a*mc, a:c ), x:c*x, sn:sin(x), cn:cos(x), if sn#0b0 then ( a:cn/sn, c:a*c, for i:l step -1 thru 0 do ( b:m[i], a:c*a, c:dn*c, dn:(n[i]+a)/(b+a), a:c/b ), a:1/sqrt(c*c+1b0), sn:if sn<0b0 then -a else a, cn:c*sn ), if bo then ( a:dn, dn:cn, cn:a, sn:sn/d ) ) else /* mc = 0 */ ( sn:tanh(x), dn:cn:sech(x) /* d:exp(x), a:1/d, b:a+d, cn:dn:2/b, if x < 0.3b0 then ( d:x*x*x*x, d:(d*(d*(d*(d+93024b0)+3047466240b0)+24135932620800b0)+ 20274183401472000b0)/60822550204416000b0, sn:cn*(x*x*x*d+sin(x)) ) else sn:(d-a)/b */ ), [sn,cn,dn] )$ Delta(sn, k2):=sqrt(1 - k2 * sn*sn)$ /* Versions of incomplete functions in terms of Jacobi elliptic function with u = am(phi) real and in [0,K(k2)] */ eirx(sn,cn,dn,k2,ec):=block([t,cn2:cn*cn,dn2:dn*dn,sn2:sn*sn,ei,kp2:1b0-k2], ei : (if k2 <= 0b0 then rf(cn2, dn2, 1b0) - k2 * sn2 * rd(cn2, dn2, 1b0) / 3 else (if kp2 >= 0b0 then kp2 * rf(cn2, dn2, 1b0) + k2 * kp2 * sn2 * rd(cn2, 1b0, dn2) / 3 + k2 * abs(cn) / dn else - kp2 * sn2 * rd(dn2, 1b0, cn2) / 3 + dn / abs(cn) ) ), ei : ei * abs(sn), if cn < 0b0 then ei : 2 * ec - ei, if sn < 0 then ei : -ei, ei)$ dirx(sn, cn, dn, k2, dc):=block( [di:abs(sn) * sn*sn * rd(cn*cn, dn*dn, 1b0) / 3], if cn < 0b0 then di : 2 * dc - di, if sn < 0b0 then di : -di, di)$ hirx(sn, cn, dn, k2, alpha2, hc):=block( [cn2 : cn*cn, dn2 : dn*dn, sn2 : sn*sn, hi, alphap2:1b0-alpha2], hi : abs(sn) * (rf(cn2, dn2, 1b0) - alphap2 * sn2 * rj(cn2, dn2, 1b0, cn2 + alphap2 * sn2) / 3), if cn < 0 then hi : 2 * hc - hi, if sn < 0 then hi : -hi, hi)$ deltae(sn, cn, dn, k2, ec):=( if cn < 0 then (cn : -cn, sn : -sn), eirx(sn, cn, dn, k2, ec) * (pi/2) / ec - atan2x(sn, cn))$ deltad(sn, cn, dn, k2, dc):=( if cn < 0 then (cn : -cn, sn : -sn), dirx(sn, cn, dn, k2, ec) * (pi/2) / dc - atan2x(sn, cn))$ deltah(sn, cn, dn, k2, alpha2, hc):=( if cn < 0 then (cn : -cn, sn : -sn), hirx(sn, cn, dn, k2, alpha2, hc) * (pi/2) / hc - atan2x(sn, cn))$ einv(x, k2, ec):=block( [n : floor(x / (2 * ec) + 0.5b0), phi, eps : k2/(sqrt(1b0-k2) + 1b0)^2, err:1b0], x : x - 2 * ec * n, phi : pi * x / (2 * ec), phi : phi - eps * sin(2 * phi) / 2, while abs(err) > tolJAC do block([sn:sin(phi), cn:cos(phi), dn], dn : Delta(sn, k2), err : (eirx(sn, cn, dn, k2, ec) - x)/dn, phi : phi - err), n * pi + phi)$ deltaeinv(stau, ctau, k2, ec) := block([tau], if ctau < 0 then (ctau : -ctau, stau : -stau), tau : atan2x(stau, ctau), einv(tau * ec / (pi/2), k2, ec) - tau)$ GeographicLib-1.49/maxima/gearea.mac0000644000771000077100000001135013165402514017207 0ustar ckarneyckarney/* Compute the series expansion for the great ellipse area. Copyright (c) Charles Karney (2014) and licensed under the MIT/X11 License. For more information, see https://geographiclib.sourceforge.io/ Area of great ellipse quad area from equator to phi dA = dlambda*b^2*sin(phi)/2* (1/(1-e^2*sin(phi)^2) + atanh(e*sin(phi))/(e*sin(phi))) Total area = 2*pi*(a^2 + b^2*atanh(e)/e) convert to beta using sin(phi)^2 = sin(beta)^2/(1-e^2*cos(beta)^2) dA = dlambda*sin(beta)/2* ( a^2*sqrt(1-e^2*cos(beta)^2) + b^2*atanh(e*sin(beta)/sqrt(1-e^2*cos(beta)^2)) /(e*sin(beta))) ) subst for great ellipse sin(beta) = cos(gamma0)*sin(sigma) dlambda = dsigma * sin(gamma0) / (1 - cos(gamma0)^2*sin(sigma)^2) (1-e^2*cos(beta)^2) = (1-e^2)*(1+k^2*sin(sigma)^2) k^2 = ep^2*cos(gamma0)^2 e*sin(beta) = sqrt(1-e^2)*k*sin(sigma) dA = dsigma*sin(gamma0)*cos(gamma0)*sin(sigma)/2*e^2*a^2*sqrt(1+ep^2)* ( (1+k^2*sin(sigma)^2) + atanh(k*sin(sigma)/sqrt(1+k^2*sin(sigma)^2)) / (k*sin(sigma))) ) / (ep^2 - k^2*sin(sigma)^2) Spherical case radius c, c^2 = a^2/2 + b^2/2*atanh(e)/e dA0 = dsigma*sin(gamma0)*cos(gamma0)*sin(sigma)/2* ( a^2 + b^2*atanh(e)/e) / (1 - cos(gamma0)^2*sin(sigma)^2) = dsigma*sin(gamma0)*cos(gamma0)*sin(sigma)/2*e^2*a^2*sqrt(1+ep^2) ( sqrt(1+ep^2) + atanh(ep/sqrt(1+ep^2))/ep ) / (ep^2 - k^2*sin(sigma)^2) dA-dA0 = dsigma*sin(gamma0)*cos(gamma0)*sin(sigma)/2*e^2*a^2*sqrt(1+ep^2)* -( ( sqrt(1+ep^2) + atanh(ep/sqrt(1+ep^2))/ep ) - ( sqrt(1+k^2*sin(sigma)^2) + atanh(k*sin(sigma)/sqrt(1+k^2*sin(sigma)^2)) / (k*sin(sigma)) ) ) / / (ep^2 - k^2*sin(sigma)^2) atanh(y/sqrt(1+y^2)) = asinh(y) dA-dA0 = dsigma*sin(gamma0)*cos(gamma0)*sin(sigma)/2*e^2*a^2* - ( ( sqrt(1+ep^2) + asinh(ep)/ep ) - ( sqrt(1+k^2*sin(sigma)^2) + asinh(k*sin(sigma)) / (k*sin(sigma)) ) ) / / (ep^2 - k^2*sin(sigma)^2) r(x) = sqrt(1+x) + asinh(sqrt(x))/sqrt(x) dA-dA0 = e^2*a^2*dsigma*sin(gamma0)*cos(gamma0)* - ( r(ep^2) - r(k^2*sin(sigma)^2)) / ( ep^2 - k^2*sin(sigma)^2 ) * sin(sigma)/2*sqrt(1+ep^2)* subst ep^2=4*n/(1-n)^2 -- second eccentricity in terms of third flattening ellipse semi axes = [a, a * sqrt(1-e^2*cos(gamma0)^2)] third flattening for ellipsoid eps = (1 - sqrt(1-e^2*cos(gamma0)^2)) / (1 + sqrt(1-e^2*cos(gamma0)^2)) e^2*cos(gamma0)^2 = 4*eps/(1+eps)^2 -- 1st ecc in terms of 3rd flattening k2=((1+n)/(1-n))^2 * 4*eps/(1+eps)^2 Taylor expand in n and eps, integrate, trigreduce */ taylordepth:5$ jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1], ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$ /* Great ellipse via r */ computeG4(maxpow):=block([int,r,intexp,area, x,ep2,k2], maxpow:maxpow-1, r : sqrt(1+x) + asinh(sqrt(x))/sqrt(x), int:-(rf(ep2) - rf(k2*sin(sigma)^2)) / (ep2 - k2*sin(sigma)^2) * sin(sigma)/2*sqrt(1+ep2), int:subst([rf(ep2)=subst([x=ep2],r), rf(k2*sin(sigma)^2)=subst([x=k2*sin(sigma)^2],r)], int), int:subst([abs(sin(sigma))=sin(sigma)],int), int:subst([k2=((1+n)/(1-n))^2 * 4*eps/(1+eps)^2,ep2=4*n/(1-n)^2],int), intexp:jtaylor(int,n,eps,maxpow), area:trigreduce(integrate(intexp,sigma)), area:expand(area-subst(sigma=%pi/2,area)), for i:0 thru maxpow do G4[i]:coeff(area,cos((2*i+1)*sigma)), if expand(area-sum(G4[i]*cos((2*i+1)*sigma),i,0,maxpow)) # 0 then error("left over terms in G4"), 'done)$ codeG4(maxpow):=block([tab1:" ",nn:maxpow,c], c:0, for m:0 thru nn-1 do block( [q:jtaylor(G4[m],n,eps,nn-1), linel:1200], for j:m thru nn-1 do ( print(concat(tab1,"G4x(",c,"+1) = ", string(horner(coeff(q,eps,j))),";")), c:c+1) ), 'done)$ dispG4(ord):=(ord:ord-1,for i:0 thru ord do block([tt:jtaylor(G4[i],n,eps,ord), ttt,t4,linel:1200], for j:i thru ord do ( ttt:coeff(tt,eps,j), if ttt # 0 then block([a:taylor(ttt+n^(ord+1),n,0,ord+1),paren,s], paren : is(length(a) > 2), s:if j = i then concat("G4[",i,"] = ") else " ", if subst([n=1],part(a,1)) > 0 then s:concat(s,"+ ") else (s:concat(s,"- "), a:-a), if paren then s:concat(s,"("), for k:1 thru length(a)-1 do block([term:part(a,k),nn], nn:subst([n=1],term), term:term/nn, if nn > 0 and k > 1 then s:concat(s," + ") else if nn < 0 then (s:concat(s," - "), nn:-nn), if lopow(term,n) = 0 then s:concat(s,string(nn)) else ( if nn # 1 then s:concat(s,string(nn)," * "), s:concat(s,string(term)) )), if paren then s:concat(s,")"), if j>0 then s:concat(s," * ", string(eps^j)), print(concat(s,if j = ord then ";" else ""))))))$ maxpow:6$ (computeG4(maxpow), print(""), codeG4(maxpow), print(""), dispG4(maxpow))$ GeographicLib-1.49/maxima/polyprint.mac0000644000771000077100000001237113165402514020027 0ustar ckarneyckarney/* Print out the coefficients for the geodesic series in a format that allows Math::polyval to be used. */ taylordepth:5$ simplenum:true$ count:0$ jtaylor(expr,var1,var2,ord):=expand(subst([zz=1], ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord))))$ h(x):=if x=0 then 0 else block([n:0],while not(oddp(x)) do (x:x/2,n:n+1),n); decorhex(x):=if x=0 then "0" else if abs(x)<10^12 then string(x) else concat(if x<0 then "-" else "", "0x",block([obase:16,s], s:sdowncase(string(abs(x))), if substring(s,1,2) = "0" then s:substring(s,2), s))$ formatnum(x):=block([n,neg:is(x<0),s1,s2,ll],x:abs(x),n:h(x), ll:if x<2^31 then "" else "LL", s1:concat(if neg then "-" else "", decorhex(x), ll), s2:concat(if neg then "-(" else "", decorhex(x/2^n), ll, "<<", n, if neg then ")" else ""), if slength(s2) < slength(s1) then s2 else s1)$ formatnumx(x):=if simplenum then concat(string(x),if abs(x) < 2^31 then "" else "LL") else if abs(x)<2^63 then (if abs(x) < 2^24 /* test used to be: abs(x)/2^h(abs(x)) < 2^24; but Visual Studio complains about truncation of __int64 to real even if trailing bits are zero */ then formatnum(x) else concat(s:if x<0 then "-" else "","real(",formatnum(abs(x)),")")) else block([s:if x<0 then "-" else ""], x:abs(x), concat(s,"reale(",formatnum(floor(x/2^52)),",", formatnum(x-floor(x/2^52)*2^52),")"))$ printterm(x,line):=block([lx:slength(x)+1,lline:slength(line)], count:count+1, x:concat(x,if simplenum then ", " else ","), if lline=0 then line:concat(" ",x) else (if lx+lline<80 then line:concat(line,x) else (print(line),line:concat(" ",x))), line)$ flushline(line):=(if slength(line)>0 then (print(line),line:""),line)$ polyprint(p, var, title):=block([linel:90,d,line:"",h], p:ratsimp(p), d:abs(denom(p)), p:expand(d*p), h:hipow(p,var), print(concat(" // ", title, ", polynomial in ", var, " of order ",h)), for k:h step -1 thru 0 do line:printterm(formatnumx(coeff(p,var,k)),line), line:printterm(formatnumx(d),line), flushline(line), done)$ value1(val,var,pow,dord):=block([tab2:" ",linel:90,div], print(concat(tab2,"// Generated by Maxima on ",timedate())), div:if pow = 1 then "" else concat("/",pow), for nn:0 step pow thru maxpow do block([c], if nn = 0 then print(concat("#if ", macro, div, " == ",nn/pow)) else print(concat("#elif ", macro, div, " == ",nn/pow)), count:0, print(concat(tab2,"static const real coeff[] = {")), block( [q:ratdisrep(taylor(ev(val),var,0,nn-dord)),line:""], if pow = 2 then ( q:subst(var=sqrt(concat(var,2)),expand(q)), polyprint(q,concat(var,2),string(val))) else (polyprint(q,var,string(val))), line:flushline(line)), print(concat(tab2,"}; // count = ",count))), print("#else #error", concat("\"Bad value for ", macro, "\""), " #endif "), 'done)$ array1(array,var,pow,dord):=block([tab2:" ",linel:90], print(concat(tab2,"// Generated by Maxima on ",timedate())), for nn:0 thru maxpow do block([c], if nn = 0 then print(concat("#if ", macro, " == ",nn)) else print(concat("#elif ", macro, " == ",nn)), count:0, print(concat(tab2,"static const real coeff[] = {")), for m:0 thru nn do if part(arrayapply(array,[m]),0) # array then block( [q:ratdisrep(taylor(arrayapply(array,[m]),var,0,nn-dord)),line:""], if pow = 2 then ( q:subst(var=sqrt(concat(var,2)),expand(q/var^(m-dord))), polyprint(q,concat(var,2),concat(array, "[", m, "]/",var,"^",m-dord))) else ( q:expand(q/var^(m-dord)), polyprint(q,var,concat(array, "[", m, "]/",var,"^",m-dord))), line:flushline(line)), print(concat(tab2,"}; // count = ",count))), print("#else #error", concat("\"Bad value for ", macro, "\""), " #endif "), 'done)$ value2(val,var1,var2,dord):=block([tab2:" ",linel:90], print(concat(tab2,"// Generated by Maxima on ",timedate())), for nn:0 thru maxpow do block([c], if nn = 0 then print(concat("#if ", macro, " == ",nn)) else print(concat("#elif ", macro, " == ",nn)), count:0, print(concat(tab2,"static const real coeff[] = {")), block( [q:jtaylor(ev(val),n,eps,nn-dord),line:""], for j:nn-dord step -1 thru 0 do block( [p:coeff(q,var2,j)], polyprint(p,var1,concat(val, ", coeff of eps^",j))), line:flushline(line)), print(concat(tab2,"}; // count = ",count))), print("#else #error", concat("\"Bad value for ", macro, "\""), " #endif "), 'done)$ array2(array,var1,var2,dord):=block([tab2:" ",linel:90], print(concat(tab2,"// Generated by Maxima on ",timedate())), for nn:0 thru maxpow do block([c], if nn = 0 then print(concat("#if ", macro, " == ",nn)) else print(concat("#elif ", macro, " == ",nn)), count:0, print(concat(tab2,"static const real coeff[] = {")), for m:0 thru nn-1 do if part(arrayapply(array,[m]),0) # array then block( [q:jtaylor(arrayapply(array,[m]),n,eps,nn-dord),line:""], for j:nn-dord step -1 thru m do block( [p:coeff(q,var2,j)], polyprint(p,var1,concat(array, "[", m ,"], coeff of eps^",j))), line:flushline(line)), print(concat(tab2,"}; // count = ",count))), print("#else #error", concat("\"Bad value for ", macro, "\""), " #endif "), 'done)$ GeographicLib-1.49/maxima/Makefile.mk0000644000771000077100000000023213165402514017344 0ustar ckarneyckarneyMAXIMA = tm ellint tmseries geod geodesic auxlat MAXIMASOURCES = $(addsuffix .mac,$(MAXIMA)) all: @: install: @: clean: @: .PHONY: all install clean GeographicLib-1.49/man/RhumbSolve.pod0000644000771000077100000002113613165402514017375 0ustar ckarneyckarney=head1 NAME RhumbSolve -- perform rhumb line calculations =head1 SYNOPSIS B [ B<-i> | B<-L> I I I ] [ B<-e> I I ] [ B<-d> | B<-:> ] [ B<-w> ] [ B<-p> I ] [ B<-s> ] [ B<--comment-delimiter> I ] [ B<--version> | B<-h> | B<--help> ] [ B<--input-file> I | B<--input-string> I ] [ B<--line-separator> I ] [ B<--output-file> I ] =head1 DESCRIPTION The path with constant heading between two points on the ellipsoid at (I, I) and (I, I) is called the rhumb line or loxodrome. Its length is I and the rhumb line has a forward azimuth I along its length. Also computed is I is the area between the rhumb line from point 1 to point 2 and the equator; i.e., it is the area, measured counter-clockwise, of the geodesic quadrilateral with corners (I,I), (0,I), (0,I), and (I,I). 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 B reports NaNs for the longitude and the area in this case. B the rhumb line is B the shortest path between two points; that is the geodesic and it is calculated by GeodSolve(1). B operates in one of three modes: =over =item 1. By default, B accepts lines on the standard input containing I I I I and prints I I I on standard output. This is the direct calculation. =item 2. With the B<-i> command line argument, B performs the inverse calculation. It reads lines containing I I I I and prints the values of I I I for the corresponding shortest rhumb lines. If the end points are on opposite meridians, there are two shortest rhumb lines and the east-going one is chosen. =item 3. Command line arguments B<-L> I I I specify a rhumb line. B then accepts a sequence of I values (one per line) on standard input and prints I I I for each. This generates a sequence of points on a rhumb line. =back =head1 OPTIONS =over =item B<-i> perform an inverse calculation (see 2 above). =item B<-L> I I I line mode (see 3 above); generate a sequence of points along the rhumb line specified by I I I. The B<-w> flag can be used to swap the default order of the 2 geographic coordinates, provided that it appears before B<-L>. (B<-l> is an alternative, deprecated, spelling of this flag.) =item B<-e> I I specify the ellipsoid via the equatorial radius, I and the flattening, I. Setting I = 0 results in a sphere. Specify I E 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for I. By default, the WGS84 ellipsoid is used, I = 6378137 m, I = 1/298.257223563. =item B<-d> output angles as degrees, minutes, seconds instead of decimal degrees. =item B<-:> like B<-d>, except use : as a separator instead of the d, ', and " delimiters. =item B<-w> on input and output, longitude precedes latitude (except that on input this can be overridden by a hemisphere designator, I, I, I, I). =item B<-p> I set the output precision to I (default 3); I is the precision relative to 1 m. See L. =item B<-s> By default, the rhumb line calculations are carried out exactly in terms of elliptic integrals. This includes the use of the addition theorem for elliptic integrals to compute the divided difference of the isometric and rectifying latitudes. If B<-s> is supplied this divided difference is computed using Krueger series for the transverse Mercator projection which is only accurate for |I| E 0.01. See L. =item B<--comment-delimiter> I set the comment delimiter to I (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). =item B<--version> print version and exit. =item B<-h> print usage and exit. =item B<--help> print full documentation and exit. =item B<--input-file> I read input from the file I instead of from standard input; a file name of "-" stands for standard input. =item B<--input-string> I read input from the string I instead of from standard input. All occurrences of the line separator character (default is a semicolon) in I are converted to newlines before the reading begins. =item B<--line-separator> I set the line separator character to I. By default this is a semicolon. =item B<--output-file> I write output to the file I instead of to standard output; a file name of "-" stands for standard output. =back =head1 INPUT B measures all angles in degrees, all lengths (I) in meters, and all areas (I) in meters^2. On input angles (latitude, longitude, azimuth, arc length) can be as decimal degrees or degrees, minutes, seconds. For example, C<40d30>, C<40d30'>, C<40:30>, C<40.5d>, and C<40.5> are all equivalent. By default, latitude precedes longitude for each point (the B<-w> flag switches this convention); however on input either may be given first by appending (or prepending) I or I to the latitude and I or I to the longitude. Azimuths are measured clockwise from north; however this may be overridden with I or I. For details on the allowed formats for angles, see the C section of GeoConvert(1). =head1 PRECISION I gives precision of the output with I = 0 giving 1 m precision, I = 3 giving 1 mm precision, etc. I is the number of digits after the decimal point for lengths. For decimal degrees, the number of digits after the decimal point is I + 5. For DMS (degree, minute, seconds) output, the number of digits after the decimal point in the seconds component is I + 1. The minimum value of I is 0 and the maximum is 10. =head1 ERRORS An illegal line of input will print an error message to standard output beginning with C and causes B to return an exit code of 1. However, an error does not cause B to terminate; following lines will be converted. =head1 ACCURACY The algorithm used by B uses exact formulas for converting between the latitude, rectifying latitude (I), and isometric latitude (I). These formulas are accurate for any value of the flattening. The computation of rhumb lines involves the ratio (I - I) / (I - I) and this is subject to large round-off errors if I is close to I. So this ratio is computed using divided differences using one of two methods: by default, this uses the addition theorem for elliptic integrals (accurate for all values of I); however, with the B<-s> options, it is computed using the series expansions used by TransverseMercatorProj(1) for the conversions between rectifying and conformal latitudes (accurate for |I| E 0.01). For the WGS84 ellipsoid, the error is about 10 nanometers using either method. =head1 EXAMPLES Route from JFK Airport to Singapore Changi Airport: echo 40:38:23N 073:46:44W 01:21:33N 103:59:22E | RhumbSolve -i -: -p 0 103:34:58.2 18523563 N.B. This is B the route typically taken by aircraft because it's considerably longer than the geodesic given by GeodSolve(1). Waypoints on the route at intervals of 2000km: for ((i = 0; i <= 20; i += 2)); do echo ${i}000000;done | RhumbSolve -L 40:38:23N 073:46:44W 103:34:58.2 -: -p 0 40:38:23.0N 073:46:44.0W 0 36:24:30.3N 051:28:26.4W 9817078307821 32:10:26.8N 030:20:57.3W 18224745682005 27:56:13.2N 010:10:54.2W 25358020327741 23:41:50.1N 009:12:45.5E 31321269267102 19:27:18.7N 027:59:22.1E 36195163180159 15:12:40.2N 046:17:01.1E 40041499143669 10:57:55.9N 064:12:52.8E 42906570007050 06:43:07.3N 081:53:28.8E 44823504180200 02:28:16.2N 099:24:54.5E 45813843358737 01:46:36.0S 116:52:59.7E 45888525219677 =head1 SEE ALSO GeoConvert(1), GeodSolve(1), TransverseMercatorProj(1). An online version of this utility is availbable at L. The Wikipedia page, Rhumb line, L. =head1 AUTHOR B was written by Charles Karney. =head1 HISTORY B was added to GeographicLib, L, in version 1.37. GeographicLib-1.49/man/GeoidEval.usage0000644000771000077100000003123613165402556017500 0ustar ckarneyckarneyint usage(int retval, bool brief) { if (brief) ( retval ? std::cerr : std::cout ) << "Usage:\n" " GeoidEval [ -n name ] [ -d dir ] [ -l ] [ -a | -c south west north east\n" " ] [ -w ] [ -z zone ] [ --msltohae ] [ --haetomsl ] [ -v ] [\n" " --comment-delimiter commentdelim ] [ --version | -h | --help ] [\n" " --input-file infile | --input-string instring ] [ --line-separator\n" " linesep ] [ --output-file outfile ]\n" "\n" "For full documentation type:\n" " GeoidEval --help\n" "or visit:\n" " https://geographiclib.sourceforge.io/1.49/GeoidEval.1.html\n"; else ( retval ? std::cerr : std::cout ) << "Man page:\n" "NAME\n" " GeoidEval -- look up geoid heights\n" "\n" "SYNOPSIS\n" " GeoidEval [ -n name ] [ -d dir ] [ -l ] [ -a | -c south west north east\n" " ] [ -w ] [ -z zone ] [ --msltohae ] [ --haetomsl ] [ -v ] [\n" " --comment-delimiter commentdelim ] [ --version | -h | --help ] [\n" " --input-file infile | --input-string instring ] [ --line-separator\n" " linesep ] [ --output-file outfile ]\n" "\n" "DESCRIPTION\n" " GeoidEval reads in positions on standard input and prints out the\n" " corresponding heights of the geoid above the WGS84 ellipsoid on\n" " standard output.\n" "\n" " Positions are given as latitude and longitude, UTM/UPS, or MGRS, in any\n" " of the formats accepted by GeoConvert(1). (MGRS coordinates signify\n" " the center of the corresponding MGRS square.) If the -z option is\n" " specified then the specified zone is prepended to each line of input\n" " (which must be in UTM/UPS coordinates). This allows a file with UTM\n" " eastings and northings in a single zone to be used as standard input.\n" "\n" " More accurate results for the geoid height are provided by Gravity(1).\n" " This utility can also compute the direction of gravity accurately.\n" "\n" " The height of the geoid above the ellipsoid, N, is sometimes called the\n" " geoid undulation. It can be used to convert a height above the\n" " ellipsoid, h, to the corresponding height above the geoid (the\n" " orthometric height, roughly the height above mean sea level), H, using\n" " the relations\n" "\n" " h = N + H, H = -N + h.\n" "\n" "OPTIONS\n" " -n name\n" " use geoid name instead of the default \"egm96-5\". See \"GEOIDS\".\n" "\n" " -d dir\n" " read geoid data from dir instead of the default. See \"GEOIDS\".\n" "\n" " -l use bilinear interpolation instead of cubic. See \"INTERPOLATION\".\n" "\n" " -a cache the entire data set in memory. See \"CACHE\".\n" "\n" " -c south west north east\n" " cache the data bounded by south west north east in memory. The\n" " first two arguments specify the SW corner of the cache and the last\n" " two arguments specify the NE corner. The -w flag specifies that\n" " longitude precedes latitude for these corners, provided that it\n" " appears before -c. See \"CACHE\".\n" "\n" " -w toggle the longitude first flag (it starts off); if the flag is on,\n" " then when reading geographic coordinates, longitude precedes\n" " latitude (this can be overridden by a hemisphere designator, N, S,\n" " E, W).\n" "\n" " -z zone\n" " prefix each line of input by zone, e.g., \"38n\". This should be\n" " used when the input consists of UTM/UPS eastings and northings.\n" "\n" " --msltohae\n" " standard input should include a final token on each line which is\n" " treated as a height (in meters) above the geoid and the output\n" " echoes the input line with the height converted to height above\n" " ellipsoid (HAE). If -z zone is specified then the third token is\n" " treated as the height; this makes it possible to convert LIDAR data\n" " where each line consists of: easting northing height intensity.\n" "\n" " --haetomsl\n" " this is similar to --msltohae except that the height token is\n" " treated as a height (in meters) above the ellipsoid and the output\n" " echoes the input line with the height converted to height above the\n" " geoid (MSL).\n" "\n" " -v print information about the geoid on standard error before\n" " processing the input.\n" "\n" " --comment-delimiter commentdelim\n" " set the comment delimiter to commentdelim (e.g., \"#\" or \"//\"). If\n" " set, the input lines will be scanned for this delimiter and, if\n" " found, the delimiter and the rest of the line will be removed prior\n" " to processing and subsequently appended to the output line\n" " (separated by a space).\n" "\n" " --version\n" " print version and exit.\n" "\n" " -h print usage, the default geoid path and name, and exit.\n" "\n" " --help\n" " print full documentation and exit.\n" "\n" " --input-file infile\n" " read input from the file infile instead of from standard input; a\n" " file name of \"-\" stands for standard input.\n" "\n" " --input-string instring\n" " read input from the string instring instead of from standard input.\n" " All occurrences of the line separator character (default is a\n" " semicolon) in instring are converted to newlines before the reading\n" " begins.\n" "\n" " --line-separator linesep\n" " set the line separator character to linesep. By default this is a\n" " semicolon.\n" "\n" " --output-file outfile\n" " write output to the file outfile instead of to standard output; a\n" " file name of \"-\" stands for standard output.\n" "\n" "GEOIDS\n" " GeoidEval computes geoid heights by interpolating on the data in a\n" " regularly spaced table (see \"INTERPOLATION\"). The following geoid\n" " tables are available (however, some may not be installed):\n" "\n" " bilinear error cubic error\n" " name geoid grid max rms max rms\n" " egm84-30 EGM84 30' 1.546 m 70 mm 0.274 m 14 mm\n" " egm84-15 EGM84 15' 0.413 m 18 mm 0.021 m 1.2 mm\n" " egm96-15 EGM96 15' 1.152 m 40 mm 0.169 m 7.0 mm\n" " egm96-5 EGM96 5' 0.140 m 4.6 mm .0032 m 0.7 mm\n" " egm2008-5 EGM2008 5' 0.478 m 12 mm 0.294 m 4.5 mm\n" " egm2008-2_5 EGM2008 2.5' 0.135 m 3.2 mm 0.031 m 0.8 mm\n" " egm2008-1 EGM2008 1' 0.025 m 0.8 mm .0022 m 0.7 mm\n" "\n" " By default, the \"egm96-5\" geoid is used. This may changed by setting\n" " the environment variable \"GEOGRAPHICLIB_GEOID_NAME\" or with the -n\n" " option. The errors listed here are estimates of the quantization and\n" " interpolation errors in the reported heights compared to the specified\n" " geoid.\n" "\n" " The geoid data will be loaded from a directory specified at compile\n" " time. This may changed by setting the environment variables\n" " \"GEOGRAPHICLIB_GEOID_PATH\" or \"GEOGRAPHICLIB_DATA\", or with the -d\n" " option. The -h option prints the default geoid path and name. Use the\n" " -v option to ascertain the full path name of the data file.\n" "\n" " Instructions for downloading and installing geoid data are available at\n" " .\n" "\n" " NOTE: all the geoids above apply to the WGS84 ellipsoid (a = 6378137 m,\n" " f = 1/298.257223563) only.\n" "\n" "INTERPOLATION\n" " Cubic interpolation is used to compute the geoid height unless -l is\n" " specified in which case bilinear interpolation is used. The cubic\n" " interpolation is based on a least-squares fit of a cubic polynomial to\n" " a 12-point stencil\n" "\n" " . 1 1 .\n" " 1 2 2 1\n" " 1 2 2 1\n" " . 1 1 .\n" "\n" " The cubic is constrained to be independent of longitude when evaluating\n" " the height at one of the poles. Cubic interpolation is considerably\n" " more accurate than bilinear; however it results in small\n" " discontinuities in the returned height on cell boundaries.\n" "\n" "CACHE\n" " By default, the data file is randomly read to compute the geoid heights\n" " at the input positions. Usually this is sufficient for interactive\n" " use. If many heights are to be computed, use -c south west north east\n" " to notify GeoidEval to read a rectangle of data into memory; heights\n" " within the this rectangle can then be computed without any disk access.\n" " If -a is specified all the geoid data is read; in the case of\n" " \"egm2008-1\", this requires about 0.5 GB of RAM. The evaluation of\n" " heights outside the cached area causes the necessary data to be read\n" " from disk. Use the -v option to verify the size of the cache.\n" "\n" " Regardless of whether any cache is requested (with the -a or -c\n" " options), the data for the last grid cell in cached. This allows the\n" " geoid height along a continuous path to be returned with little disk\n" " overhead.\n" "\n" "ENVIRONMENT\n" " GEOGRAPHICLIB_GEOID_NAME\n" " Override the compile-time default geoid name of \"egm96-5\". The -h\n" " option reports the value of GEOGRAPHICLIB_GEOID_NAME, if defined,\n" " otherwise it reports the compile-time value. If the -n name option\n" " is used, then name takes precedence.\n" "\n" " GEOGRAPHICLIB_GEOID_PATH\n" " Override the compile-time default geoid path. This is typically\n" " \"/usr/local/share/GeographicLib/geoids\" on Unix-like systems and\n" " \"C:/ProgramData/GeographicLib/geoids\" on Windows systems. The -h\n" " option reports the value of GEOGRAPHICLIB_GEOID_PATH, if defined,\n" " otherwise it reports the compile-time value. If the -d dir option\n" " is used, then dir takes precedence.\n" "\n" " GEOGRAPHICLIB_DATA\n" " Another way of overriding the compile-time default geoid path. If\n" " it is set (and if GEOGRAPHICLIB_GEOID_PATH is not set), then\n" " $GEOGRAPHICLIB_DATA/geoids is used.\n" "\n" "ERRORS\n" " An illegal line of input will print an error message to standard output\n" " beginning with \"ERROR:\" and causes GeoidEval to return an exit code of\n" " 1. However, an error does not cause GeoidEval to terminate; following\n" " lines will be converted.\n" "\n" "ABBREVIATIONS\n" " The geoid is usually approximated by an \"earth gravity model\". The\n" " models published by the NGA are:\n" "\n" " EGM84\n" " An earth gravity model published by the NGA in 1984,\n" " .\n" "\n" " EGM96\n" " An earth gravity model published by the NGA in 1996,\n" " .\n" "\n" " EGM2008\n" " An earth gravity model published by the NGA in 2008,\n" " .\n" "\n" " WGS84\n" " World Geodetic System 1984, .\n" "\n" " HAE Height above the WGS84 ellipsoid.\n" "\n" " MSL Mean sea level, used as a convenient short hand for the geoid.\n" " (However, typically, the geoid differs by a few meters from mean\n" " sea level.)\n" "\n" "EXAMPLES\n" " The height of the EGM96 geoid at Timbuktu\n" "\n" " echo 16:46:33N 3:00:34W | GeoidEval\n" " => 28.7068 -0.02e-6 -1.73e-6\n" "\n" " The first number returned is the height of the geoid and the 2nd and\n" " 3rd are its slopes in the northerly and easterly directions.\n" "\n" " Convert a point in UTM zone 18n from MSL to HAE\n" "\n" " echo 531595 4468135 23 | GeoidEval --msltohae -z 18n\n" " => 531595 4468135 -10.842\n" "\n" "SEE ALSO\n" " GeoConvert(1), Gravity(1), geographiclib-get-geoids(8).\n" "\n" " An online version of this utility is availbable at\n" " .\n" "\n" "AUTHOR\n" " GeoidEval was written by Charles Karney.\n" "\n" "HISTORY\n" " GeoidEval was added to GeographicLib,\n" " , in 2009-09.\n" ; return retval; } GeographicLib-1.49/man/Planimeter.pod0000644000771000077100000001637413165402514017417 0ustar ckarneyckarney=head1 NAME Planimeter -- compute the area of geodesic polygons =head1 SYNOPSIS B [ B<-r> ] [ B<-s> ] [ B<-l> ] [ B<-e> I I ] [ B<-w> ] [ B<-p> I ] [ B<-G> | B<-E> | B<-Q> | B<-R> ] [ B<--comment-delimiter> I ] [ B<--version> | B<-h> | B<--help> ] [ B<--input-file> I | B<--input-string> I ] [ B<--line-separator> I ] [ B<--output-file> I ] =head1 DESCRIPTION Measure the area of a geodesic polygon. Reads polygon vertices from standard input, one per line. Vertices may be given as latitude and longitude, UTM/UPS, or MGRS coordinates, interpreted in the same way as GeoConvert(1). (MGRS coordinates signify the center of the corresponding MGRS square.) The end of input, a blank line, or a line which can't be interpreted as a vertex signals the end of one polygon and the start of the next. For each polygon print a summary line with the number of points, the perimeter (in meters), and the area (in meters^2). The edges of the polygon are given by the I geodesic between consecutive vertices. In certain cases, there may be two or many such shortest geodesics, and in that case, the polygon is not uniquely specified by its vertices. This only happens with very long edges (for the WGS84 ellipsoid, any edge shorter than 19970 km is uniquely specified by its end points). In such cases, insert an additional vertex near the middle of the long edge to define the boundary of the polygon. By default, polygons traversed in a counter-clockwise direction return a positive area and those traversed in a clockwise direction return a negative area. This sign convention is reversed if the B<-r> option is given. Of course, encircling an area in the clockwise direction is equivalent to encircling the rest of the ellipsoid in the counter-clockwise direction. The default interpretation used by B is the one that results in a smaller magnitude of area; i.e., the magnitude of the area is less than or equal to one half the total area of the ellipsoid. If the B<-s> option is given, then the interpretation used is the one that results in a positive area; i.e., the area is positive and less than the total area of the ellipsoid. Only simple (i.e., non-self-intersecting) polygons are supported for the area computation. Polygons may include one or both poles. There is no need to close the polygon. =head1 OPTIONS =over =item B<-r> toggle whether counter-clockwise traversal of the polygon returns a positive (the default) or negative result. =item B<-s> toggle whether to return a signed result (the default) or not. =item B<-l> toggle whether the vertices represent a polygon (the default) or a polyline. For a polyline, the number of points and the length of the path joining them is returned; the path is not closed and the area is not reported. =item B<-e> I I specify the ellipsoid via the equatorial radius, I and the flattening, I. Setting I = 0 results in a sphere. Specify I E 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for I. By default, the WGS84 ellipsoid is used, I = 6378137 m, I = 1/298.257223563. If entering vertices as UTM/UPS or MGRS coordinates, use the default ellipsoid, since the conversion of these coordinates to latitude and longitude always uses the WGS84 parameters. =item B<-w> toggle the longitude first flag (it starts off); if the flag is on, then when reading geographic coordinates, longitude precedes latitude (this can be overridden by a hemisphere designator, I, I, I, I). =item B<-p> I set the output precision to I (default 6); the perimeter is given (in meters) with I digits after the decimal point; the area is given (in meters^2) with (I - 5) digits after the decimal point. =item B<-G> use the series formulation for the geodesics. This is the default option and is recommended for terrestrial applications. This option, B<-G>, and the following three options, B<-E>, B<-Q>, and B<-R>, are mutually exclusive. =item B<-E> use "exact" algorithms (based on elliptic integrals) for the geodesic calculations. These are more accurate than the (default) series expansions for |I| E 0.02. (But note that the implementation of areas in GeodesicExact uses a high order series and this is only accurate for modest flattenings.) =item B<-Q> perform the calculation on the authalic sphere. The area calculation is accurate even if the flattening is large, I the edges are sufficiently short. The perimeter calculation is not accurate. =item B<-R> The lines joining the vertices are rhumb lines instead of geodesics. =item B<--comment-delimiter> I set the comment delimiter to I (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing. For a given polygon, the last such string found will be appended to the output line (separated by a space). =item B<--version> print version and exit. =item B<-h> print usage and exit. =item B<--help> print full documentation and exit. =item B<--input-file> I read input from the file I instead of from standard input; a file name of "-" stands for standard input. =item B<--input-string> I read input from the string I instead of from standard input. All occurrences of the line separator character (default is a semicolon) in I are converted to newlines before the reading begins. =item B<--line-separator> I set the line separator character to I. By default this is a semicolon. =item B<--output-file> I write output to the file I instead of to standard output; a file name of "-" stands for standard output. =back =head1 EXAMPLES Example (the area of the 100km MGRS square 18SWK) Planimeter < 4 400139.53295860 10007388597.1913 The following code takes the output from gdalinfo and reports the area covered by the data (assuming the edges of the image are geodesics). #! /bin/sh egrep '^((Upper|Lower) (Left|Right)|Center) ' | sed -e 's/d /d/g' -e "s/' /'/g" | tr -s '(),\r\t' ' ' | awk '{ if ($1 $2 == "UpperLeft") ul = $6 " " $5; else if ($1 $2 == "LowerLeft") ll = $6 " " $5; else if ($1 $2 == "UpperRight") ur = $6 " " $5; else if ($1 $2 == "LowerRight") lr = $6 " " $5; else if ($1 == "Center") { printf "%s\n%s\n%s\n%s\n\n", ul, ll, lr, ur; ul = ll = ur = lr = ""; } } ' | Planimeter | cut -f3 -d' ' =head1 SEE ALSO GeoConvert(1), GeodSolve(1). An online version of this utility is availbable at L. The algorithm for the area of geodesic polygon is given in Section 6 of C. F. F. Karney, I, J. Geodesy 87, 43-55 (2013); DOI L; addenda: L. =head1 AUTHOR B was written by Charles Karney. =head1 HISTORY B was added to GeographicLib, L, in version 1.4. GeographicLib-1.49/man/Gravity.10000644000771000077100000003335013165402556016321 0ustar ckarneyckarney.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "GRAVITY 1" .TH GRAVITY 1 "2017-10-05" "GeographicLib 1.49" "GeographicLib Utilities" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Gravity \-\- compute the earth's gravity field .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBGravity\fR [ \fB\-n\fR \fIname\fR ] [ \fB\-d\fR \fIdir\fR ] [ \fB\-G\fR | \fB\-D\fR | \fB\-A\fR | \fB\-H\fR ] [ \fB\-c\fR \fIlat\fR \fIh\fR ] [ \fB\-w\fR ] [ \fB\-p\fR \fIprec\fR ] [ \fB\-v\fR ] [ \fB\-\-comment\-delimiter\fR \fIcommentdelim\fR ] [ \fB\-\-version\fR | \fB\-h\fR | \fB\-\-help\fR ] [ \fB\-\-input\-file\fR \fIinfile\fR | \fB\-\-input\-string\fR \fIinstring\fR ] [ \fB\-\-line\-separator\fR \fIlinesep\fR ] [ \fB\-\-output\-file\fR \fIoutfile\fR ] .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBGravity\fR reads in positions on standard input and prints out the gravitational field on standard output. .PP The input line is of the form \fIlat\fR \fIlon\fR \fIh\fR. \fIlat\fR and \fIlon\fR are the latitude and longitude expressed as decimal degrees or degrees, minutes, and seconds; for details on the allowed formats for latitude and longitude, see the \f(CW\*(C`GEOGRAPHIC COORDINATES\*(C'\fR section of \&\fIGeoConvert\fR\|(1). \fIh\fR is the height above the ellipsoid in meters; this quantity is optional and defaults to 0. Alternatively, the gravity field can be computed at various points on a circle of latitude (constant \fIlat\fR and \fIh\fR) via the \fB\-c\fR option; in this case only the longitude should be given on the input lines. The quantities printed out are governed by the \fB\-G\fR (default), \fB\-D\fR, \fB\-A\fR, or \fB\-H\fR options. .PP All the supported gravity models, except for grs80, use \s-1WGS84\s0 as the reference ellipsoid \fIa\fR = 6378137 m, \fIf\fR = 1/298.257223563, \fIomega\fR = 7292115e\-11 rad/s, and \fI\s-1GM\s0\fR = 3986004.418e8 m^3/s^2. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-n\fR \fIname\fR" 4 .IX Item "-n name" use gravity field model \fIname\fR instead of the default \f(CW\*(C`egm96\*(C'\fR. See \&\*(L"\s-1MODELS\*(R"\s0. .IP "\fB\-d\fR \fIdir\fR" 4 .IX Item "-d dir" read gravity models from \fIdir\fR instead of the default. See \&\*(L"\s-1MODELS\*(R"\s0. .IP "\fB\-G\fR" 4 .IX Item "-G" compute the acceleration due to gravity (including the centrifugal acceleration due the the earth's rotation) \fBg\fR. The output consists of \&\fIgx\fR \fIgy\fR \fIgz\fR (all in m/s^2), where the \fIx\fR, \fIy\fR, and \fIz\fR components are in easterly, northerly, and up directions, respectively. Usually \fIgz\fR is negative. .IP "\fB\-D\fR" 4 .IX Item "-D" compute the gravity disturbance \fBdelta\fR = \fBg\fR \- \fBgamma\fR, where \&\fBgamma\fR is the \*(L"normal\*(R" gravity due to the reference ellipsoid . The output consists of \fIdeltax\fR \fIdeltay\fR \fIdeltaz\fR (all in mGal, 1 mGal = 10^\-5 m/s^2), where the \fIx\fR, \fIy\fR, and \fIz\fR components are in easterly, northerly, and up directions, respectively. Note that \fIdeltax\fR = \&\fIgx\fR, because \fIgammax\fR = 0. .IP "\fB\-A\fR" 4 .IX Item "-A" computes the gravitational anomaly. The output consists of 3 items \&\fIDg01\fR \fIxi\fR \fIeta\fR, where \fIDg01\fR is in mGal (1 mGal = 10^\-5 m/s^2) and \fIxi\fR and \fIeta\fR are in arcseconds. The gravitational anomaly compares the gravitational field \fBg\fR at \fIP\fR with the normal gravity \&\fBgamma\fR at \fIQ\fR where the \fIP\fR is vertically above \fIQ\fR and the gravitational potential at \fIP\fR equals the normal potential at \fIQ\fR. \&\fIDg01\fR gives the difference in the magnitudes of these two vectors and \&\fIxi\fR and \fIeta\fR give the difference in their directions (as northerly and easterly components). The calculation uses a spherical approximation to match the results of the \s-1NGA\s0's synthesis programs. .IP "\fB\-H\fR" 4 .IX Item "-H" compute the height of the geoid above the reference ellipsoid (in meters). In this case, \fIh\fR should be zero. The results accurately match the results of the \s-1NGA\s0's synthesis programs. \fIGeoidEval\fR\|(1) can compute geoid heights much more quickly by interpolating on a grid of precomputed results; however the results from \fIGeoidEval\fR\|(1) are only accurate to a few millimeters. .IP "\fB\-c\fR \fIlat\fR \fIh\fR" 4 .IX Item "-c lat h" evaluate the field on a circle of latitude given by \fIlat\fR and \fIh\fR instead of reading these quantities from the input lines. In this case, \&\fBGravity\fR can calculate the field considerably more quickly. If geoid heights are being computed (the \fB\-H\fR option), then \fIh\fR must be zero. .IP "\fB\-w\fR" 4 .IX Item "-w" toggle the longitude first flag (it starts off); if the flag is on, then on input and output, longitude precedes latitude (except that, on input, this can be overridden by a hemisphere designator, \fIN\fR, \fIS\fR, \fIE\fR, \&\fIW\fR). .IP "\fB\-p\fR \fIprec\fR" 4 .IX Item "-p prec" set the output precision to \fIprec\fR. By default \fIprec\fR is 5 for acceleration due to gravity, 3 for the gravity disturbance and anomaly, and 4 for the geoid height. .IP "\fB\-v\fR" 4 .IX Item "-v" print information about the gravity model on standard error before processing the input. .IP "\fB\-\-comment\-delimiter\fR \fIcommentdelim\fR" 4 .IX Item "--comment-delimiter commentdelim" set the comment delimiter to \fIcommentdelim\fR (e.g., \*(L"#\*(R" or \*(L"//\*(R"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). .IP "\fB\-\-version\fR" 4 .IX Item "--version" print version and exit. .IP "\fB\-h\fR" 4 .IX Item "-h" print usage, the default gravity path and name, and exit. .IP "\fB\-\-help\fR" 4 .IX Item "--help" print full documentation and exit. .IP "\fB\-\-input\-file\fR \fIinfile\fR" 4 .IX Item "--input-file infile" read input from the file \fIinfile\fR instead of from standard input; a file name of \*(L"\-\*(R" stands for standard input. .IP "\fB\-\-input\-string\fR \fIinstring\fR" 4 .IX Item "--input-string instring" read input from the string \fIinstring\fR instead of from standard input. All occurrences of the line separator character (default is a semicolon) in \fIinstring\fR are converted to newlines before the reading begins. .IP "\fB\-\-line\-separator\fR \fIlinesep\fR" 4 .IX Item "--line-separator linesep" set the line separator character to \fIlinesep\fR. By default this is a semicolon. .IP "\fB\-\-output\-file\fR \fIoutfile\fR" 4 .IX Item "--output-file outfile" write output to the file \fIoutfile\fR instead of to standard output; a file name of \*(L"\-\*(R" stands for standard output. .SH "MODELS" .IX Header "MODELS" \&\fBGravity\fR computes the gravity field using one of the following models .PP .Vb 10 \& egm84, earth gravity model 1984. See \& http://earth\-info.nga.mil/GandG/wgs84/gravitymod/wgs84_180/wgs84_180.html \& egm96, earth gravity model 1996. See \& http://earth\-info.nga.mil/GandG/wgs84/gravitymod/egm96/egm96.html \& egm2008, earth gravity model 2008. See \& http://earth\-info.nga.mil/GandG/wgs84/gravitymod/egm2008 \& wgs84, world geodetic system 1984. This returns the normal \& gravity for the WGS84 ellipsoid. \& grs80, geodetic reference system 1980. This returns the normal \& gravity for the GRS80 ellipsoid. .Ve .PP These models approximate the gravitation field above the surface of the earth. By default, the \f(CW\*(C`egm96\*(C'\fR gravity model is used. This may changed by setting the environment variable \&\f(CW\*(C`GEOGRAPHICLIB_GRAVITY_NAME\*(C'\fR or with the \fB\-n\fR option. .PP The gravity models will be loaded from a directory specified at compile time. This may changed by setting the environment variables \&\f(CW\*(C`GEOGRAPHICLIB_GRAVITY_PATH\*(C'\fR or \f(CW\*(C`GEOGRAPHICLIB_DATA\*(C'\fR, or with the \&\fB\-d\fR option. The \fB\-h\fR option prints the default gravity path and name. Use the \fB\-v\fR option to ascertain the full path name of the data file. .PP Instructions for downloading and installing gravity models are available at . .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" .IP "\fB\s-1GEOGRAPHICLIB_GRAVITY_NAME\s0\fR" 4 .IX Item "GEOGRAPHICLIB_GRAVITY_NAME" Override the compile-time default gravity name of \f(CW\*(C`egm96\*(C'\fR. The \fB\-h\fR option reports the value of \fB\s-1GEOGRAPHICLIB_GRAVITY_NAME\s0\fR, if defined, otherwise it reports the compile-time value. If the \fB\-n\fR \fIname\fR option is used, then \fIname\fR takes precedence. .IP "\fB\s-1GEOGRAPHICLIB_GRAVITY_PATH\s0\fR" 4 .IX Item "GEOGRAPHICLIB_GRAVITY_PATH" Override the compile-time default gravity path. This is typically \&\f(CW\*(C`/usr/local/share/GeographicLib/gravity\*(C'\fR on Unix-like systems and \&\f(CW\*(C`C:/ProgramData/GeographicLib/gravity\*(C'\fR on Windows systems. The \fB\-h\fR option reports the value of \fB\s-1GEOGRAPHICLIB_GRAVITY_PATH\s0\fR, if defined, otherwise it reports the compile-time value. If the \fB\-d\fR \fIdir\fR option is used, then \fIdir\fR takes precedence. .IP "\fB\s-1GEOGRAPHICLIB_DATA\s0\fR" 4 .IX Item "GEOGRAPHICLIB_DATA" Another way of overriding the compile-time default gravity path. If it is set (and if \fB\s-1GEOGRAPHICLIB_GRAVITY_PATH\s0\fR is not set), then $\fB\s-1GEOGRAPHICLIB_DATA\s0\fR/gravity is used. .SH "ERRORS" .IX Header "ERRORS" An illegal line of input will print an error message to standard output beginning with \f(CW\*(C`ERROR:\*(C'\fR and causes \fBGravity\fR to return an exit code of 1. However, an error does not cause \fBGravity\fR to terminate; following lines will be converted. .SH "EXAMPLES" .IX Header "EXAMPLES" The gravity field from \s-1EGM2008\s0 at the top of Mount Everest .PP .Vb 2 \& echo 27:59:17N 86:55:32E 8820 | Gravity \-n egm2008 \& => \-0.00001 0.00103 \-9.76782 .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIGeoConvert\fR\|(1), \fIGeoidEval\fR\|(1), \fIgeographiclib\-get\-gravity\fR\|(8). .SH "AUTHOR" .IX Header "AUTHOR" \&\fBGravity\fR was written by Charles Karney. .SH "HISTORY" .IX Header "HISTORY" \&\fBGravity\fR was added to GeographicLib, , in version 1.16. GeographicLib-1.49/man/RhumbSolve.1.html0000644000771000077100000002565713165402556017740 0ustar ckarneyckarney RhumbSolve(1)

NAME

RhumbSolve -- perform rhumb line calculations

SYNOPSIS

RhumbSolve [ -i | -L lat1 lon1 azi12 ] [ -e a f ] [ -d | -: ] [ -w ] [ -p prec ] [ -s ] [ --comment-delimiter commentdelim ] [ --version | -h | --help ] [ --input-file infile | --input-string instring ] [ --line-separator linesep ] [ --output-file outfile ]

DESCRIPTION

The path with constant heading between two points on the ellipsoid at (lat1, lon1) and (lat2, lon2) is called the rhumb line or loxodrome. Its length is s12 and the rhumb line has a forward azimuth azi12 along its length. Also computed is S12 is the area between the rhumb line from point 1 to point 2 and the equator; i.e., it is the area, measured counter-clockwise, of the geodesic quadrilateral with corners (lat1,lon1), (0,lon1), (0,lon2), and (lat2,lon2). 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.

NOTE: the rhumb line is not the shortest path between two points; that is the geodesic and it is calculated by GeodSolve(1).

RhumbSolve operates in one of three modes:

  1. By default, RhumbSolve accepts lines on the standard input containing lat1 lon1 azi12 s12 and prints lat2 lon2 S12 on standard output. This is the direct calculation.

  2. With the -i command line argument, RhumbSolve performs the inverse calculation. It reads lines containing lat1 lon1 lat2 lon2 and prints the values of azi12 s12 S12 for the corresponding shortest rhumb lines. If the end points are on opposite meridians, there are two shortest rhumb lines and the east-going one is chosen.

  3. Command line arguments -L lat1 lon1 azi12 specify a rhumb line. RhumbSolve then accepts a sequence of s12 values (one per line) on standard input and prints lat2 lon2 S12 for each. This generates a sequence of points on a rhumb line.

OPTIONS

-i

perform an inverse calculation (see 2 above).

-L lat1 lon1 azi12

line mode (see 3 above); generate a sequence of points along the rhumb line specified by lat1 lon1 azi12. The -w flag can be used to swap the default order of the 2 geographic coordinates, provided that it appears before -L. (-l is an alternative, deprecated, spelling of this flag.)

-e a f

specify the ellipsoid via the equatorial radius, a and the flattening, f. Setting f = 0 results in a sphere. Specify f < 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for f. By default, the WGS84 ellipsoid is used, a = 6378137 m, f = 1/298.257223563.

-d

output angles as degrees, minutes, seconds instead of decimal degrees.

-:

like -d, except use : as a separator instead of the d, ', and " delimiters.

-w

on input and output, longitude precedes latitude (except that on input this can be overridden by a hemisphere designator, N, S, E, W).

-p prec

set the output precision to prec (default 3); prec is the precision relative to 1 m. See "PRECISION".

-s

By default, the rhumb line calculations are carried out exactly in terms of elliptic integrals. This includes the use of the addition theorem for elliptic integrals to compute the divided difference of the isometric and rectifying latitudes. If -s is supplied this divided difference is computed using Krueger series for the transverse Mercator projection which is only accurate for |f| < 0.01. See "ACCURACY".

--comment-delimiter commentdelim

set the comment delimiter to commentdelim (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space).

--version

print version and exit.

-h

print usage and exit.

--help

print full documentation and exit.

--input-file infile

read input from the file infile instead of from standard input; a file name of "-" stands for standard input.

--input-string instring

read input from the string instring instead of from standard input. All occurrences of the line separator character (default is a semicolon) in instring are converted to newlines before the reading begins.

--line-separator linesep

set the line separator character to linesep. By default this is a semicolon.

--output-file outfile

write output to the file outfile instead of to standard output; a file name of "-" stands for standard output.

INPUT

RhumbSolve measures all angles in degrees, all lengths (s12) in meters, and all areas (S12) in meters^2. On input angles (latitude, longitude, azimuth, arc length) can be as decimal degrees or degrees, minutes, seconds. For example, 40d30, 40d30', 40:30, 40.5d, and 40.5 are all equivalent. By default, latitude precedes longitude for each point (the -w flag switches this convention); however on input either may be given first by appending (or prepending) N or S to the latitude and E or W to the longitude. Azimuths are measured clockwise from north; however this may be overridden with E or W.

For details on the allowed formats for angles, see the GEOGRAPHIC COORDINATES section of GeoConvert(1).

PRECISION

prec gives precision of the output with prec = 0 giving 1 m precision, prec = 3 giving 1 mm precision, etc. prec is the number of digits after the decimal point for lengths. For decimal degrees, the number of digits after the decimal point is prec + 5. For DMS (degree, minute, seconds) output, the number of digits after the decimal point in the seconds component is prec + 1. The minimum value of prec is 0 and the maximum is 10.

ERRORS

An illegal line of input will print an error message to standard output beginning with ERROR: and causes RhumbSolve to return an exit code of 1. However, an error does not cause RhumbSolve to terminate; following lines will be converted.

ACCURACY

The algorithm used by RhumbSolve uses exact formulas for converting between the latitude, rectifying latitude (mu), and isometric latitude (psi). These formulas are accurate for any value of the flattening. The computation of rhumb lines involves the ratio (psi1 - psi2) / (mu1 - mu2) and this is subject to large round-off errors if lat1 is close to lat2. So this ratio is computed using divided differences using one of two methods: by default, this uses the addition theorem for elliptic integrals (accurate for all values of f); however, with the -s options, it is computed using the series expansions used by TransverseMercatorProj(1) for the conversions between rectifying and conformal latitudes (accurate for |f| < 0.01). For the WGS84 ellipsoid, the error is about 10 nanometers using either method.

EXAMPLES

Route from JFK Airport to Singapore Changi Airport:

   echo 40:38:23N 073:46:44W 01:21:33N 103:59:22E |
   RhumbSolve -i -: -p 0

   103:34:58.2 18523563

N.B. This is not the route typically taken by aircraft because it's considerably longer than the geodesic given by GeodSolve(1).

Waypoints on the route at intervals of 2000km:

   for ((i = 0; i <= 20; i += 2)); do echo ${i}000000;done |
   RhumbSolve -L 40:38:23N 073:46:44W 103:34:58.2 -: -p 0

   40:38:23.0N 073:46:44.0W 0
   36:24:30.3N 051:28:26.4W 9817078307821
   32:10:26.8N 030:20:57.3W 18224745682005
   27:56:13.2N 010:10:54.2W 25358020327741
   23:41:50.1N 009:12:45.5E 31321269267102
   19:27:18.7N 027:59:22.1E 36195163180159
   15:12:40.2N 046:17:01.1E 40041499143669
   10:57:55.9N 064:12:52.8E 42906570007050
   06:43:07.3N 081:53:28.8E 44823504180200
   02:28:16.2N 099:24:54.5E 45813843358737
   01:46:36.0S 116:52:59.7E 45888525219677

SEE ALSO

GeoConvert(1), GeodSolve(1), TransverseMercatorProj(1).

An online version of this utility is availbable at https://geographiclib.sourceforge.io/cgi-bin/RhumbSolve.

The Wikipedia page, Rhumb line, https://en.wikipedia.org/wiki/Rhumb_line.

AUTHOR

RhumbSolve was written by Charles Karney.

HISTORY

RhumbSolve was added to GeographicLib, https://geographiclib.sourceforge.io, in version 1.37.

GeographicLib-1.49/man/GeoidEval.1.html0000644000771000077100000003301613165402556017475 0ustar ckarneyckarney GeoidEval(1)

NAME

GeoidEval -- look up geoid heights

SYNOPSIS

GeoidEval [ -n name ] [ -d dir ] [ -l ] [ -a | -c south west north east ] [ -w ] [ -z zone ] [ --msltohae ] [ --haetomsl ] [ -v ] [ --comment-delimiter commentdelim ] [ --version | -h | --help ] [ --input-file infile | --input-string instring ] [ --line-separator linesep ] [ --output-file outfile ]

DESCRIPTION

GeoidEval reads in positions on standard input and prints out the corresponding heights of the geoid above the WGS84 ellipsoid on standard output.

Positions are given as latitude and longitude, UTM/UPS, or MGRS, in any of the formats accepted by GeoConvert(1). (MGRS coordinates signify the center of the corresponding MGRS square.) If the -z option is specified then the specified zone is prepended to each line of input (which must be in UTM/UPS coordinates). This allows a file with UTM eastings and northings in a single zone to be used as standard input.

More accurate results for the geoid height are provided by Gravity(1). This utility can also compute the direction of gravity accurately.

The height of the geoid above the ellipsoid, N, is sometimes called the geoid undulation. It can be used to convert a height above the ellipsoid, h, to the corresponding height above the geoid (the orthometric height, roughly the height above mean sea level), H, using the relations

    h = N + H,   H = -N + h.

OPTIONS

-n name

use geoid name instead of the default egm96-5. See "GEOIDS".

-d dir

read geoid data from dir instead of the default. See "GEOIDS".

-l

use bilinear interpolation instead of cubic. See "INTERPOLATION".

-a

cache the entire data set in memory. See "CACHE".

-c south west north east

cache the data bounded by south west north east in memory. The first two arguments specify the SW corner of the cache and the last two arguments specify the NE corner. The -w flag specifies that longitude precedes latitude for these corners, provided that it appears before -c. See "CACHE".

-w

toggle the longitude first flag (it starts off); if the flag is on, then when reading geographic coordinates, longitude precedes latitude (this can be overridden by a hemisphere designator, N, S, E, W).

-z zone

prefix each line of input by zone, e.g., 38n. This should be used when the input consists of UTM/UPS eastings and northings.

--msltohae

standard input should include a final token on each line which is treated as a height (in meters) above the geoid and the output echoes the input line with the height converted to height above ellipsoid (HAE). If -z zone is specified then the third token is treated as the height; this makes it possible to convert LIDAR data where each line consists of: easting northing height intensity.

--haetomsl

this is similar to --msltohae except that the height token is treated as a height (in meters) above the ellipsoid and the output echoes the input line with the height converted to height above the geoid (MSL).

-v

print information about the geoid on standard error before processing the input.

--comment-delimiter commentdelim

set the comment delimiter to commentdelim (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space).

--version

print version and exit.

-h

print usage, the default geoid path and name, and exit.

--help

print full documentation and exit.

--input-file infile

read input from the file infile instead of from standard input; a file name of "-" stands for standard input.

--input-string instring

read input from the string instring instead of from standard input. All occurrences of the line separator character (default is a semicolon) in instring are converted to newlines before the reading begins.

--line-separator linesep

set the line separator character to linesep. By default this is a semicolon.

--output-file outfile

write output to the file outfile instead of to standard output; a file name of "-" stands for standard output.

GEOIDS

GeoidEval computes geoid heights by interpolating on the data in a regularly spaced table (see "INTERPOLATION"). The following geoid tables are available (however, some may not be installed):

                                  bilinear error    cubic error
   name         geoid    grid     max      rms      max      rms
   egm84-30     EGM84    30'      1.546 m  70 mm    0.274 m  14 mm
   egm84-15     EGM84    15'      0.413 m  18 mm    0.021 m  1.2 mm
   egm96-15     EGM96    15'      1.152 m  40 mm    0.169 m  7.0 mm
   egm96-5      EGM96     5'      0.140 m  4.6 mm   .0032 m  0.7 mm
   egm2008-5    EGM2008   5'      0.478 m  12 mm    0.294 m  4.5 mm
   egm2008-2_5  EGM2008   2.5'    0.135 m  3.2 mm   0.031 m  0.8 mm
   egm2008-1    EGM2008   1'      0.025 m  0.8 mm   .0022 m  0.7 mm

By default, the egm96-5 geoid is used. This may changed by setting the environment variable GEOGRAPHICLIB_GEOID_NAME or with the -n option. The errors listed here are estimates of the quantization and interpolation errors in the reported heights compared to the specified geoid.

The geoid data will be loaded from a directory specified at compile time. This may changed by setting the environment variables GEOGRAPHICLIB_GEOID_PATH or GEOGRAPHICLIB_DATA, or with the -d option. The -h option prints the default geoid path and name. Use the -v option to ascertain the full path name of the data file.

Instructions for downloading and installing geoid data are available at https://geographiclib.sourceforge.io/html/geoid.html#geoidinst.

NOTE: all the geoids above apply to the WGS84 ellipsoid (a = 6378137 m, f = 1/298.257223563) only.

INTERPOLATION

Cubic interpolation is used to compute the geoid height unless -l is specified in which case bilinear interpolation is used. The cubic interpolation is based on a least-squares fit of a cubic polynomial to a 12-point stencil

   . 1 1 .
   1 2 2 1
   1 2 2 1
   . 1 1 .

The cubic is constrained to be independent of longitude when evaluating the height at one of the poles. Cubic interpolation is considerably more accurate than bilinear; however it results in small discontinuities in the returned height on cell boundaries.

CACHE

By default, the data file is randomly read to compute the geoid heights at the input positions. Usually this is sufficient for interactive use. If many heights are to be computed, use -c south west north east to notify GeoidEval to read a rectangle of data into memory; heights within the this rectangle can then be computed without any disk access. If -a is specified all the geoid data is read; in the case of egm2008-1, this requires about 0.5 GB of RAM. The evaluation of heights outside the cached area causes the necessary data to be read from disk. Use the -v option to verify the size of the cache.

Regardless of whether any cache is requested (with the -a or -c options), the data for the last grid cell in cached. This allows the geoid height along a continuous path to be returned with little disk overhead.

ENVIRONMENT

GEOGRAPHICLIB_GEOID_NAME

Override the compile-time default geoid name of egm96-5. The -h option reports the value of GEOGRAPHICLIB_GEOID_NAME, if defined, otherwise it reports the compile-time value. If the -n name option is used, then name takes precedence.

GEOGRAPHICLIB_GEOID_PATH

Override the compile-time default geoid path. This is typically /usr/local/share/GeographicLib/geoids on Unix-like systems and C:/ProgramData/GeographicLib/geoids on Windows systems. The -h option reports the value of GEOGRAPHICLIB_GEOID_PATH, if defined, otherwise it reports the compile-time value. If the -d dir option is used, then dir takes precedence.

GEOGRAPHICLIB_DATA

Another way of overriding the compile-time default geoid path. If it is set (and if GEOGRAPHICLIB_GEOID_PATH is not set), then $GEOGRAPHICLIB_DATA/geoids is used.

ERRORS

An illegal line of input will print an error message to standard output beginning with ERROR: and causes GeoidEval to return an exit code of 1. However, an error does not cause GeoidEval to terminate; following lines will be converted.

ABBREVIATIONS

The geoid is usually approximated by an "earth gravity model". The models published by the NGA are:

EGM84

An earth gravity model published by the NGA in 1984, http://earth-info.nga.mil/GandG/wgs84/gravitymod/wgs84_180/wgs84_180.html.

EGM96

An earth gravity model published by the NGA in 1996, http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/egm96.html.

EGM2008

An earth gravity model published by the NGA in 2008, http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008.

WGS84

World Geodetic System 1984, https://en.wikipedia.org/wiki/WGS84.

HAE

Height above the WGS84 ellipsoid.

MSL

Mean sea level, used as a convenient short hand for the geoid. (However, typically, the geoid differs by a few meters from mean sea level.)

EXAMPLES

The height of the EGM96 geoid at Timbuktu

    echo 16:46:33N 3:00:34W | GeoidEval
    => 28.7068 -0.02e-6 -1.73e-6

The first number returned is the height of the geoid and the 2nd and 3rd are its slopes in the northerly and easterly directions.

Convert a point in UTM zone 18n from MSL to HAE

   echo 531595 4468135 23 | GeoidEval --msltohae -z 18n
   => 531595 4468135 -10.842

SEE ALSO

GeoConvert(1), Gravity(1), geographiclib-get-geoids(8).

An online version of this utility is availbable at https://geographiclib.sourceforge.io/cgi-bin/GeoidEval.

AUTHOR

GeoidEval was written by Charles Karney.

HISTORY

GeoidEval was added to GeographicLib, https://geographiclib.sourceforge.io, in 2009-09.

GeographicLib-1.49/man/GeodesicProj.pod0000644000771000077100000001306113165402514017662 0ustar ckarneyckarney=head1 NAME GeodesicProj -- perform projections based on geodesics =head1 SYNOPSIS B ( B<-z> | B<-c> | B<-g> ) I I [ B<-r> ] [ B<-e> I I ] [ B<-w> ] [ B<-p> I ] [ B<--comment-delimiter> I ] [ B<--version> | B<-h> | B<--help> ] [ B<--input-file> I | B<--input-string> I ] [ B<--line-separator> I ] [ B<--output-file> I ] =head1 DESCRIPTION Perform projections based on geodesics. Convert geodetic coordinates to either azimuthal equidistant, Cassini-Soldner, or gnomonic coordinates. The center of the projection (I, I) is specified by either the B<-c> option (for Cassini-Soldner), the B<-z> option (for azimuthal equidistant), or the B<-g> option (for gnomonic). At least one of these options must be given (the last one given is used). Geodetic coordinates are provided on standard input as a set of lines containing (blank separated) I and I (decimal degrees or degrees, minutes, seconds); for details on the allowed formats for latitude and longitude, see the C section of GeoConvert(1). For each set of geodetic coordinates, the corresponding projected coordinates I, I (meters) are printed on standard output together with the azimuth I (degrees) and reciprocal scale I. For Cassini-Soldner, I is the bearing of the easting direction and the scale in the easting direction is 1 and the scale in the northing direction is 1/I. For azimuthal equidistant and gnomonic, I is the bearing of the radial direction and the scale in the azimuthal direction is 1/I. For azimuthal equidistant and gnomonic, the scales in the radial direction are 1 and 1/I^2, respectively. =head1 OPTIONS =over =item B<-z> I I use the azimuthal equidistant projection centered at latitude = I, longitude = I. The B<-w> flag can be used to swap the default order of the 2 coordinates, provided that it appears before B<-z>. =item B<-c> I I use the Cassini-Soldner projection centered at latitude = I, longitude = I. The B<-w> flag can be used to swap the default order of the 2 coordinates, provided that it appears before B<-c>. =item B<-g> I I use the ellipsoidal gnomonic projection centered at latitude = I, longitude = I. The B<-w> flag can be used to swap the default order of the 2 coordinates, provided that it appears before B<-g>. =item B<-r> perform the reverse projection. I and I are given on standard input and each line of standard output gives I, I, I, and I. =item B<-e> I I specify the ellipsoid via the equatorial radius, I and the flattening, I. Setting I = 0 results in a sphere. Specify I E 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for I. By default, the WGS84 ellipsoid is used, I = 6378137 m, I = 1/298.257223563. =item B<-w> toggle the longitude first flag (it starts off); if the flag is on, then on input and output, longitude precedes latitude (except that, on input, this can be overridden by a hemisphere designator, I, I, I, I). =item B<-p> I set the output precision to I (default 6). I is the number of digits after the decimal point for lengths (in meters). For latitudes, longitudes, and azimuths (in degrees), the number of digits after the decimal point is I + 5. For the scale, the number of digits after the decimal point is I + 6. =item B<--comment-delimiter> I set the comment delimiter to I (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). =item B<--version> print version and exit. =item B<-h> print usage and exit. =item B<--help> print full documentation and exit. =item B<--input-file> I read input from the file I instead of from standard input; a file name of "-" stands for standard input. =item B<--input-string> I read input from the string I instead of from standard input. All occurrences of the line separator character (default is a semicolon) in I are converted to newlines before the reading begins. =item B<--line-separator> I set the line separator character to I. By default this is a semicolon. =item B<--output-file> I write output to the file I instead of to standard output; a file name of "-" stands for standard output. =back =head1 EXAMPLES echo 48.648 -2.007 | GeodesicProj -c 48.836 2.337 => -319919 -11791 86.7 0.999 echo -319919 -11791 | GeodesicProj -c 48.836 2.337 -r => 48.648 -2.007 86.7 0.999 =head1 ERRORS An illegal line of input will print an error message to standard output beginning with C and causes B to return an exit code of 1. However, an error does not cause B to terminate; following lines will be converted. =head1 SEE ALSO The ellipsoidal gnomonic projection is derived in Section 8 of C. F. F. Karney, I, J. Geodesy 87, 43-55 (2013); DOI L; addenda: L. =head1 AUTHOR B was written by Charles Karney. =head1 HISTORY B was added to GeographicLib, L, in 2009-08. Prior to version 1.9 it was called EquidistantTest. GeographicLib-1.49/man/GeoidEval.pod0000644000771000077100000002442313165402514017150 0ustar ckarneyckarney=head1 NAME GeoidEval -- look up geoid heights =head1 SYNOPSIS B [ B<-n> I ] [ B<-d> I ] [ B<-l> ] [ B<-a> | B<-c> I I I I ] [ B<-w> ] [ B<-z> I ] [ B<--msltohae> ] [ B<--haetomsl> ] [ B<-v> ] [ B<--comment-delimiter> I ] [ B<--version> | B<-h> | B<--help> ] [ B<--input-file> I | B<--input-string> I ] [ B<--line-separator> I ] [ B<--output-file> I ] =head1 DESCRIPTION B reads in positions on standard input and prints out the corresponding heights of the geoid above the WGS84 ellipsoid on standard output. Positions are given as latitude and longitude, UTM/UPS, or MGRS, in any of the formats accepted by GeoConvert(1). (MGRS coordinates signify the I
of the corresponding MGRS square.) If the B<-z> option is specified then the specified zone is prepended to each line of input (which must be in UTM/UPS coordinates). This allows a file with UTM eastings and northings in a single zone to be used as standard input. More accurate results for the geoid height are provided by Gravity(1). This utility can also compute the direction of gravity accurately. The height of the geoid above the ellipsoid, I, is sometimes called the geoid undulation. It can be used to convert a height above the ellipsoid, I, to the corresponding height above the geoid (the orthometric height, roughly the height above mean sea level), I, using the relations =over I = I + I, EEI = -I + I. =back =head1 OPTIONS =over =item B<-n> I use geoid I instead of the default C. See L. =item B<-d> I read geoid data from I instead of the default. See L. =item B<-l> use bilinear interpolation instead of cubic. See L. =item B<-a> cache the entire data set in memory. See L. =item B<-c> I I I I cache the data bounded by I I I I in memory. The first two arguments specify the SW corner of the cache and the last two arguments specify the NE corner. The B<-w> flag specifies that longitude precedes latitude for these corners, provided that it appears before B<-c>. See L. =item B<-w> toggle the longitude first flag (it starts off); if the flag is on, then when reading geographic coordinates, longitude precedes latitude (this can be overridden by a hemisphere designator, I, I, I, I). =item B<-z> I prefix each line of input by I, e.g., C<38n>. This should be used when the input consists of UTM/UPS eastings and northings. =item B<--msltohae> standard input should include a final token on each line which is treated as a height (in meters) above the geoid and the output echoes the input line with the height converted to height above ellipsoid (HAE). If B<-z> I is specified then the I token is treated as the height; this makes it possible to convert LIDAR data where each line consists of: easting northing height intensity. =item B<--haetomsl> this is similar to B<--msltohae> except that the height token is treated as a height (in meters) above the ellipsoid and the output echoes the input line with the height converted to height above the geoid (MSL). =item B<-v> print information about the geoid on standard error before processing the input. =item B<--comment-delimiter> I set the comment delimiter to I (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). =item B<--version> print version and exit. =item B<-h> print usage, the default geoid path and name, and exit. =item B<--help> print full documentation and exit. =item B<--input-file> I read input from the file I instead of from standard input; a file name of "-" stands for standard input. =item B<--input-string> I read input from the string I instead of from standard input. All occurrences of the line separator character (default is a semicolon) in I are converted to newlines before the reading begins. =item B<--line-separator> I set the line separator character to I. By default this is a semicolon. =item B<--output-file> I write output to the file I instead of to standard output; a file name of "-" stands for standard output. =back =head1 GEOIDS B computes geoid heights by interpolating on the data in a regularly spaced table (see L). The following geoid tables are available (however, some may not be installed): bilinear error cubic error name geoid grid max rms max rms egm84-30 EGM84 30' 1.546 m 70 mm 0.274 m 14 mm egm84-15 EGM84 15' 0.413 m 18 mm 0.021 m 1.2 mm egm96-15 EGM96 15' 1.152 m 40 mm 0.169 m 7.0 mm egm96-5 EGM96 5' 0.140 m 4.6 mm .0032 m 0.7 mm egm2008-5 EGM2008 5' 0.478 m 12 mm 0.294 m 4.5 mm egm2008-2_5 EGM2008 2.5' 0.135 m 3.2 mm 0.031 m 0.8 mm egm2008-1 EGM2008 1' 0.025 m 0.8 mm .0022 m 0.7 mm By default, the C geoid is used. This may changed by setting the environment variable C or with the B<-n> option. The errors listed here are estimates of the quantization and interpolation errors in the reported heights compared to the specified geoid. The geoid data will be loaded from a directory specified at compile time. This may changed by setting the environment variables C or C, or with the B<-d> option. The B<-h> option prints the default geoid path and name. Use the B<-v> option to ascertain the full path name of the data file. Instructions for downloading and installing geoid data are available at L. B: all the geoids above apply to the WGS84 ellipsoid (I = 6378137 m, I = 1/298.257223563) only. =head1 INTERPOLATION Cubic interpolation is used to compute the geoid height unless B<-l> is specified in which case bilinear interpolation is used. The cubic interpolation is based on a least-squares fit of a cubic polynomial to a 12-point stencil . 1 1 . 1 2 2 1 1 2 2 1 . 1 1 . The cubic is constrained to be independent of longitude when evaluating the height at one of the poles. Cubic interpolation is considerably more accurate than bilinear; however it results in small discontinuities in the returned height on cell boundaries. =head1 CACHE By default, the data file is randomly read to compute the geoid heights at the input positions. Usually this is sufficient for interactive use. If many heights are to be computed, use B<-c> I I I I to notify B to read a rectangle of data into memory; heights within the this rectangle can then be computed without any disk access. If B<-a> is specified all the geoid data is read; in the case of C, this requires about 0.5 GB of RAM. The evaluation of heights outside the cached area causes the necessary data to be read from disk. Use the B<-v> option to verify the size of the cache. Regardless of whether any cache is requested (with the B<-a> or B<-c> options), the data for the last grid cell in cached. This allows the geoid height along a continuous path to be returned with little disk overhead. =head1 ENVIRONMENT =over =item B Override the compile-time default geoid name of C. The B<-h> option reports the value of B, if defined, otherwise it reports the compile-time value. If the B<-n> I option is used, then I takes precedence. =item B Override the compile-time default geoid path. This is typically C on Unix-like systems and C on Windows systems. The B<-h> option reports the value of B, if defined, otherwise it reports the compile-time value. If the B<-d> I option is used, then I takes precedence. =item B Another way of overriding the compile-time default geoid path. If it is set (and if B is not set), then $B/geoids is used. =back =head1 ERRORS An illegal line of input will print an error message to standard output beginning with C and causes B to return an exit code of 1. However, an error does not cause B to terminate; following lines will be converted. =head1 ABBREVIATIONS The geoid is usually approximated by an "earth gravity model". The models published by the NGA are: =over =item B An earth gravity model published by the NGA in 1984, L. =item B An earth gravity model published by the NGA in 1996, L. =item B An earth gravity model published by the NGA in 2008, L. =item B World Geodetic System 1984, L. =item B Height above the WGS84 ellipsoid. =item B Mean sea level, used as a convenient short hand for the geoid. (However, typically, the geoid differs by a few meters from mean sea level.) =back =head1 EXAMPLES The height of the EGM96 geoid at Timbuktu echo 16:46:33N 3:00:34W | GeoidEval => 28.7068 -0.02e-6 -1.73e-6 The first number returned is the height of the geoid and the 2nd and 3rd are its slopes in the northerly and easterly directions. Convert a point in UTM zone 18n from MSL to HAE echo 531595 4468135 23 | GeoidEval --msltohae -z 18n => 531595 4468135 -10.842 =head1 SEE ALSO GeoConvert(1), Gravity(1), geographiclib-get-geoids(8). An online version of this utility is availbable at L. =head1 AUTHOR B was written by Charles Karney. =head1 HISTORY B was added to GeographicLib, L, in 2009-09. GeographicLib-1.49/man/TransverseMercatorProj.10000644000771000077100000002501513165402556021357 0ustar ckarneyckarney.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "TRANSVERSEMERCATORPROJ 1" .TH TRANSVERSEMERCATORPROJ 1 "2017-10-05" "GeographicLib 1.49" "GeographicLib Utilities" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" TransverseMercatorProj \-\- perform transverse Mercator projection .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBTransverseMercatorProj\fR [ \fB\-s\fR | \fB\-t\fR ] [ \fB\-l\fR \fIlon0\fR ] [ \fB\-k\fR \fIk0\fR ] [ \fB\-r\fR ] [ \fB\-e\fR \fIa\fR \fIf\fR ] [ \fB\-w\fR ] [ \fB\-p\fR \fIprec\fR ] [ \fB\-\-comment\-delimiter\fR \fIcommentdelim\fR ] [ \fB\-\-version\fR | \fB\-h\fR | \fB\-\-help\fR ] [ \fB\-\-input\-file\fR \fIinfile\fR | \fB\-\-input\-string\fR \fIinstring\fR ] [ \fB\-\-line\-separator\fR \fIlinesep\fR ] [ \fB\-\-output\-file\fR \fIoutfile\fR ] .SH "DESCRIPTION" .IX Header "DESCRIPTION" Perform the transverse Mercator projections. Convert geodetic coordinates to transverse Mercator coordinates. The central meridian is given by \fIlon0\fR. The longitude of origin is the equator. The scale on the central meridian is \fIk0\fR. By default an implementation of the exact transverse Mercator projection is used. .PP Geodetic coordinates are provided on standard input as a set of lines containing (blank separated) \fIlatitude\fR and \fIlongitude\fR (decimal degrees or degrees, minutes, seconds); for detils on the allowed formats for latitude and longitude, see the \f(CW\*(C`GEOGRAPHIC COORDINATES\*(C'\fR section of \fIGeoConvert\fR\|(1). For each set of geodetic coordinates, the corresponding projected easting, \fIx\fR, and northing, \fIy\fR, (meters) are printed on standard output together with the meridian convergence \&\fIgamma\fR (degrees) and scale \fIk\fR. The meridian convergence is the bearing of grid north (the \fIy\fR axis) measured clockwise from true north. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-s\fR" 4 .IX Item "-s" use the sixth-order Krueger series approximation to the transverse Mercator projection instead of the exact projection. .IP "\fB\-t\fR" 4 .IX Item "-t" use the exact algorithm with the \*(L"\s-1EXTENDED DOMAIN\*(R"\s0. .IP "\fB\-l\fR \fIlon0\fR" 4 .IX Item "-l lon0" specify the longitude of origin \fIlon0\fR (degrees, default 0). .IP "\fB\-k\fR \fIk0\fR" 4 .IX Item "-k k0" specify the scale \fIk0\fR on the central meridian (default 0.9996). .IP "\fB\-r\fR" 4 .IX Item "-r" perform the reverse projection. \fIx\fR and \fIy\fR are given on standard input and each line of standard output gives \fIlatitude\fR, \fIlongitude\fR, \&\fIgamma\fR, and \fIk\fR. .IP "\fB\-e\fR \fIa\fR \fIf\fR" 4 .IX Item "-e a f" specify the ellipsoid via the equatorial radius, \fIa\fR and the flattening, \fIf\fR. Setting \fIf\fR = 0 results in a sphere. Specify \&\fIf\fR < 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for \fIf\fR. By default, the \s-1WGS84\s0 ellipsoid is used, \fIa\fR = 6378137 m, \fIf\fR = 1/298.257223563. If the exact algorithm is used, \fIf\fR must be positive. .IP "\fB\-w\fR" 4 .IX Item "-w" on input and output, longitude precedes latitude (except that on input this can be overridden by a hemisphere designator, \fIN\fR, \fIS\fR, \fIE\fR, \&\fIW\fR). .IP "\fB\-p\fR \fIprec\fR" 4 .IX Item "-p prec" set the output precision to \fIprec\fR (default 6). \fIprec\fR is the number of digits after the decimal point for lengths (in meters). For latitudes and longitudes (in degrees), the number of digits after the decimal point is \fIprec\fR + 5. For the convergence (in degrees) and scale, the number of digits after the decimal point is \fIprec\fR + 6. .IP "\fB\-\-comment\-delimiter\fR \fIcommentdelim\fR" 4 .IX Item "--comment-delimiter commentdelim" set the comment delimiter to \fIcommentdelim\fR (e.g., \*(L"#\*(R" or \*(L"//\*(R"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). .IP "\fB\-\-version\fR" 4 .IX Item "--version" print version and exit. .IP "\fB\-h\fR" 4 .IX Item "-h" print usage and exit. .IP "\fB\-\-help\fR" 4 .IX Item "--help" print full documentation and exit. .IP "\fB\-\-input\-file\fR \fIinfile\fR" 4 .IX Item "--input-file infile" read input from the file \fIinfile\fR instead of from standard input; a file name of \*(L"\-\*(R" stands for standard input. .IP "\fB\-\-input\-string\fR \fIinstring\fR" 4 .IX Item "--input-string instring" read input from the string \fIinstring\fR instead of from standard input. All occurrences of the line separator character (default is a semicolon) in \fIinstring\fR are converted to newlines before the reading begins. .IP "\fB\-\-line\-separator\fR \fIlinesep\fR" 4 .IX Item "--line-separator linesep" set the line separator character to \fIlinesep\fR. By default this is a semicolon. .IP "\fB\-\-output\-file\fR \fIoutfile\fR" 4 .IX Item "--output-file outfile" write output to the file \fIoutfile\fR instead of to standard output; a file name of \*(L"\-\*(R" stands for standard output. .SH "EXTENDED DOMAIN" .IX Header "EXTENDED DOMAIN" The exact transverse Mercator projection has a \fIbranch point\fR on the equator at longitudes (relative to \fIlon0\fR) of +/\- (1 \- \fIe\fR) 90, where \&\fIe\fR is the eccentricity of the ellipsoid. The standard convention for handling this branch point is to map positive (negative) latitudes into positive (negative) northings \fIy\fR; i.e., a branch cut is placed on the equator. With the \fIextended\fR domain, the northern sheet of the projection is extended into the south hemisphere by pushing the branch cut south from the branch points. See the reference below for details. .SH "EXAMPLES" .IX Header "EXAMPLES" .Vb 4 \& echo 0 90 | TransverseMercatorProj \& => 25953592.84 9997964.94 90 18.40 \& echo 260e5 100e5 | TransverseMercatorProj \-r \& => \-0.02 90.00 90.01 18.48 .Ve .SH "ERRORS" .IX Header "ERRORS" An illegal line of input will print an error message to standard output beginning with \f(CW\*(C`ERROR:\*(C'\fR and causes \fBTransverseMercatorProj\fR to return an exit code of 1. However, an error does not cause \fBTransverseMercatorProj\fR to terminate; following lines will be converted. .SH "AUTHOR" .IX Header "AUTHOR" \&\fBTransverseMercatorProj\fR was written by Charles Karney. .SH "SEE ALSO" .IX Header "SEE ALSO" The algorithms for the transverse Mercator projection are described in C. F. F. Karney, \fITransverse Mercator with an accuracy of a few nanometers\fR, J. Geodesy \fB85\fR(8), 475\-485 (Aug. 2011); \s-1DOI\s0 ; preprint . The explanation of the extended domain of the projection with the \fB\-t\fR option is given in Section 5 of this paper. .SH "HISTORY" .IX Header "HISTORY" \&\fBTransverseMercatorProj\fR was added to GeographicLib, , in 2009\-01. Prior to version 1.9 it was called TransverseMercatorTest (and its interface was slightly different). GeographicLib-1.49/man/GeoConvert.10000644000771000077100000004755213165402556016760 0ustar ckarneyckarney.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "GEOCONVERT 1" .TH GEOCONVERT 1 "2017-10-05" "GeographicLib 1.49" "GeographicLib Utilities" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" GeoConvert \-\- convert geographic coordinates .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBGeoConvert\fR [ \fB\-g\fR | \fB\-d\fR | \fB\-:\fR | \fB\-u\fR | \fB\-m\fR | \fB\-c\fR ] [ \fB\-z\fR \fIzone\fR | \fB\-s\fR | \fB\-t\fR | \fB\-S\fR | \fB\-T\fR ] [ \fB\-n\fR ] [ \fB\-w\fR ] [ \fB\-p\fR \fIprec\fR ] [ \fB\-l\fR | \fB\-a\fR ] [ \fB\-\-comment\-delimiter\fR \fIcommentdelim\fR ] [ \fB\-\-version\fR | \fB\-h\fR | \fB\-\-help\fR ] [ \fB\-\-input\-file\fR \fIinfile\fR | \fB\-\-input\-string\fR \fIinstring\fR ] [ \fB\-\-line\-separator\fR \fIlinesep\fR ] [ \fB\-\-output\-file\fR \fIoutfile\fR ] .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBGeoConvert\fR reads from standard input interpreting each line as a geographic coordinate and prints the coordinate in the format specified by the options on standard output. The input is interpreted in one of three different ways depending on how many space or comma delimited tokens there are on the line. The options \fB\-g\fR, \fB\-d\fR, \fB\-u\fR, and \fB\-m\fR govern the format of output. In all cases, the \s-1WGS84\s0 model of the earth is used (\fIa\fR = 6378137 m, \fIf\fR = 1/298.257223563). .IP "\fBgeographic\fR" 4 .IX Item "geographic" 2 tokens (output options \fB\-g\fR, \fB\-d\fR, or \fB\-:\fR) given as \fIlatitude\fR \&\fIlongitude\fR using decimal degrees or degrees, minutes, and seconds. Latitude is given first (unless the \fB\-w\fR option is given). See \&\*(L"\s-1GEOGRAPHIC COORDINATES\*(R"\s0 for a description of the format. For example, the following are all equivalent .Sp .Vb 5 \& 33.3 44.4 \& E44.4 N33.3 \& 33d18\*(AqN 44d24\*(AqE \& 44d24 33d18N \& 33:18 +44:24 .Ve .IP "\fB\s-1UTM/UPS\s0\fR" 4 .IX Item "UTM/UPS" 3 tokens (output option \fB\-u\fR) given as \fIzone\fR+\fIhemisphere\fR \fIeasting\fR \&\fInorthing\fR or \fIeasting\fR \fInorthing\fR \fIzone\fR+\fIhemisphere\fR, where \&\fIhemisphere\fR is either \fIn\fR (or \fInorth\fR) or \fIs\fR (or \fIsouth\fR). The \&\fIzone\fR is absent for a \s-1UPS\s0 specification. For example, .Sp .Vb 4 \& 38n 444140.54 3684706.36 \& 444140.54 3684706.36 38n \& s 2173854.98 2985980.58 \& 2173854.98 2985980.58 s .Ve .IP "\fB\s-1MRGS\s0\fR" 4 .IX Item "MRGS" 1 token (output option \fB\-m\fR) is used to specify the center of an \s-1MGRS\s0 grid square. For example, .Sp .Vb 2 \& 38SMB4484 \& 38SMB44140847064 .Ve .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-g\fR" 4 .IX Item "-g" output latitude and longitude using decimal degrees. Default output mode. .IP "\fB\-d\fR" 4 .IX Item "-d" output latitude and longitude using degrees, minutes, and seconds (\s-1DMS\s0). .IP "\fB\-:\fR" 4 .IX Item "-:" like \fB\-d\fR, except use : as a separator instead of the d, ', and " delimiters. .IP "\fB\-u\fR" 4 .IX Item "-u" output \s-1UTM\s0 or \s-1UPS.\s0 .IP "\fB\-m\fR" 4 .IX Item "-m" output \s-1MGRS.\s0 .IP "\fB\-c\fR" 4 .IX Item "-c" output meridian convergence and scale for the corresponding \s-1UTM\s0 or \s-1UPS\s0 projection. The meridian convergence is the bearing of grid north given as degrees clockwise from true north. .IP "\fB\-z\fR \fIzone\fR" 4 .IX Item "-z zone" set the zone to \fIzone\fR for output. Use either 0 < \fIzone\fR <= 60 for a \s-1UTM\s0 zone or \fIzone\fR = 0 for \s-1UPS.\s0 Alternatively use a \&\fIzone\fR+\fIhemisphere\fR designation, e.g., 38n. See \*(L"\s-1ZONE\*(R"\s0. .IP "\fB\-s\fR" 4 .IX Item "-s" use the standard \s-1UPS\s0 and \s-1UTM\s0 zones. .IP "\fB\-t\fR" 4 .IX Item "-t" similar to \fB\-s\fR but forces \s-1UPS\s0 regions to the closest \s-1UTM\s0 zone. .IP "\fB\-S\fR or \fB\-T\fR" 4 .IX Item "-S or -T" behave the same as \fB\-s\fR and \fB\-t\fR, respectively, until the first legal conversion is performed. For subsequent points, the zone and hemisphere of that conversion are used. This enables a sequence of points to be converted into \s-1UTM\s0 or \s-1UPS\s0 using a consistent coordinate system. .IP "\fB\-n\fR" 4 .IX Item "-n" on input, \s-1MGRS\s0 coordinates refer to the south-west corner of the \s-1MGRS\s0 square instead of the center; see \*(L"\s-1MGRS\*(R"\s0. .IP "\fB\-w\fR" 4 .IX Item "-w" toggle the longitude first flag (it starts off); if the flag is on, then on input and output, longitude precedes latitude (except that, on input, this can be overridden by a hemisphere designator, \fIN\fR, \fIS\fR, \fIE\fR, \&\fIW\fR). .IP "\fB\-p\fR \fIprec\fR" 4 .IX Item "-p prec" set the output precision to \fIprec\fR (default 0); \fIprec\fR is the precision relative to 1 m. See \*(L"\s-1PRECISION\*(R"\s0. .IP "\fB\-l\fR" 4 .IX Item "-l" on output, \s-1UTM/UPS\s0 uses the long forms \fInorth\fR and \fIsouth\fR to designate the hemisphere instead of \fIn\fR or \fIs\fR. .IP "\fB\-a\fR" 4 .IX Item "-a" on output, \s-1UTM/UPS\s0 uses the abbreviations \fIn\fR and \fIs\fR to designate the hemisphere instead of \fInorth\fR or \fIsouth\fR; this is the default representation. .IP "\fB\-\-comment\-delimiter\fR \fIcommentdelim\fR" 4 .IX Item "--comment-delimiter commentdelim" set the comment delimiter to \fIcommentdelim\fR (e.g., \*(L"#\*(R" or \*(L"//\*(R"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). .IP "\fB\-\-version\fR" 4 .IX Item "--version" print version and exit. .IP "\fB\-h\fR" 4 .IX Item "-h" print usage and exit. .IP "\fB\-\-help\fR" 4 .IX Item "--help" print full documentation and exit. .IP "\fB\-\-input\-file\fR \fIinfile\fR" 4 .IX Item "--input-file infile" read input from the file \fIinfile\fR instead of from standard input; a file name of \*(L"\-\*(R" stands for standard input. .IP "\fB\-\-input\-string\fR \fIinstring\fR" 4 .IX Item "--input-string instring" read input from the string \fIinstring\fR instead of from standard input. All occurrences of the line separator character (default is a semicolon) in \fIinstring\fR are converted to newlines before the reading begins. .IP "\fB\-\-line\-separator\fR \fIlinesep\fR" 4 .IX Item "--line-separator linesep" set the line separator character to \fIlinesep\fR. By default this is a semicolon. .IP "\fB\-\-output\-file\fR \fIoutfile\fR" 4 .IX Item "--output-file outfile" write output to the file \fIoutfile\fR instead of to standard output; a file name of \*(L"\-\*(R" stands for standard output. .SH "PRECISION" .IX Header "PRECISION" \&\fIprec\fR gives precision of the output with \fIprec\fR = 0 giving 1 m precision, \fIprec\fR = 3 giving 1 mm precision, etc. \fIprec\fR is the number of digits after the decimal point for \s-1UTM/UPS.\s0 For \s-1MGRS,\s0 The number of digits per coordinate is 5 + \fIprec\fR; = \-6 results in just the grid zone. For decimal degrees, the number of digits after the decimal point is 5 + \fIprec\fR. For \s-1DMS\s0 (degree, minute, seconds) output, the number of digits after the decimal point in the seconds components is 1 + \fIprec\fR; if this is negative then use minutes (\fIprec\fR = \-2 or \&\-3) or degrees (\fIprec\fR <= \-4) as the least significant component. Print convergence, resp. scale, with 5 + \fIprec\fR, resp. 7 + \fIprec\fR, digits after the decimal point. The minimum value of \fIprec\fR is \-5 (\-6 for \s-1MGRS\s0) and the maximum is 9 for \s-1UTM/UPS, 9\s0 for decimal degrees, 10 for \s-1DMS, 6\s0 for \s-1MGRS,\s0 and 8 for convergence and scale. .SH "GEOGRAPHIC COORDINATES" .IX Header "GEOGRAPHIC COORDINATES" The utility accepts geographic coordinates, latitude and longitude, in a number of common formats. Latitude precedes longitude, unless the \fB\-w\fR option is given which switches this convention. On input, either coordinate may be given first by appending or prepending \fIN\fR or \fIS\fR to the latitude and \fIE\fR or \fIW\fR to the longitude. These hemisphere designators carry an implied sign, positive for \fIN\fR and \fIE\fR and negative for \fIS\fR and \fIW\fR. This sign multiplies any +/\- sign prefixing the coordinate. The coordinates may be given as decimal degree or as degrees, minutes, and seconds. d, ', and " are used to denote degrees, minutes, and seconds, with the least significant designator optional. (See \*(L"\s-1QUOTING\*(R"\s0 for how to quote the characters ' and " when entering coordinates on the command line.) Alternatively, : (colon) may be used to separate the various components. Only the final component of coordinate can include a decimal point, and the minutes and seconds components must be less than 60. .PP It is also possible to carry out addition or subtraction operations in geographic coordinates. If the coordinate includes interior signs (i.e., not at the beginning or immediately after an initial hemisphere designator), then the coordinate is split before such signs; the pieces are parsed separately and the results summed. For example the point 15" east of 39N 70W is .PP .Vb 1 \& 39N 70W+0:0:15E .Ve .PP \&\fB\s-1WARNING:\s0\fR \*(L"Exponential\*(R" notation is not recognized for geographic coordinates. Thus 7.0E1 is illegal, while 7.0E+1 is parsed as (7.0E) + (+1), yielding the same result as 8.0E. .PP Various unicode characters (encoded with \s-1UTF\-8\s0) may also be used to denote degrees, minutes, and seconds, e.g., the degree, prime, and double prime symbols; in addition two single quotes can be used to represent ". .PP The other GeographicLib utilities use the same rules for interpreting geographic coordinates; in addition, azimuths and arc lengths are interpreted the same way. .SH "QUOTING" .IX Header "QUOTING" Unfortunately the characters ' and \*(L" have special meanings in many shells and have to be entered with care. However note (1) that the trailing designator is optional and that (2) you can use colons as a separator character. Thus 10d20' can be entered as 10d20 or 10:20 and 10d20'30\*(R" can be entered as 10:20:30. .IP "Unix shells (sh, bash, tsch)" 4 .IX Item "Unix shells (sh, bash, tsch)" The characters ' and \*(L" can be quoted by preceding them with a \e (backslash); or you can quote a string containing ' with a pair of \*(R"s. The two alternatives are illustrated by .Sp .Vb 2 \& echo 10d20\e\*(Aq30\e" "20d30\*(Aq40" | GeoConvert \-d \-p \-1 \& => 10d20\*(Aq30"N 020d30\*(Aq40"E .Ve .Sp Quoting of command line arguments is similar .Sp .Vb 2 \& GeoConvert \-d \-p \-1 \-\-input\-string "10d20\*(Aq30\e" 20d30\*(Aq40" \& => 10d20\*(Aq30"N 020d30\*(Aq40"E .Ve .IP "Windows command shell (cmd)" 4 .IX Item "Windows command shell (cmd)" The ' character needs no quoting; the " character can either be quoted by a ^ or can be represented by typing ' twice. (This quoting is usually unnecessary because the trailing designator can be omitted.) Thus .Sp .Vb 2 \& echo 10d20\*(Aq30\*(Aq\*(Aq 20d30\*(Aq40 | GeoConvert \-d \-p \-1 \& => 10d20\*(Aq30"N 020d30\*(Aq40"E .Ve .Sp Use \e to quote the " character in a command line argument .Sp .Vb 2 \& GeoConvert \-d \-p \-1 \-\-input\-string "10d20\*(Aq30\e" 20d30\*(Aq40" \& => 10d20\*(Aq30"N 020d30\*(Aq40"E .Ve .IP "Input from a file" 4 .IX Item "Input from a file" No quoting need be done if the input from a file. Thus each line of the file \f(CW\*(C`input.txt\*(C'\fR should just contain the plain coordinates. .Sp .Vb 1 \& GeoConvert \-d \-p \-1 < input.txt .Ve .SH "MGRS" .IX Header "MGRS" \&\s-1MGRS\s0 coordinates represent a square patch of the earth, thus \f(CW\*(C`38SMB4488\*(C'\fR is in zone \f(CW\*(C`38n\*(C'\fR with 444km <= \fIeasting\fR < 445km and 3688km <= \&\fInorthing\fR < 3689km. Consistent with this representation, coordinates are \fItruncated\fR (instead of \fIrounded\fR) to the requested precision. Similarly, on input an \s-1MGRS\s0 coordinate represents the \&\fIcenter\fR of the square (\f(CW\*(C`38n 444500 3688500\*(C'\fR in the example above). However, if the \fB\-n\fR option is given then the south-west corner of the square is returned instead (\f(CW\*(C`38n 444000 3688000\*(C'\fR in the example above). .SH "ZONE" .IX Header "ZONE" If the input is \fBgeographic\fR, \fBGeoConvert\fR uses the standard rules of selecting \s-1UTM\s0 vs \s-1UPS\s0 and for assigning the \s-1UTM\s0 zone (with the Norway and Svalbard exceptions). If the input is \fB\s-1UTM/UPS\s0\fR or \fB\s-1MGRS\s0\fR, then the choice between \s-1UTM\s0 and \s-1UPS\s0 and the \s-1UTM\s0 zone mirrors the input. The \fB\-z\fR \&\fIzone\fR, \fB\-s\fR, and \fB\-t\fR options allow these rules to be overridden with \fIzone\fR = 0 being used to indicate \s-1UPS.\s0 For example, the point .PP .Vb 1 \& 79.9S 6.1E .Ve .PP corresponds to possible \s-1MGRS\s0 coordinates .PP .Vb 3 \& 32CMS4324728161 (standard UTM zone = 32) \& 31CEM6066227959 (neighboring UTM zone = 31) \& BBZ1945517770 (neighboring UPS zone) .Ve .PP then .PP .Vb 4 \& echo 79.9S 6.1E | GeoConvert \-p \-3 \-m => 32CMS4328 \& echo 31CEM6066227959 | GeoConvert \-p \-3 \-m => 31CEM6027 \& echo 31CEM6066227959 | GeoConvert \-p \-3 \-m \-s => 32CMS4328 \& echo 31CEM6066227959 | GeoConvert \-p \-3 \-m \-z 0 => BBZ1917 .Ve .PP Is \fIzone\fR is specified with a hemisphere, then this is honored when printing \s-1UTM\s0 coordinates: .PP .Vb 4 \& echo \-1 3 | GeoConvert \-u => 31s 500000 9889470 \& echo \-1 3 | GeoConvert \-u \-z 31 => 31s 500000 9889470 \& echo \-1 3 | GeoConvert \-u \-z 31s => 31s 500000 9889470 \& echo \-1 3 | GeoConvert \-u \-z 31n => 31n 500000 \-110530 .Ve .PP \&\fB\s-1NOTE\s0\fR: the letter in the zone specification for \s-1UTM\s0 is a hemisphere designator \fIn\fR or \fIs\fR and \fInot\fR an \s-1MGRS\s0 latitude band letter. Convert the \s-1MGRS\s0 latitude band letter to a hemisphere as follows: replace \fIC\fR thru \fIM\fR by \fIs\fR (or \fIsouth\fR); replace \fIN\fR thru \fIX\fR by \&\fIn\fR (or \fInorth\fR). .SH "EXAMPLES" .IX Header "EXAMPLES" .Vb 4 \& echo 38SMB4488 | GeoConvert => 33.33424 44.40363 \& echo 38SMB4488 | GeoConvert \-: \-p 1 => 33:20:03.25N 044:2413.06E \& echo 38SMB4488 | GeoConvert \-u => 38n 444500 3688500 \& echo E44d24 N33d20 | GeoConvert \-m \-p \-3 => 38SMB4488 .Ve .PP GeoConvert can be used to do simple arithmetic using degree, minutes, and seconds. For example, sometimes data is tiled in 15 second squares tagged by the \s-1DMS\s0 representation of the \s-1SW\s0 corner. The tags of the tile at 38:59:45N 077:02:00W and its 8 neighbors are then given by .PP .Vb 10 \& t=0:0:15 \& for y in \-$t +0 +$t; do \& for x in \-$t +0 +$t; do \& echo 38:59:45N$y 077:02:00W$x \& done \& done | GeoConvert \-: \-p \-1 | tr \-d \*(Aq: \*(Aq \& => \& 385930N0770215W \& 385930N0770200W \& 385930N0770145W \& 385945N0770215W \& 385945N0770200W \& 385945N0770145W \& 390000N0770215W \& 390000N0770200W \& 390000N0770145W .Ve .SH "ERRORS" .IX Header "ERRORS" An illegal line of input will print an error message to standard output beginning with \f(CW\*(C`ERROR:\*(C'\fR and causes \fBGeoConvert\fR to return an exit code of 1. However, an error does not cause \fBGeoConvert\fR to terminate; following lines will be converted. .SH "ABBREVIATIONS" .IX Header "ABBREVIATIONS" .IP "\fB\s-1UTM\s0\fR" 4 .IX Item "UTM" Universal Transverse Mercator, . .IP "\fB\s-1UPS\s0\fR" 4 .IX Item "UPS" Universal Polar Stereographic, . .IP "\fB\s-1MGRS\s0\fR" 4 .IX Item "MGRS" Military Grid Reference System, . .IP "\fB\s-1WGS84\s0\fR" 4 .IX Item "WGS84" World Geodetic System 1984, . .SH "SEE ALSO" .IX Header "SEE ALSO" An online version of this utility is availbable at . .PP The algorithms for the transverse Mercator projection are described in C. F. F. Karney, \fITransverse Mercator with an accuracy of a few nanometers\fR, J. Geodesy \fB85\fR(8), 475\-485 (Aug. 2011); \s-1DOI\s0 ; preprint . .SH "AUTHOR" .IX Header "AUTHOR" \&\fBGeoConvert\fR was written by Charles Karney. .SH "HISTORY" .IX Header "HISTORY" \&\fBGeoConvert\fR was added to GeographicLib, , in 2009\-01. GeographicLib-1.49/man/script.8.in0000644000771000077100000000066713165402514016613 0ustar ckarneyckarney.TH @SCRIPT@ 8 "" GeographicLib GeographicLib .SH NAME @SCRIPT@ \-\- a GeographicLib administrative tool .SH DESCRIPTION .B @SCRIPT@ downloads and installs the @DATA@ datasets used by GeographicLib, . For documentation, supply the .B \-h option: .PP @SCRIPT@ \-h .PP By default, the datasets are installed in .I @GEOGRAPHICLIB_DATA@/@DATA@ and the script requires write access to this directory. GeographicLib-1.49/man/ConicProj.usage0000644000771000077100000001574313165402556017534 0ustar ckarneyckarneyint usage(int retval, bool brief) { if (brief) ( retval ? std::cerr : std::cout ) << "Usage:\n" " ConicProj ( -c | -a ) lat1 lat2 [ -l lon0 ] [ -k k1 ] [ -r ] [ -e a f ]\n" " [ -w ] [ -p prec ] [ --comment-delimiter commentdelim ] [ --version |\n" " -h | --help ] [ --input-file infile | --input-string instring ] [\n" " --line-separator linesep ] [ --output-file outfile ]\n" "\n" "For full documentation type:\n" " ConicProj --help\n" "or visit:\n" " https://geographiclib.sourceforge.io/1.49/ConicProj.1.html\n"; else ( retval ? std::cerr : std::cout ) << "Man page:\n" "NAME\n" " ConicProj -- perform conic projections\n" "\n" "SYNOPSIS\n" " ConicProj ( -c | -a ) lat1 lat2 [ -l lon0 ] [ -k k1 ] [ -r ] [ -e a f ]\n" " [ -w ] [ -p prec ] [ --comment-delimiter commentdelim ] [ --version |\n" " -h | --help ] [ --input-file infile | --input-string instring ] [\n" " --line-separator linesep ] [ --output-file outfile ]\n" "\n" "DESCRIPTION\n" " Perform one of two conic projections geodesics. Convert geodetic\n" " coordinates to either Lambert conformal conic or Albers equal area\n" " coordinates. The standard latitudes lat1 and lat2 are specified by\n" " that the -c option (for Lambert conformal conic) or the -a option (for\n" " Albers equal area). At least one of these options must be given (the\n" " last one given is used). Specify lat1 = lat2, to obtain the case with\n" " a single standard parallel. The central meridian is given by lon0.\n" " The longitude of origin is given by the latitude of minimum (azimuthal)\n" " scale for Lambert conformal conic (Albers equal area). The (azimuthal)\n" " scale on the standard parallels is k1.\n" "\n" " Geodetic coordinates are provided on standard input as a set of lines\n" " containing (blank separated) latitude and longitude (decimal degrees or\n" " degrees, minutes, seconds); for details on the allowed formats for\n" " latitude and longitude, see the \"GEOGRAPHIC COORDINATES\" section of\n" " GeoConvert(1). For each set of geodetic coordinates, the corresponding\n" " projected easting, x, and northing, y, (meters) are printed on standard\n" " output together with the meridian convergence gamma (degrees) and\n" " (azimuthal) scale k. For Albers equal area, the radial scale is 1/k.\n" " The meridian convergence is the bearing of the y axis measured\n" " clockwise from true north.\n" "\n" " Special cases of the Lambert conformal projection are the Mercator\n" " projection (the standard latitudes equal and opposite) and the polar\n" " stereographic projection (both standard latitudes correspond to the\n" " same pole). Special cases of the Albers equal area projection are the\n" " cylindrical equal area projection (the standard latitudes equal and\n" " opposite), the Lambert azimuthal equal area projection (both standard\n" " latitude corresponds to the same pole), and the Lambert equal area\n" " conic projection (one standard parallel is at a pole).\n" "\n" "OPTIONS\n" " -c lat1 lat2\n" " use the Lambert conformal conic projection with standard parallels\n" " lat1 and lat2.\n" "\n" " -a lat1 lat2\n" " use the Albers equal area projection with standard parallels lat1\n" " and lat2.\n" "\n" " -l lon0\n" " specify the longitude of origin lon0 (degrees, default 0).\n" "\n" " -k k1\n" " specify the (azimuthal) scale k1 on the standard parallels (default\n" " 1).\n" "\n" " -r perform the reverse projection. x and y are given on standard\n" " input and each line of standard output gives latitude, longitude,\n" " gamma, and k.\n" "\n" " -e a f\n" " specify the ellipsoid via the equatorial radius, a and the\n" " flattening, f. Setting f = 0 results in a sphere. Specify f < 0\n" " for a prolate ellipsoid. A simple fraction, e.g., 1/297, is\n" " allowed for f. By default, the WGS84 ellipsoid is used, a =\n" " 6378137 m, f = 1/298.257223563.\n" "\n" " -w toggle the longitude first flag (it starts off); if the flag is on,\n" " then on input and output, longitude precedes latitude (except that,\n" " on input, this can be overridden by a hemisphere designator, N, S,\n" " E, W).\n" "\n" " -p prec\n" " set the output precision to prec (default 6). prec is the number\n" " of digits after the decimal point for lengths (in meters). For\n" " latitudes and longitudes (in degrees), the number of digits after\n" " the decimal point is prec + 5. For the convergence (in degrees)\n" " and scale, the number of digits after the decimal point is prec +\n" " 6.\n" "\n" " --comment-delimiter commentdelim\n" " set the comment delimiter to commentdelim (e.g., \"#\" or \"//\"). If\n" " set, the input lines will be scanned for this delimiter and, if\n" " found, the delimiter and the rest of the line will be removed prior\n" " to processing and subsequently appended to the output line\n" " (separated by a space).\n" "\n" " --version\n" " print version and exit.\n" "\n" " -h print usage and exit.\n" "\n" " --help\n" " print full documentation and exit.\n" "\n" " --input-file infile\n" " read input from the file infile instead of from standard input; a\n" " file name of \"-\" stands for standard input.\n" "\n" " --input-string instring\n" " read input from the string instring instead of from standard input.\n" " All occurrences of the line separator character (default is a\n" " semicolon) in instring are converted to newlines before the reading\n" " begins.\n" "\n" " --line-separator linesep\n" " set the line separator character to linesep. By default this is a\n" " semicolon.\n" "\n" " --output-file outfile\n" " write output to the file outfile instead of to standard output; a\n" " file name of \"-\" stands for standard output.\n" "\n" "EXAMPLES\n" " echo 39.95N 75.17W | ConicProj -c 40d58 39d56 -l 77d45W\n" " => 220445 -52372 1.67 1.0\n" " echo 220445 -52372 | ConicProj -c 40d58 39d56 -l 77d45W -r\n" " => 39.95 -75.17 1.67 1.0\n" "\n" "ERRORS\n" " An illegal line of input will print an error message to standard output\n" " beginning with \"ERROR:\" and causes ConicProj to return an exit code of\n" " 1. However, an error does not cause ConicProj to terminate; following\n" " lines will be converted.\n" "\n" "AUTHOR\n" " ConicProj was written by Charles Karney.\n" "\n" "HISTORY\n" " ConicProj was added to GeographicLib,\n" " , in version 1.9.\n" ; return retval; } GeographicLib-1.49/man/MagneticField.10000644000771000077100000003470213165402556017371 0ustar ckarneyckarney.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "MAGNETICFIELD 1" .TH MAGNETICFIELD 1 "2017-10-05" "GeographicLib 1.49" "GeographicLib Utilities" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" MagneticField \-\- compute the earth's magnetic field .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBMagneticField\fR [ \fB\-n\fR \fIname\fR ] [ \fB\-d\fR \fIdir\fR ] [ \fB\-t\fR \fItime\fR | \fB\-c\fR \fItime\fR \fIlat\fR \fIh\fR ] [ \fB\-r\fR ] [ \fB\-w\fR ] [ \fB\-T\fR \fItguard\fR ] [ \fB\-H\fR \fIhguard\fR ] [ \fB\-p\fR \fIprec\fR ] [ \fB\-v\fR ] [ \fB\-\-comment\-delimiter\fR \fIcommentdelim\fR ] [ \fB\-\-version\fR | \fB\-h\fR | \fB\-\-help\fR ] [ \fB\-\-input\-file\fR \fIinfile\fR | \fB\-\-input\-string\fR \fIinstring\fR ] [ \fB\-\-line\-separator\fR \fIlinesep\fR ] [ \fB\-\-output\-file\fR \fIoutfile\fR ] .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBMagneticField\fR reads in times and positions on standard input and prints out the geomagnetic field on standard output and, optionally, its rate of change. .PP The input line is of the form \fItime\fR \fIlat\fR \fIlon\fR \fIh\fR. \fItime\fR is a date of the form 2012\-07\-03, a fractional year such as 2012.5, or the string \*(L"now\*(R". \fIlat\fR and \fIlon\fR are the latitude and longitude expressed as decimal degrees or degrees, minutes, and seconds; for details on the allowed formats for latitude and longitude, see the \&\f(CW\*(C`GEOGRAPHIC COORDINATES\*(C'\fR section of \fIGeoConvert\fR\|(1). \fIh\fR is the height above the ellipsoid in meters; this is optional and defaults to zero. Alternatively, \fItime\fR can be given on the command line as the argument to the \fB\-t\fR option, in which case it should not be included on the input lines. Finally, the magnetic field can be computed at various points on a circle of latitude (constant \fItime\fR, \fIlat\fR, and \fIh\fR) via the \fB\-c\fR option; in this case only the longitude should be given on the input lines. .PP The output consists of the following 7 items: .PP .Vb 9 \& the declination (the direction of the horizontal component of \& the magnetic field measured clockwise from north) in degrees, \& the inclination (the direction of the magnetic field measured \& down from the horizontal) in degrees, \& the horizontal field in nanotesla (nT), \& the north component of the field in nT, \& the east component of the field in nT, \& the vertical component of the field in nT (down is positive), \& the total field in nT. .Ve .PP If the \fB\-r\fR option is given, a second line is printed giving the rates of change of these quantities in degrees/yr and nT/yr. .PP The \s-1WGS84\s0 ellipsoid is used, \fIa\fR = 6378137 m, \fIf\fR = 1/298.257223563. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-n\fR \fIname\fR" 4 .IX Item "-n name" use magnetic field model \fIname\fR instead of the default \f(CW\*(C`wmm2015\*(C'\fR. See \&\*(L"\s-1MODELS\*(R"\s0. .IP "\fB\-d\fR \fIdir\fR" 4 .IX Item "-d dir" read magnetic models from \fIdir\fR instead of the default. See \&\*(L"\s-1MODELS\*(R"\s0. .IP "\fB\-t\fR \fItime\fR" 4 .IX Item "-t time" evaluate the field at \fItime\fR instead of reading the time from the input lines. .IP "\fB\-c\fR \fItime\fR \fIlat\fR \fIh\fR" 4 .IX Item "-c time lat h" evaluate the field on a circle of latitude given by \fItime\fR, \fIlat\fR, \&\fIh\fR instead of reading these quantities from the input lines. In this case, \fBMagneticField\fR can calculate the field considerably more quickly. .IP "\fB\-r\fR" 4 .IX Item "-r" toggle whether to report the rates of change of the field. .IP "\fB\-w\fR" 4 .IX Item "-w" toggle the longitude first flag (it starts off); if the flag is on, then on input and output, longitude precedes latitude (except that, on input, this can be overridden by a hemisphere designator, \fIN\fR, \fIS\fR, \fIE\fR, \&\fIW\fR). .IP "\fB\-T\fR \fItguard\fR" 4 .IX Item "-T tguard" signal an error if \fItime\fR lies \fItguard\fR years (default 50 yr) beyond the range for the model. .IP "\fB\-H\fR \fIhguard\fR" 4 .IX Item "-H hguard" signal an error if \fIh\fR lies \fIhguard\fR meters (default 500000 m) beyond the range for the model. .IP "\fB\-p\fR \fIprec\fR" 4 .IX Item "-p prec" set the output precision to \fIprec\fR (default 1). Fields are printed with precision with \fIprec\fR decimal places; angles use \fIprec\fR + 1 places. .IP "\fB\-v\fR" 4 .IX Item "-v" print information about the magnetic model on standard error before processing the input. .IP "\fB\-\-comment\-delimiter\fR \fIcommentdelim\fR" 4 .IX Item "--comment-delimiter commentdelim" set the comment delimiter to \fIcommentdelim\fR (e.g., \*(L"#\*(R" or \*(L"//\*(R"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). .IP "\fB\-\-version\fR" 4 .IX Item "--version" print version and exit. .IP "\fB\-h\fR" 4 .IX Item "-h" print usage, the default magnetic path and name, and exit. .IP "\fB\-\-help\fR" 4 .IX Item "--help" print full documentation and exit. .IP "\fB\-\-input\-file\fR \fIinfile\fR" 4 .IX Item "--input-file infile" read input from the file \fIinfile\fR instead of from standard input; a file name of \*(L"\-\*(R" stands for standard input. .IP "\fB\-\-input\-string\fR \fIinstring\fR" 4 .IX Item "--input-string instring" read input from the string \fIinstring\fR instead of from standard input. All occurrences of the line separator character (default is a semicolon) in \fIinstring\fR are converted to newlines before the reading begins. .IP "\fB\-\-line\-separator\fR \fIlinesep\fR" 4 .IX Item "--line-separator linesep" set the line separator character to \fIlinesep\fR. By default this is a semicolon. .IP "\fB\-\-output\-file\fR \fIoutfile\fR" 4 .IX Item "--output-file outfile" write output to the file \fIoutfile\fR instead of to standard output; a file name of \*(L"\-\*(R" stands for standard output. .SH "MODELS" .IX Header "MODELS" \&\fBMagneticField\fR computes the geomagnetic field using one of the following models .PP .Vb 10 \& wmm2010, the World Magnetic Model 2010, which approximates the \& main magnetic field for the period 2010\-2015. See \& https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml \& wmm2015, the World Magnetic Model 2015, which approximates the \& main magnetic field for the period 2015\-2020. See \& https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml \& igrf11, the International Geomagnetic Reference Field (11th \& generation), which approximates the main magnetic field for \& the period 1900\-2015. See \& https://ngdc.noaa.gov/IAGA/vmod/igrf.html \& igrf12, the International Geomagnetic Reference Field (12th \& generation), which approximates the main magnetic field for \& the period 1900\-2020. See \& https://ngdc.noaa.gov/IAGA/vmod/igrf.html \& emm2010, the Enhanced Magnetic Model 2010, which approximates \& the main and crustal magnetic fields for the period 2010\-2015. \& See https://ngdc.noaa.gov/geomag/EMM/index.html \& emm2015, the Enhanced Magnetic Model 2015, which approximates \& the main and crustal magnetic fields for the period 2000\-2020. \& See https://ngdc.noaa.gov/geomag/EMM/index.html \& emm2017, the Enhanced Magnetic Model 2017, which approximates \& the main and crustal magnetic fields for the period 2000\-2022. \& See https://ngdc.noaa.gov/geomag/EMM/index.html .Ve .PP These models approximate the magnetic field due to the earth's core and (in the case of emm20xx) its crust. They neglect magnetic fields due to the ionosphere, the magnetosphere, nearby magnetized materials, electrical machinery, etc. .PP By default, the \f(CW\*(C`wmm2015\*(C'\fR magnetic model is used. This may changed by setting the environment variable \f(CW\*(C`GEOGRAPHICLIB_MAGNETIC_NAME\*(C'\fR or with the \fB\-n\fR option. .PP The magnetic models will be loaded from a directory specified at compile time. This may changed by setting the environment variables \&\f(CW\*(C`GEOGRAPHICLIB_MAGNETIC_PATH\*(C'\fR or \f(CW\*(C`GEOGRAPHICLIB_DATA\*(C'\fR, or with the \&\fB\-d\fR option. The \fB\-h\fR option prints the default magnetic path and name. Use the \fB\-v\fR option to ascertain the full path name of the data file. .PP Instructions for downloading and installing magnetic models are available at . .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" .IP "\fB\s-1GEOGRAPHICLIB_MAGNETIC_NAME\s0\fR" 4 .IX Item "GEOGRAPHICLIB_MAGNETIC_NAME" Override the compile-time default magnetic name of \f(CW\*(C`wmm2015\*(C'\fR. The \&\fB\-h\fR option reports the value of \fB\s-1GEOGRAPHICLIB_MAGNETIC_NAME\s0\fR, if defined, otherwise it reports the compile-time value. If the \fB\-n\fR \&\fIname\fR option is used, then \fIname\fR takes precedence. .IP "\fB\s-1GEOGRAPHICLIB_MAGNETIC_PATH\s0\fR" 4 .IX Item "GEOGRAPHICLIB_MAGNETIC_PATH" Override the compile-time default magnetic path. This is typically \&\f(CW\*(C`/usr/local/share/GeographicLib/magnetic\*(C'\fR on Unix-like systems and \&\f(CW\*(C`C:/ProgramData/GeographicLib/magnetic\*(C'\fR on Windows systems. The \fB\-h\fR option reports the value of \fB\s-1GEOGRAPHICLIB_MAGNETIC_PATH\s0\fR, if defined, otherwise it reports the compile-time value. If the \fB\-d\fR \fIdir\fR option is used, then \fIdir\fR takes precedence. .IP "\fB\s-1GEOGRAPHICLIB_DATA\s0\fR" 4 .IX Item "GEOGRAPHICLIB_DATA" Another way of overriding the compile-time default magnetic path. If it is set (and if \fB\s-1GEOGRAPHICLIB_MAGNETIC_PATH\s0\fR is not set), then $\fB\s-1GEOGRAPHICLIB_DATA\s0\fR/magnetic is used. .SH "ERRORS" .IX Header "ERRORS" An illegal line of input will print an error message to standard output beginning with \f(CW\*(C`ERROR:\*(C'\fR and causes \fBMagneticField\fR to return an exit code of 1. However, an error does not cause \fBMagneticField\fR to terminate; following lines will be converted. If \fItime\fR or \fIh\fR are outside the recommended ranges for the model (but inside the ranges increase by \fItguard\fR and \fIhguard\fR), a warning is printed on standard error and the field (which may be inaccurate) is returned in the normal way. .SH "EXAMPLES" .IX Header "EXAMPLES" The magnetic field from \s-1WMM2015\s0 in Timbuktu on 2016\-01\-01 .PP .Vb 3 \& echo 2016\-01\-01 16:46:33N 3:00:34W 300 | MagneticField \-r \& => \-2.12 12.15 33871.9 33848.7 \-1251.4 7293.9 34648.3 \& 0.09 \-0.08 31.8 33.8 53.7 \-41.4 22.3 .Ve .PP The first two numbers returned are the declination and inclination of the field. The second line gives the annual change. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIGeoConvert\fR\|(1), \fIgeographiclib\-get\-magnetic\fR\|(8). .SH "AUTHOR" .IX Header "AUTHOR" \&\fBMagneticField\fR was written by Charles Karney. .SH "HISTORY" .IX Header "HISTORY" \&\fBMagneticField\fR was added to GeographicLib, , in version 1.15. GeographicLib-1.49/man/GeodSolve.usage0000644000771000077100000004021713165402556017527 0ustar ckarneyckarneyint usage(int retval, bool brief) { if (brief) ( retval ? std::cerr : std::cout ) << "Usage:\n" " GeodSolve [ -i | -L lat1 lon1 azi1 | -D lat1 lon1 azi1 s13 | -I lat1\n" " lon1 lat3 lon3 ] [ -a ] [ -e a f ] [ -u ] [ -F ] [ -d | -: ] [ -w ] [\n" " -b ] [ -f ] [ -p prec ] [ -E ] [ --comment-delimiter commentdelim ] [\n" " --version | -h | --help ] [ --input-file infile | --input-string\n" " instring ] [ --line-separator linesep ] [ --output-file outfile ]\n" "\n" "For full documentation type:\n" " GeodSolve --help\n" "or visit:\n" " https://geographiclib.sourceforge.io/1.49/GeodSolve.1.html\n"; else ( retval ? std::cerr : std::cout ) << "Man page:\n" "NAME\n" " GeodSolve -- perform geodesic calculations\n" "\n" "SYNOPSIS\n" " GeodSolve [ -i | -L lat1 lon1 azi1 | -D lat1 lon1 azi1 s13 | -I lat1\n" " lon1 lat3 lon3 ] [ -a ] [ -e a f ] [ -u ] [ -F ] [ -d | -: ] [ -w ] [\n" " -b ] [ -f ] [ -p prec ] [ -E ] [ --comment-delimiter commentdelim ] [\n" " --version | -h | --help ] [ --input-file infile | --input-string\n" " instring ] [ --line-separator linesep ] [ --output-file outfile ]\n" "\n" "DESCRIPTION\n" " The shortest path between two points on the ellipsoid at (lat1, lon1)\n" " and (lat2, lon2) is called the geodesic. Its length is s12 and the\n" " geodesic from point 1 to point 2 has forward azimuths azi1 and azi2 at\n" " the two end points.\n" "\n" " GeodSolve operates in one of three modes:\n" "\n" " 1. By default, GeodSolve accepts lines on the standard input\n" " containing lat1 lon1 azi1 s12 and prints lat2 lon2 azi2 on standard\n" " output. This is the direct geodesic calculation.\n" "\n" " 2. With the -i command line argument, GeodSolve performs the inverse\n" " geodesic calculation. It reads lines containing lat1 lon1 lat2\n" " lon2 and prints the corresponding values of azi1 azi2 s12.\n" "\n" " 3. Command line arguments -L lat1 lon1 azi1 specify a geodesic line.\n" " GeodSolve then accepts a sequence of s12 values (one per line) on\n" " standard input and prints lat2 lon2 azi2 for each. This generates\n" " a sequence of points on a single geodesic. Command line arguments\n" " -D and -I work similarly with the geodesic line defined in terms of\n" " a direct or inverse geodesic calculation, respectively.\n" "\n" "OPTIONS\n" " -i perform an inverse geodesic calculation (see 2 above).\n" "\n" " -L lat1 lon1 azi1\n" " line mode (see 3 above); generate a sequence of points along the\n" " geodesic specified by lat1 lon1 azi1. The -w flag can be used to\n" " swap the default order of the 2 geographic coordinates, provided\n" " that it appears before -L. (-l is an alternative, deprecated,\n" " spelling of this flag.)\n" "\n" " -D lat1 lon1 azi1 s13\n" " line mode (see 3 above); generate a sequence of points along the\n" " geodesic specified by lat1 lon1 azi1 s13. The -w flag can be used\n" " to swap the default order of the 2 geographic coordinates, provided\n" " that it appears before -D. Similarly, the -a flag can be used to\n" " change the interpretation of s13 to a13, provided that it appears\n" " before -D.\n" "\n" " -I lat1 lon1 lat3 lon3\n" " line mode (see 3 above); generate a sequence of points along the\n" " geodesic specified by lat1 lon1 lat3 lon3. The -w flag can be used\n" " to swap the default order of the 2 geographic coordinates, provided\n" " that it appears before -I.\n" "\n" " -a toggle the arc mode flag (it starts off); if this flag is on, then\n" " on input and output s12 is replaced by a12 the arc length (in\n" " degrees) on the auxiliary sphere. See \"AUXILIARY SPHERE\".\n" "\n" " -e a f\n" " specify the ellipsoid via the equatorial radius, a and the\n" " flattening, f. Setting f = 0 results in a sphere. Specify f < 0\n" " for a prolate ellipsoid. A simple fraction, e.g., 1/297, is\n" " allowed for f. By default, the WGS84 ellipsoid is used, a =\n" " 6378137 m, f = 1/298.257223563.\n" "\n" " -u unroll the longitude. Normally, on output longitudes are reduced\n" " to lie in [-180deg,180deg). However with this option, the returned\n" " longitude lon2 is \"unrolled\" so that lon2 - lon1 indicates how\n" " often and in what sense the geodesic has encircled the earth. Use\n" " the -f option, to get both longitudes printed.\n" "\n" " -F fractional mode. This only has any effect with the -D and -I\n" " options (and is otherwise ignored). The values read on standard\n" " input are interpreted as fractional distances to point 3, i.e., as\n" " s12/s13 instead of s12. If arc mode is in effect, then the values\n" " denote fractional arc length, i.e., a12/a13.\n" "\n" " -d output angles as degrees, minutes, seconds instead of decimal\n" " degrees.\n" "\n" " -: like -d, except use : as a separator instead of the d, ', and \"\n" " delimiters.\n" "\n" " -w toggle the longitude first flag (it starts off); if the flag is on,\n" " then on input and output, longitude precedes latitude (except that,\n" " on input, this can be overridden by a hemisphere designator, N, S,\n" " E, W).\n" "\n" " -b report the back azimuth at point 2 instead of the forward azimuth.\n" "\n" " -f full output; each line of output consists of 12 quantities: lat1\n" " lon1 azi1 lat2 lon2 azi2 s12 a12 m12 M12 M21 S12. a12 is described\n" " in \"AUXILIARY SPHERE\". The four quantities m12, M12, M21, and S12\n" " are described in \"ADDITIONAL QUANTITIES\".\n" "\n" " -p prec\n" " set the output precision to prec (default 3); prec is the precision\n" " relative to 1 m. See \"PRECISION\".\n" "\n" " -E use \"exact\" algorithms (based on elliptic integrals) for the\n" " geodesic calculations. These are more accurate than the (default)\n" " series expansions for |f| > 0.02.\n" "\n" " --comment-delimiter commentdelim\n" " set the comment delimiter to commentdelim (e.g., \"#\" or \"//\"). If\n" " set, the input lines will be scanned for this delimiter and, if\n" " found, the delimiter and the rest of the line will be removed prior\n" " to processing and subsequently appended to the output line\n" " (separated by a space).\n" "\n" " --version\n" " print version and exit.\n" "\n" " -h print usage and exit.\n" "\n" " --help\n" " print full documentation and exit.\n" "\n" " --input-file infile\n" " read input from the file infile instead of from standard input; a\n" " file name of \"-\" stands for standard input.\n" "\n" " --input-string instring\n" " read input from the string instring instead of from standard input.\n" " All occurrences of the line separator character (default is a\n" " semicolon) in instring are converted to newlines before the reading\n" " begins.\n" "\n" " --line-separator linesep\n" " set the line separator character to linesep. By default this is a\n" " semicolon.\n" "\n" " --output-file outfile\n" " write output to the file outfile instead of to standard output; a\n" " file name of \"-\" stands for standard output.\n" "\n" "INPUT\n" " GeodSolve measures all angles in degrees and all lengths (s12) in\n" " meters, and all areas (S12) in meters^2. On input angles (latitude,\n" " longitude, azimuth, arc length) can be as decimal degrees or degrees,\n" " minutes, seconds. For example, \"40d30\", \"40d30'\", \"40:30\", \"40.5d\",\n" " and 40.5 are all equivalent. By default, latitude precedes longitude\n" " for each point (the -w flag switches this convention); however on input\n" " either may be given first by appending (or prepending) N or S to the\n" " latitude and E or W to the longitude. Azimuths are measured clockwise\n" " from north; however this may be overridden with E or W.\n" "\n" " For details on the allowed formats for angles, see the \"GEOGRAPHIC\n" " COORDINATES\" section of GeoConvert(1).\n" "\n" "AUXILIARY SPHERE\n" " Geodesics on the ellipsoid can be transferred to the auxiliary sphere\n" " on which the distance is measured in terms of the arc length a12\n" " (measured in degrees) instead of s12. In terms of a12, 180 degrees is\n" " the distance from one equator crossing to the next or from the minimum\n" " latitude to the maximum latitude. Geodesics with a12 > 180 degrees do\n" " not correspond to shortest paths. With the -a flag, s12 (on both input\n" " and output) is replaced by a12. The -a flag does not affect the full\n" " output given by the -f flag (which always includes both s12 and a12).\n" "\n" "ADDITIONAL QUANTITIES\n" " The -f flag reports four additional quantities.\n" "\n" " The reduced length of the geodesic, m12, is defined such that if the\n" " initial azimuth is perturbed by dazi1 (radians) then the second point\n" " is displaced by m12 dazi1 in the direction perpendicular to the\n" " geodesic. m12 is given in meters. On a curved surface the reduced\n" " length obeys a symmetry relation, m12 + m21 = 0. On a flat surface, we\n" " have m12 = s12.\n" "\n" " M12 and M21 are geodesic scales. If two geodesics are parallel at\n" " point 1 and separated by a small distance dt, then they are separated\n" " by a distance M12 dt at point 2. M21 is defined similarly (with the\n" " geodesics being parallel to one another at point 2). M12 and M21 are\n" " dimensionless quantities. On a flat surface, we have M12 = M21 = 1.\n" "\n" " If points 1, 2, and 3 lie on a single geodesic, then the following\n" " addition rules hold:\n" "\n" " s13 = s12 + s23,\n" " a13 = a12 + a23,\n" " S13 = S12 + S23,\n" " m13 = m12 M23 + m23 M21,\n" " M13 = M12 M23 - (1 - M12 M21) m23 / m12,\n" " M31 = M32 M21 - (1 - M23 M32) m12 / m23.\n" "\n" " Finally, S12 is the area between the geodesic from point 1 to point 2\n" " and the equator; i.e., it is the area, measured counter-clockwise, of\n" " the geodesic quadrilateral with corners (lat1,lon1), (0,lon1),\n" " (0,lon2), and (lat2,lon2). It is given in meters^2.\n" "\n" "PRECISION\n" " prec gives precision of the output with prec = 0 giving 1 m precision,\n" " prec = 3 giving 1 mm precision, etc. prec is the number of digits\n" " after the decimal point for lengths. For decimal degrees, the number\n" " of digits after the decimal point is prec + 5. For DMS (degree,\n" " minute, seconds) output, the number of digits after the decimal point\n" " in the seconds component is prec + 1. The minimum value of prec is 0\n" " and the maximum is 10.\n" "\n" "ERRORS\n" " An illegal line of input will print an error message to standard output\n" " beginning with \"ERROR:\" and causes GeodSolve to return an exit code of\n" " 1. However, an error does not cause GeodSolve to terminate; following\n" " lines will be converted.\n" "\n" "ACCURACY\n" " Using the (default) series solution, GeodSolve is accurate to about 15\n" " nm (15 nanometers) for the WGS84 ellipsoid. The approximate maximum\n" " error (expressed as a distance) for an ellipsoid with the same\n" " equatorial radius as the WGS84 ellipsoid and different values of the\n" " flattening is\n" "\n" " |f| error\n" " 0.01 25 nm\n" " 0.02 30 nm\n" " 0.05 10 um\n" " 0.1 1.5 mm\n" " 0.2 300 mm\n" "\n" " If -E is specified, GeodSolve is accurate to about 40 nm (40\n" " nanometers) for the WGS84 ellipsoid. The approximate maximum error\n" " (expressed as a distance) for an ellipsoid with a quarter meridian of\n" " 10000 km and different values of the a/b = 1 - f is\n" "\n" " 1-f error (nm)\n" " 1/128 387\n" " 1/64 345\n" " 1/32 269\n" " 1/16 210\n" " 1/8 115\n" " 1/4 69\n" " 1/2 36\n" " 1 15\n" " 2 25\n" " 4 96\n" " 8 318\n" " 16 985\n" " 32 2352\n" " 64 6008\n" " 128 19024\n" "\n" "MULTIPLE SOLUTIONS\n" " The shortest distance returned for the inverse problem is (obviously)\n" " uniquely defined. However, in a few special cases there are multiple\n" " azimuths which yield the same shortest distance. Here is a catalog of\n" " those cases:\n" "\n" " lat1 = -lat2 (with neither point at a pole)\n" " If azi1 = azi2, the geodesic is unique. Otherwise there are two\n" " geodesics and the second one is obtained by setting [azi1,azi2] =\n" " [azi2,azi1], [M12,M21] = [M21,M12], S12 = -S12. (This occurs when\n" " the longitude difference is near +/-180 for oblate ellipsoids.)\n" "\n" " lon2 = lon1 +/- 180 (with neither point at a pole)\n" " If azi1 = 0 or +/-180, the geodesic is unique. Otherwise there are\n" " two geodesics and the second one is obtained by setting [azi1,azi2]\n" " = [-azi1,-azi2], S12 = -S12. (This occurs when lat2 is near -lat1\n" " for prolate ellipsoids.)\n" "\n" " Points 1 and 2 at opposite poles\n" " There are infinitely many geodesics which can be generated by\n" " setting [azi1,azi2] = [azi1,azi2] + [d,-d], for arbitrary d. (For\n" " spheres, this prescription applies when points 1 and 2 are\n" " antipodal.)\n" "\n" " s12 = 0 (coincident points)\n" " There are infinitely many geodesics which can be generated by\n" " setting [azi1,azi2] = [azi1,azi2] + [d,d], for arbitrary d.\n" "\n" "EXAMPLES\n" " Route from JFK Airport to Singapore Changi Airport:\n" "\n" " echo 40:38:23N 073:46:44W 01:21:33N 103:59:22E |\n" " GeodSolve -i -: -p 0\n" "\n" " 003:18:29.9 177:29:09.2 15347628\n" "\n" " Equally spaced waypoints on the route:\n" "\n" " for ((i = 0; i <= 10; ++i)); do echo ${i}e-1; done |\n" " GeodSolve -I 40:38:23N 073:46:44W 01:21:33N 103:59:22E -F -: -p 0\n" "\n" " 40:38:23.0N 073:46:44.0W 003:18:29.9\n" " 54:24:51.3N 072:25:39.6W 004:18:44.1\n" " 68:07:37.7N 069:40:42.9W 006:44:25.4\n" " 81:38:00.4N 058:37:53.9W 017:28:52.7\n" " 83:43:26.0N 080:37:16.9E 156:26:00.4\n" " 70:20:29.2N 097:01:29.4E 172:31:56.4\n" " 56:38:36.0N 100:14:47.6E 175:26:10.5\n" " 42:52:37.1N 101:43:37.2E 176:34:28.6\n" " 29:03:57.0N 102:39:34.8E 177:07:35.2\n" " 15:13:18.6N 103:22:08.0E 177:23:44.7\n" " 01:21:33.0N 103:59:22.0E 177:29:09.2\n" "\n" "SEE ALSO\n" " GeoConvert(1).\n" "\n" " An online version of this utility is availbable at\n" " .\n" "\n" " The algorithms are described in C. F. F. Karney, Algorithms for\n" " geodesics, J. Geodesy 87, 43-55 (2013); DOI:\n" " ; addenda:\n" " .\n" "\n" " The Wikipedia page, Geodesics on an ellipsoid,\n" " .\n" "\n" "AUTHOR\n" " GeodSolve was written by Charles Karney.\n" "\n" "HISTORY\n" " GeodSolve was added to GeographicLib,\n" " , in 2009-03. Prior to version\n" " 1.30, it was called Geod. (The name was changed to avoid a conflict\n" " with the geod utility in proj.4.)\n" ; return retval; } GeographicLib-1.49/man/RhumbSolve.usage0000644000771000077100000002473613165402556017736 0ustar ckarneyckarneyint usage(int retval, bool brief) { if (brief) ( retval ? std::cerr : std::cout ) << "Usage:\n" " RhumbSolve [ -i | -L lat1 lon1 azi12 ] [ -e a f ] [ -d | -: ] [ -w ] [\n" " -p prec ] [ -s ] [ --comment-delimiter commentdelim ] [ --version | -h\n" " | --help ] [ --input-file infile | --input-string instring ] [\n" " --line-separator linesep ] [ --output-file outfile ]\n" "\n" "For full documentation type:\n" " RhumbSolve --help\n" "or visit:\n" " https://geographiclib.sourceforge.io/1.49/RhumbSolve.1.html\n"; else ( retval ? std::cerr : std::cout ) << "Man page:\n" "NAME\n" " RhumbSolve -- perform rhumb line calculations\n" "\n" "SYNOPSIS\n" " RhumbSolve [ -i | -L lat1 lon1 azi12 ] [ -e a f ] [ -d | -: ] [ -w ] [\n" " -p prec ] [ -s ] [ --comment-delimiter commentdelim ] [ --version | -h\n" " | --help ] [ --input-file infile | --input-string instring ] [\n" " --line-separator linesep ] [ --output-file outfile ]\n" "\n" "DESCRIPTION\n" " The path with constant heading between two points on the ellipsoid at\n" " (lat1, lon1) and (lat2, lon2) is called the rhumb line or loxodrome.\n" " Its length is s12 and the rhumb line has a forward azimuth azi12 along\n" " its length. Also computed is S12 is the area between the rhumb line\n" " from point 1 to point 2 and the equator; i.e., it is the area, measured\n" " counter-clockwise, of the geodesic quadrilateral with corners\n" " (lat1,lon1), (0,lon1), (0,lon2), and (lat2,lon2). A point at a pole is\n" " treated as a point a tiny distance away from the pole on the given line\n" " of longitude. The longitude becomes indeterminate when a rhumb line\n" " passes through a pole, and RhumbSolve reports NaNs for the longitude\n" " and the area in this case.\n" "\n" " NOTE: the rhumb line is not the shortest path between two points; that\n" " is the geodesic and it is calculated by GeodSolve(1).\n" "\n" " RhumbSolve operates in one of three modes:\n" "\n" " 1. By default, RhumbSolve accepts lines on the standard input\n" " containing lat1 lon1 azi12 s12 and prints lat2 lon2 S12 on standard\n" " output. This is the direct calculation.\n" "\n" " 2. With the -i command line argument, RhumbSolve performs the inverse\n" " calculation. It reads lines containing lat1 lon1 lat2 lon2 and\n" " prints the values of azi12 s12 S12 for the corresponding shortest\n" " rhumb lines. If the end points are on opposite meridians, there\n" " are two shortest rhumb lines and the east-going one is chosen.\n" "\n" " 3. Command line arguments -L lat1 lon1 azi12 specify a rhumb line.\n" " RhumbSolve then accepts a sequence of s12 values (one per line) on\n" " standard input and prints lat2 lon2 S12 for each. This generates a\n" " sequence of points on a rhumb line.\n" "\n" "OPTIONS\n" " -i perform an inverse calculation (see 2 above).\n" "\n" " -L lat1 lon1 azi12\n" " line mode (see 3 above); generate a sequence of points along the\n" " rhumb line specified by lat1 lon1 azi12. The -w flag can be used\n" " to swap the default order of the 2 geographic coordinates, provided\n" " that it appears before -L. (-l is an alternative, deprecated,\n" " spelling of this flag.)\n" "\n" " -e a f\n" " specify the ellipsoid via the equatorial radius, a and the\n" " flattening, f. Setting f = 0 results in a sphere. Specify f < 0\n" " for a prolate ellipsoid. A simple fraction, e.g., 1/297, is\n" " allowed for f. By default, the WGS84 ellipsoid is used, a =\n" " 6378137 m, f = 1/298.257223563.\n" "\n" " -d output angles as degrees, minutes, seconds instead of decimal\n" " degrees.\n" "\n" " -: like -d, except use : as a separator instead of the d, ', and \"\n" " delimiters.\n" "\n" " -w on input and output, longitude precedes latitude (except that on\n" " input this can be overridden by a hemisphere designator, N, S, E,\n" " W).\n" "\n" " -p prec\n" " set the output precision to prec (default 3); prec is the precision\n" " relative to 1 m. See \"PRECISION\".\n" "\n" " -s By default, the rhumb line calculations are carried out exactly in\n" " terms of elliptic integrals. This includes the use of the addition\n" " theorem for elliptic integrals to compute the divided difference of\n" " the isometric and rectifying latitudes. If -s is supplied this\n" " divided difference is computed using Krueger series for the\n" " transverse Mercator projection which is only accurate for |f| <\n" " 0.01. See \"ACCURACY\".\n" "\n" " --comment-delimiter commentdelim\n" " set the comment delimiter to commentdelim (e.g., \"#\" or \"//\"). If\n" " set, the input lines will be scanned for this delimiter and, if\n" " found, the delimiter and the rest of the line will be removed prior\n" " to processing and subsequently appended to the output line\n" " (separated by a space).\n" "\n" " --version\n" " print version and exit.\n" "\n" " -h print usage and exit.\n" "\n" " --help\n" " print full documentation and exit.\n" "\n" " --input-file infile\n" " read input from the file infile instead of from standard input; a\n" " file name of \"-\" stands for standard input.\n" "\n" " --input-string instring\n" " read input from the string instring instead of from standard input.\n" " All occurrences of the line separator character (default is a\n" " semicolon) in instring are converted to newlines before the reading\n" " begins.\n" "\n" " --line-separator linesep\n" " set the line separator character to linesep. By default this is a\n" " semicolon.\n" "\n" " --output-file outfile\n" " write output to the file outfile instead of to standard output; a\n" " file name of \"-\" stands for standard output.\n" "\n" "INPUT\n" " RhumbSolve measures all angles in degrees, all lengths (s12) in meters,\n" " and all areas (S12) in meters^2. On input angles (latitude, longitude,\n" " azimuth, arc length) can be as decimal degrees or degrees, minutes,\n" " seconds. For example, \"40d30\", \"40d30'\", \"40:30\", \"40.5d\", and 40.5\n" " are all equivalent. By default, latitude precedes longitude for each\n" " point (the -w flag switches this convention); however on input either\n" " may be given first by appending (or prepending) N or S to the latitude\n" " and E or W to the longitude. Azimuths are measured clockwise from\n" " north; however this may be overridden with E or W.\n" "\n" " For details on the allowed formats for angles, see the \"GEOGRAPHIC\n" " COORDINATES\" section of GeoConvert(1).\n" "\n" "PRECISION\n" " prec gives precision of the output with prec = 0 giving 1 m precision,\n" " prec = 3 giving 1 mm precision, etc. prec is the number of digits\n" " after the decimal point for lengths. For decimal degrees, the number\n" " of digits after the decimal point is prec + 5. For DMS (degree,\n" " minute, seconds) output, the number of digits after the decimal point\n" " in the seconds component is prec + 1. The minimum value of prec is 0\n" " and the maximum is 10.\n" "\n" "ERRORS\n" " An illegal line of input will print an error message to standard output\n" " beginning with \"ERROR:\" and causes RhumbSolve to return an exit code of\n" " 1. However, an error does not cause RhumbSolve to terminate; following\n" " lines will be converted.\n" "\n" "ACCURACY\n" " The algorithm used by RhumbSolve uses exact formulas for converting\n" " between the latitude, rectifying latitude (mu), and isometric latitude\n" " (psi). These formulas are accurate for any value of the flattening.\n" " The computation of rhumb lines involves the ratio (psi1 - psi2) / (mu1\n" " - mu2) and this is subject to large round-off errors if lat1 is close\n" " to lat2. So this ratio is computed using divided differences using one\n" " of two methods: by default, this uses the addition theorem for elliptic\n" " integrals (accurate for all values of f); however, with the -s options,\n" " it is computed using the series expansions used by\n" " TransverseMercatorProj(1) for the conversions between rectifying and\n" " conformal latitudes (accurate for |f| < 0.01). For the WGS84\n" " ellipsoid, the error is about 10 nanometers using either method.\n" "\n" "EXAMPLES\n" " Route from JFK Airport to Singapore Changi Airport:\n" "\n" " echo 40:38:23N 073:46:44W 01:21:33N 103:59:22E |\n" " RhumbSolve -i -: -p 0\n" "\n" " 103:34:58.2 18523563\n" "\n" " N.B. This is not the route typically taken by aircraft because it's\n" " considerably longer than the geodesic given by GeodSolve(1).\n" "\n" " Waypoints on the route at intervals of 2000km:\n" "\n" " for ((i = 0; i <= 20; i += 2)); do echo ${i}000000;done |\n" " RhumbSolve -L 40:38:23N 073:46:44W 103:34:58.2 -: -p 0\n" "\n" " 40:38:23.0N 073:46:44.0W 0\n" " 36:24:30.3N 051:28:26.4W 9817078307821\n" " 32:10:26.8N 030:20:57.3W 18224745682005\n" " 27:56:13.2N 010:10:54.2W 25358020327741\n" " 23:41:50.1N 009:12:45.5E 31321269267102\n" " 19:27:18.7N 027:59:22.1E 36195163180159\n" " 15:12:40.2N 046:17:01.1E 40041499143669\n" " 10:57:55.9N 064:12:52.8E 42906570007050\n" " 06:43:07.3N 081:53:28.8E 44823504180200\n" " 02:28:16.2N 099:24:54.5E 45813843358737\n" " 01:46:36.0S 116:52:59.7E 45888525219677\n" "\n" "SEE ALSO\n" " GeoConvert(1), GeodSolve(1), TransverseMercatorProj(1).\n" "\n" " An online version of this utility is availbable at\n" " .\n" "\n" " The Wikipedia page, Rhumb line,\n" " .\n" "\n" "AUTHOR\n" " RhumbSolve was written by Charles Karney.\n" "\n" "HISTORY\n" " RhumbSolve was added to GeographicLib,\n" " , in version 1.37.\n" ; return retval; } GeographicLib-1.49/man/ConicProj.pod0000644000771000077100000001301713165402514017174 0ustar ckarneyckarney=head1 NAME ConicProj -- perform conic projections =head1 SYNOPSIS B ( B<-c> | B<-a> ) I I [ B<-l> I ] [ B<-k> I ] [ B<-r> ] [ B<-e> I I ] [ B<-w> ] [ B<-p> I ] [ B<--comment-delimiter> I ] [ B<--version> | B<-h> | B<--help> ] [ B<--input-file> I | B<--input-string> I ] [ B<--line-separator> I ] [ B<--output-file> I ] =head1 DESCRIPTION Perform one of two conic projections geodesics. Convert geodetic coordinates to either Lambert conformal conic or Albers equal area coordinates. The standard latitudes I and I are specified by that the B<-c> option (for Lambert conformal conic) or the B<-a> option (for Albers equal area). At least one of these options must be given (the last one given is used). Specify I = I, to obtain the case with a single standard parallel. The central meridian is given by I. The longitude of origin is given by the latitude of minimum (azimuthal) scale for Lambert conformal conic (Albers equal area). The (azimuthal) scale on the standard parallels is I. Geodetic coordinates are provided on standard input as a set of lines containing (blank separated) I and I (decimal degrees or degrees, minutes, seconds); for details on the allowed formats for latitude and longitude, see the C section of GeoConvert(1). For each set of geodetic coordinates, the corresponding projected easting, I, and northing, I, (meters) are printed on standard output together with the meridian convergence I (degrees) and (azimuthal) scale I. For Albers equal area, the radial scale is 1/I. The meridian convergence is the bearing of the I axis measured clockwise from true north. Special cases of the Lambert conformal projection are the Mercator projection (the standard latitudes equal and opposite) and the polar stereographic projection (both standard latitudes correspond to the same pole). Special cases of the Albers equal area projection are the cylindrical equal area projection (the standard latitudes equal and opposite), the Lambert azimuthal equal area projection (both standard latitude corresponds to the same pole), and the Lambert equal area conic projection (one standard parallel is at a pole). =head1 OPTIONS =over =item B<-c> I I use the Lambert conformal conic projection with standard parallels I and I. =item B<-a> I I use the Albers equal area projection with standard parallels I and I. =item B<-l> I specify the longitude of origin I (degrees, default 0). =item B<-k> I specify the (azimuthal) scale I on the standard parallels (default 1). =item B<-r> perform the reverse projection. I and I are given on standard input and each line of standard output gives I, I, I, and I. =item B<-e> I I specify the ellipsoid via the equatorial radius, I and the flattening, I. Setting I = 0 results in a sphere. Specify I E 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for I. By default, the WGS84 ellipsoid is used, I = 6378137 m, I = 1/298.257223563. =item B<-w> toggle the longitude first flag (it starts off); if the flag is on, then on input and output, longitude precedes latitude (except that, on input, this can be overridden by a hemisphere designator, I, I, I, I). =item B<-p> I set the output precision to I (default 6). I is the number of digits after the decimal point for lengths (in meters). For latitudes and longitudes (in degrees), the number of digits after the decimal point is I + 5. For the convergence (in degrees) and scale, the number of digits after the decimal point is I + 6. =item B<--comment-delimiter> I set the comment delimiter to I (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). =item B<--version> print version and exit. =item B<-h> print usage and exit. =item B<--help> print full documentation and exit. =item B<--input-file> I read input from the file I instead of from standard input; a file name of "-" stands for standard input. =item B<--input-string> I read input from the string I instead of from standard input. All occurrences of the line separator character (default is a semicolon) in I are converted to newlines before the reading begins. =item B<--line-separator> I set the line separator character to I. By default this is a semicolon. =item B<--output-file> I write output to the file I instead of to standard output; a file name of "-" stands for standard output. =back =head1 EXAMPLES echo 39.95N 75.17W | ConicProj -c 40d58 39d56 -l 77d45W => 220445 -52372 1.67 1.0 echo 220445 -52372 | ConicProj -c 40d58 39d56 -l 77d45W -r => 39.95 -75.17 1.67 1.0 =head1 ERRORS An illegal line of input will print an error message to standard output beginning with C and causes B to return an exit code of 1. However, an error does not cause B to terminate; following lines will be converted. =head1 AUTHOR B was written by Charles Karney. =head1 HISTORY B was added to GeographicLib, L, in version 1.9. GeographicLib-1.49/man/GeoConvert.pod0000644000771000077100000003267713165402514017376 0ustar ckarneyckarney=head1 NAME GeoConvert -- convert geographic coordinates =head1 SYNOPSIS B [ B<-g> | B<-d> | B<-:> | B<-u> | B<-m> | B<-c> ] [ B<-z> I | B<-s> | B<-t> | B<-S> | B<-T> ] [ B<-n> ] [ B<-w> ] [ B<-p> I ] [ B<-l> | B<-a> ] [ B<--comment-delimiter> I ] [ B<--version> | B<-h> | B<--help> ] [ B<--input-file> I | B<--input-string> I ] [ B<--line-separator> I ] [ B<--output-file> I ] =head1 DESCRIPTION B reads from standard input interpreting each line as a geographic coordinate and prints the coordinate in the format specified by the options on standard output. The input is interpreted in one of three different ways depending on how many space or comma delimited tokens there are on the line. The options B<-g>, B<-d>, B<-u>, and B<-m> govern the format of output. In all cases, the WGS84 model of the earth is used (I = 6378137 m, I = 1/298.257223563). =over =item B 2 tokens (output options B<-g>, B<-d>, or B<-:>) given as I I using decimal degrees or degrees, minutes, and seconds. Latitude is given first (unless the B<-w> option is given). See L for a description of the format. For example, the following are all equivalent 33.3 44.4 E44.4 N33.3 33d18'N 44d24'E 44d24 33d18N 33:18 +44:24 =item B 3 tokens (output option B<-u>) given as I+I I I or I I I+I, where I is either I (or I) or I (or I). The I is absent for a UPS specification. For example, 38n 444140.54 3684706.36 444140.54 3684706.36 38n s 2173854.98 2985980.58 2173854.98 2985980.58 s =item B 1 token (output option B<-m>) is used to specify the center of an MGRS grid square. For example, 38SMB4484 38SMB44140847064 =back =head1 OPTIONS =over =item B<-g> output latitude and longitude using decimal degrees. Default output mode. =item B<-d> output latitude and longitude using degrees, minutes, and seconds (DMS). =item B<-:> like B<-d>, except use : as a separator instead of the d, ', and " delimiters. =item B<-u> output UTM or UPS. =item B<-m> output MGRS. =item B<-c> output meridian convergence and scale for the corresponding UTM or UPS projection. The meridian convergence is the bearing of grid north given as degrees clockwise from true north. =item B<-z> I set the zone to I for output. Use either 0 E I E= 60 for a UTM zone or I = 0 for UPS. Alternatively use a I+I designation, e.g., 38n. See L. =item B<-s> use the standard UPS and UTM zones. =item B<-t> similar to B<-s> but forces UPS regions to the closest UTM zone. =item B<-S> or B<-T> behave the same as B<-s> and B<-t>, respectively, until the first legal conversion is performed. For subsequent points, the zone and hemisphere of that conversion are used. This enables a sequence of points to be converted into UTM or UPS using a consistent coordinate system. =item B<-n> on input, MGRS coordinates refer to the south-west corner of the MGRS square instead of the center; see L. =item B<-w> toggle the longitude first flag (it starts off); if the flag is on, then on input and output, longitude precedes latitude (except that, on input, this can be overridden by a hemisphere designator, I, I, I, I). =item B<-p> I set the output precision to I (default 0); I is the precision relative to 1 m. See L. =item B<-l> on output, UTM/UPS uses the long forms I and I to designate the hemisphere instead of I or I. =item B<-a> on output, UTM/UPS uses the abbreviations I and I to designate the hemisphere instead of I or I; this is the default representation. =item B<--comment-delimiter> I set the comment delimiter to I (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space). =item B<--version> print version and exit. =item B<-h> print usage and exit. =item B<--help> print full documentation and exit. =item B<--input-file> I read input from the file I instead of from standard input; a file name of "-" stands for standard input. =item B<--input-string> I read input from the string I instead of from standard input. All occurrences of the line separator character (default is a semicolon) in I are converted to newlines before the reading begins. =item B<--line-separator> I set the line separator character to I. By default this is a semicolon. =item B<--output-file> I write output to the file I instead of to standard output; a file name of "-" stands for standard output. =back =head1 PRECISION I gives precision of the output with I = 0 giving 1 m precision, I = 3 giving 1 mm precision, etc. I is the number of digits after the decimal point for UTM/UPS. For MGRS, The number of digits per coordinate is 5 + I; = -6 results in just the grid zone. For decimal degrees, the number of digits after the decimal point is 5 + I. For DMS (degree, minute, seconds) output, the number of digits after the decimal point in the seconds components is 1 + I; if this is negative then use minutes (I = -2 or -3) or degrees (I E= -4) as the least significant component. Print convergence, resp. scale, with 5 + I, resp. 7 + I, digits after the decimal point. The minimum value of I is -5 (-6 for MGRS) and the maximum is 9 for UTM/UPS, 9 for decimal degrees, 10 for DMS, 6 for MGRS, and 8 for convergence and scale. =head1 GEOGRAPHIC COORDINATES The utility accepts geographic coordinates, latitude and longitude, in a number of common formats. Latitude precedes longitude, unless the B<-w> option is given which switches this convention. On input, either coordinate may be given first by appending or prepending I or I to the latitude and I or I to the longitude. These hemisphere designators carry an implied sign, positive for I and I and negative for I and I. This sign multiplies any +/- sign prefixing the coordinate. The coordinates may be given as decimal degree or as degrees, minutes, and seconds. d, ', and " are used to denote degrees, minutes, and seconds, with the least significant designator optional. (See L for how to quote the characters ' and " when entering coordinates on the command line.) Alternatively, : (colon) may be used to separate the various components. Only the final component of coordinate can include a decimal point, and the minutes and seconds components must be less than 60. It is also possible to carry out addition or subtraction operations in geographic coordinates. If the coordinate includes interior signs (i.e., not at the beginning or immediately after an initial hemisphere designator), then the coordinate is split before such signs; the pieces are parsed separately and the results summed. For example the point 15" east of 39N 70W is 39N 70W+0:0:15E B "Exponential" notation is not recognized for geographic coordinates. Thus 7.0E1 is illegal, while 7.0E+1 is parsed as (7.0E) + (+1), yielding the same result as 8.0E. Various unicode characters (encoded with UTF-8) may also be used to denote degrees, minutes, and seconds, e.g., the degree, prime, and double prime symbols; in addition two single quotes can be used to represent ". The other GeographicLib utilities use the same rules for interpreting geographic coordinates; in addition, azimuths and arc lengths are interpreted the same way. =head1 QUOTING Unfortunately the characters ' and " have special meanings in many shells and have to be entered with care. However note (1) that the trailing designator is optional and that (2) you can use colons as a separator character. Thus 10d20' can be entered as 10d20 or 10:20 and 10d20'30" can be entered as 10:20:30. =over =item Unix shells (sh, bash, tsch) The characters ' and " can be quoted by preceding them with a \ (backslash); or you can quote a string containing ' with a pair of "s. The two alternatives are illustrated by echo 10d20\'30\" "20d30'40" | GeoConvert -d -p -1 => 10d20'30"N 020d30'40"E Quoting of command line arguments is similar GeoConvert -d -p -1 --input-string "10d20'30\" 20d30'40" => 10d20'30"N 020d30'40"E =item Windows command shell (cmd) The ' character needs no quoting; the " character can either be quoted by a ^ or can be represented by typing ' twice. (This quoting is usually unnecessary because the trailing designator can be omitted.) Thus echo 10d20'30'' 20d30'40 | GeoConvert -d -p -1 => 10d20'30"N 020d30'40"E Use \ to quote the " character in a command line argument GeoConvert -d -p -1 --input-string "10d20'30\" 20d30'40" => 10d20'30"N 020d30'40"E =item Input from a file No quoting need be done if the input from a file. Thus each line of the file C should just contain the plain coordinates. GeoConvert -d -p -1 < input.txt =back =head1 MGRS MGRS coordinates represent a square patch of the earth, thus C<38SMB4488> is in zone C<38n> with 444km E= I E 445km and 3688km E= I E 3689km. Consistent with this representation, coordinates are I (instead of I) to the requested precision. Similarly, on input an MGRS coordinate represents the I
of the square (C<38n 444500 3688500> in the example above). However, if the B<-n> option is given then the south-west corner of the square is returned instead (C<38n 444000 3688000> in the example above). =head1 ZONE If the input is B, B uses the standard rules of selecting UTM vs UPS and for assigning the UTM zone (with the Norway and Svalbard exceptions). If the input is B or B, then the choice between UTM and UPS and the UTM zone mirrors the input. The B<-z> I, B<-s>, and B<-t> options allow these rules to be overridden with I = 0 being used to indicate UPS. For example, the point 79.9S 6.1E corresponds to possible MGRS coordinates 32CMS4324728161 (standard UTM zone = 32) 31CEM6066227959 (neighboring UTM zone = 31) BBZ1945517770 (neighboring UPS zone) then echo 79.9S 6.1E | GeoConvert -p -3 -m => 32CMS4328 echo 31CEM6066227959 | GeoConvert -p -3 -m => 31CEM6027 echo 31CEM6066227959 | GeoConvert -p -3 -m -s => 32CMS4328 echo 31CEM6066227959 | GeoConvert -p -3 -m -z 0 => BBZ1917 Is I is specified with a hemisphere, then this is honored when printing UTM coordinates: echo -1 3 | GeoConvert -u => 31s 500000 9889470 echo -1 3 | GeoConvert -u -z 31 => 31s 500000 9889470 echo -1 3 | GeoConvert -u -z 31s => 31s 500000 9889470 echo -1 3 | GeoConvert -u -z 31n => 31n 500000 -110530 B: the letter in the zone specification for UTM is a hemisphere designator I or I and I an MGRS latitude band letter. Convert the MGRS latitude band letter to a hemisphere as follows: replace I thru I by I (or I); replace I thru I by I (or I). =head1 EXAMPLES echo 38SMB4488 | GeoConvert => 33.33424 44.40363 echo 38SMB4488 | GeoConvert -: -p 1 => 33:20:03.25N 044:2413.06E echo 38SMB4488 | GeoConvert -u => 38n 444500 3688500 echo E44d24 N33d20 | GeoConvert -m -p -3 => 38SMB4488 GeoConvert can be used to do simple arithmetic using degree, minutes, and seconds. For example, sometimes data is tiled in 15 second squares tagged by the DMS representation of the SW corner. The tags of the tile at 38:59:45N 077:02:00W and its 8 neighbors are then given by t=0:0:15 for y in -$t +0 +$t; do for x in -$t +0 +$t; do echo 38:59:45N$y 077:02:00W$x done done | GeoConvert -: -p -1 | tr -d ': ' => 385930N0770215W 385930N0770200W 385930N0770145W 385945N0770215W 385945N0770200W 385945N0770145W 390000N0770215W 390000N0770200W 390000N0770145W =head1 ERRORS An illegal line of input will print an error message to standard output beginning with C and causes B to return an exit code of 1. However, an error does not cause B to terminate; following lines will be converted. =head1 ABBREVIATIONS =over =item B Universal Transverse Mercator, L. =item B Universal Polar Stereographic, L. =item B Military Grid Reference System, L. =item B World Geodetic System 1984, L. =back =head1 SEE ALSO An online version of this utility is availbable at L. The algorithms for the transverse Mercator projection are described in C. F. F. Karney, I, J. Geodesy B<85>(8), 475-485 (Aug. 2011); DOI L; preprint L. =head1 AUTHOR B was written by Charles Karney. =head1 HISTORY B was added to GeographicLib, L, in 2009-01. GeographicLib-1.49/man/dummy.usage.in0000644000771000077100000000045213165402514017367 0ustar ckarneyckarney// Dummy usage file to be used when the man page isn't available int usage(int retval, bool /* brief */) { ( retval ? std::cerr : std::cout ) << "For full documentation on @TOOL@, see\n" << " https://geographiclib.sourceforge.io/@PROJECT_VERSION@/@TOOL@.1.html\n"; return retval; } GeographicLib-1.49/man/ConicProj.1.html0000644000771000077100000001641313165402556017526 0ustar ckarneyckarney ConicProj(1)

NAME

ConicProj -- perform conic projections

SYNOPSIS

ConicProj ( -c | -a ) lat1 lat2 [ -l lon0 ] [ -k k1 ] [ -r ] [ -e a f ] [ -w ] [ -p prec ] [ --comment-delimiter commentdelim ] [ --version | -h | --help ] [ --input-file infile | --input-string instring ] [ --line-separator linesep ] [ --output-file outfile ]

DESCRIPTION

Perform one of two conic projections geodesics. Convert geodetic coordinates to either Lambert conformal conic or Albers equal area coordinates. The standard latitudes lat1 and lat2 are specified by that the -c option (for Lambert conformal conic) or the -a option (for Albers equal area). At least one of these options must be given (the last one given is used). Specify lat1 = lat2, to obtain the case with a single standard parallel. The central meridian is given by lon0. The longitude of origin is given by the latitude of minimum (azimuthal) scale for Lambert conformal conic (Albers equal area). The (azimuthal) scale on the standard parallels is k1.

Geodetic coordinates are provided on standard input as a set of lines containing (blank separated) latitude and longitude (decimal degrees or degrees, minutes, seconds); for details on the allowed formats for latitude and longitude, see the GEOGRAPHIC COORDINATES section of GeoConvert(1). For each set of geodetic coordinates, the corresponding projected easting, x, and northing, y, (meters) are printed on standard output together with the meridian convergence gamma (degrees) and (azimuthal) scale k. For Albers equal area, the radial scale is 1/k. The meridian convergence is the bearing of the y axis measured clockwise from true north.

Special cases of the Lambert conformal projection are the Mercator projection (the standard latitudes equal and opposite) and the polar stereographic projection (both standard latitudes correspond to the same pole). Special cases of the Albers equal area projection are the cylindrical equal area projection (the standard latitudes equal and opposite), the Lambert azimuthal equal area projection (both standard latitude corresponds to the same pole), and the Lambert equal area conic projection (one standard parallel is at a pole).

OPTIONS

-c lat1 lat2

use the Lambert conformal conic projection with standard parallels lat1 and lat2.

-a lat1 lat2

use the Albers equal area projection with standard parallels lat1 and lat2.

-l lon0

specify the longitude of origin lon0 (degrees, default 0).

-k k1

specify the (azimuthal) scale k1 on the standard parallels (default 1).

-r

perform the reverse projection. x and y are given on standard input and each line of standard output gives latitude, longitude, gamma, and k.

-e a f

specify the ellipsoid via the equatorial radius, a and the flattening, f. Setting f = 0 results in a sphere. Specify f < 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for f. By default, the WGS84 ellipsoid is used, a = 6378137 m, f = 1/298.257223563.

-w

toggle the longitude first flag (it starts off); if the flag is on, then on input and output, longitude precedes latitude (except that, on input, this can be overridden by a hemisphere designator, N, S, E, W).

-p prec

set the output precision to prec (default 6). prec is the number of digits after the decimal point for lengths (in meters). For latitudes and longitudes (in degrees), the number of digits after the decimal point is prec + 5. For the convergence (in degrees) and scale, the number of digits after the decimal point is prec + 6.

--comment-delimiter commentdelim

set the comment delimiter to commentdelim (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space).

--version

print version and exit.

-h

print usage and exit.

--help

print full documentation and exit.

--input-file infile

read input from the file infile instead of from standard input; a file name of "-" stands for standard input.

--input-string instring

read input from the string instring instead of from standard input. All occurrences of the line separator character (default is a semicolon) in instring are converted to newlines before the reading begins.

--line-separator linesep

set the line separator character to linesep. By default this is a semicolon.

--output-file outfile

write output to the file outfile instead of to standard output; a file name of "-" stands for standard output.

EXAMPLES

   echo 39.95N 75.17W | ConicProj -c 40d58 39d56 -l 77d45W
   => 220445 -52372 1.67 1.0
   echo 220445 -52372 | ConicProj -c 40d58 39d56 -l 77d45W -r
   => 39.95 -75.17 1.67 1.0

ERRORS

An illegal line of input will print an error message to standard output beginning with ERROR: and causes ConicProj to return an exit code of 1. However, an error does not cause ConicProj to terminate; following lines will be converted.

AUTHOR

ConicProj was written by Charles Karney.

HISTORY

GeographicLib-1.49/man/TransverseMercatorProj.1.html0000644000771000077100000001706313165402556022326 0ustar ckarneyckarney TransverseMercatorProj(1)

NAME

TransverseMercatorProj -- perform transverse Mercator projection

SYNOPSIS

TransverseMercatorProj [ -s | -t ] [ -l lon0 ] [ -k k0 ] [ -r ] [ -e a f ] [ -w ] [ -p prec ] [ --comment-delimiter commentdelim ] [ --version | -h | --help ] [ --input-file infile | --input-string instring ] [ --line-separator linesep ] [ --output-file outfile ]

DESCRIPTION

Perform the transverse Mercator projections. Convert geodetic coordinates to transverse Mercator coordinates. The central meridian is given by lon0. The longitude of origin is the equator. The scale on the central meridian is k0. By default an implementation of the exact transverse Mercator projection is used.

Geodetic coordinates are provided on standard input as a set of lines containing (blank separated) latitude and longitude (decimal degrees or degrees, minutes, seconds); for detils on the allowed formats for latitude and longitude, see the GEOGRAPHIC COORDINATES section of GeoConvert(1). For each set of geodetic coordinates, the corresponding projected easting, x, and northing, y, (meters) are printed on standard output together with the meridian convergence gamma (degrees) and scale k. The meridian convergence is the bearing of grid north (the y axis) measured clockwise from true north.

OPTIONS

-s

use the sixth-order Krueger series approximation to the transverse Mercator projection instead of the exact projection.

-t

use the exact algorithm with the "EXTENDED DOMAIN".

-l lon0

specify the longitude of origin lon0 (degrees, default 0).

-k k0

specify the scale k0 on the central meridian (default 0.9996).

-r

perform the reverse projection. x and y are given on standard input and each line of standard output gives latitude, longitude, gamma, and k.

-e a f

specify the ellipsoid via the equatorial radius, a and the flattening, f. Setting f = 0 results in a sphere. Specify f < 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for f. By default, the WGS84 ellipsoid is used, a = 6378137 m, f = 1/298.257223563. If the exact algorithm is used, f must be positive.

-w

on input and output, longitude precedes latitude (except that on input this can be overridden by a hemisphere designator, N, S, E, W).

-p prec

set the output precision to prec (default 6). prec is the number of digits after the decimal point for lengths (in meters). For latitudes and longitudes (in degrees), the number of digits after the decimal point is prec + 5. For the convergence (in degrees) and scale, the number of digits after the decimal point is prec + 6.

--comment-delimiter commentdelim

set the comment delimiter to commentdelim (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space).

--version

print version and exit.

-h

print usage and exit.

--help

print full documentation and exit.

--input-file infile

read input from the file infile instead of from standard input; a file name of "-" stands for standard input.

--input-string instring

read input from the string instring instead of from standard input. All occurrences of the line separator character (default is a semicolon) in instring are converted to newlines before the reading begins.

--line-separator linesep

set the line separator character to linesep. By default this is a semicolon.

--output-file outfile

write output to the file outfile instead of to standard output; a file name of "-" stands for standard output.

EXTENDED DOMAIN

The exact transverse Mercator projection has a branch point on the equator at longitudes (relative to lon0) of +/- (1 - e) 90, where e is the eccentricity of the ellipsoid. The standard convention for handling this branch point is to map positive (negative) latitudes into positive (negative) northings y; i.e., a branch cut is placed on the equator. With the extended domain, the northern sheet of the projection is extended into the south hemisphere by pushing the branch cut south from the branch points. See the reference below for details.

EXAMPLES

   echo 0 90 | TransverseMercatorProj
   => 25953592.84 9997964.94 90 18.40
   echo 260e5 100e5 | TransverseMercatorProj -r
   => -0.02 90.00 90.01 18.48

ERRORS

An illegal line of input will print an error message to standard output beginning with ERROR: and causes TransverseMercatorProj to return an exit code of 1. However, an error does not cause TransverseMercatorProj to terminate; following lines will be converted.

AUTHOR

TransverseMercatorProj was written by Charles Karney.

SEE ALSO

The algorithms for the transverse Mercator projection are described in C. F. F. Karney, Transverse Mercator with an accuracy of a few nanometers, J. Geodesy 85(8), 475-485 (Aug. 2011); DOI https://doi.org/10.1007/s00190-011-0445-3; preprint https://arxiv.org/abs/1002.1417. The explanation of the extended domain of the projection with the -t option is given in Section 5 of this paper.

HISTORY

TransverseMercatorProj was added to GeographicLib, https://geographiclib.sourceforge.io, in 2009-01. Prior to version 1.9 it was called TransverseMercatorTest (and its interface was slightly different).

GeographicLib-1.49/man/GeodSolve.1.html0000644000771000077100000004233013165402556017524 0ustar ckarneyckarney GeodSolve(1)

NAME

GeodSolve -- perform geodesic calculations

SYNOPSIS

GeodSolve [ -i | -L lat1 lon1 azi1 | -D lat1 lon1 azi1 s13 | -I lat1 lon1 lat3 lon3 ] [ -a ] [ -e a f ] [ -u ] [ -F ] [ -d | -: ] [ -w ] [ -b ] [ -f ] [ -p prec ] [ -E ] [ --comment-delimiter commentdelim ] [ --version | -h | --help ] [ --input-file infile | --input-string instring ] [ --line-separator linesep ] [ --output-file outfile ]

DESCRIPTION

The shortest path between two points on the ellipsoid at (lat1, lon1) and (lat2, lon2) is called the geodesic. Its length is s12 and the geodesic from point 1 to point 2 has forward azimuths azi1 and azi2 at the two end points.

GeodSolve operates in one of three modes:

  1. By default, GeodSolve accepts lines on the standard input containing lat1 lon1 azi1 s12 and prints lat2 lon2 azi2 on standard output. This is the direct geodesic calculation.

  2. With the -i command line argument, GeodSolve performs the inverse geodesic calculation. It reads lines containing lat1 lon1 lat2 lon2 and prints the corresponding values of azi1 azi2 s12.

  3. Command line arguments -L lat1 lon1 azi1 specify a geodesic line. GeodSolve then accepts a sequence of s12 values (one per line) on standard input and prints lat2 lon2 azi2 for each. This generates a sequence of points on a single geodesic. Command line arguments -D and -I work similarly with the geodesic line defined in terms of a direct or inverse geodesic calculation, respectively.

OPTIONS

-i

perform an inverse geodesic calculation (see 2 above).

-L lat1 lon1 azi1

line mode (see 3 above); generate a sequence of points along the geodesic specified by lat1 lon1 azi1. The -w flag can be used to swap the default order of the 2 geographic coordinates, provided that it appears before -L. (-l is an alternative, deprecated, spelling of this flag.)

-D lat1 lon1 azi1 s13

line mode (see 3 above); generate a sequence of points along the geodesic specified by lat1 lon1 azi1 s13. The -w flag can be used to swap the default order of the 2 geographic coordinates, provided that it appears before -D. Similarly, the -a flag can be used to change the interpretation of s13 to a13, provided that it appears before -D.

-I lat1 lon1 lat3 lon3

line mode (see 3 above); generate a sequence of points along the geodesic specified by lat1 lon1 lat3 lon3. The -w flag can be used to swap the default order of the 2 geographic coordinates, provided that it appears before -I.

-a

toggle the arc mode flag (it starts off); if this flag is on, then on input and output s12 is replaced by a12 the arc length (in degrees) on the auxiliary sphere. See "AUXILIARY SPHERE".

-e a f

specify the ellipsoid via the equatorial radius, a and the flattening, f. Setting f = 0 results in a sphere. Specify f < 0 for a prolate ellipsoid. A simple fraction, e.g., 1/297, is allowed for f. By default, the WGS84 ellipsoid is used, a = 6378137 m, f = 1/298.257223563.

-u

unroll the longitude. Normally, on output longitudes are reduced to lie in [-180deg,180deg). However with this option, the returned longitude lon2 is "unrolled" so that lon2 - lon1 indicates how often and in what sense the geodesic has encircled the earth. Use the -f option, to get both longitudes printed.

-F

fractional mode. This only has any effect with the -D and -I options (and is otherwise ignored). The values read on standard input are interpreted as fractional distances to point 3, i.e., as s12/s13 instead of s12. If arc mode is in effect, then the values denote fractional arc length, i.e., a12/a13.

-d

output angles as degrees, minutes, seconds instead of decimal degrees.

-:

like -d, except use : as a separator instead of the d, ', and " delimiters.

-w

toggle the longitude first flag (it starts off); if the flag is on, then on input and output, longitude precedes latitude (except that, on input, this can be overridden by a hemisphere designator, N, S, E, W).

-b

report the back azimuth at point 2 instead of the forward azimuth.

-f

full output; each line of output consists of 12 quantities: lat1 lon1 azi1 lat2 lon2 azi2 s12 a12 m12 M12 M21 S12. a12 is described in "AUXILIARY SPHERE". The four quantities m12, M12, M21, and S12 are described in "ADDITIONAL QUANTITIES".

-p prec

set the output precision to prec (default 3); prec is the precision relative to 1 m. See "PRECISION".

-E

use "exact" algorithms (based on elliptic integrals) for the geodesic calculations. These are more accurate than the (default) series expansions for |f| > 0.02.

--comment-delimiter commentdelim

set the comment delimiter to commentdelim (e.g., "#" or "//"). If set, the input lines will be scanned for this delimiter and, if found, the delimiter and the rest of the line will be removed prior to processing and subsequently appended to the output line (separated by a space).

--version

print version and exit.

-h

print usage and exit.

--help

print full documentation and exit.

--input-file infile

read input from the file infile instead of from standard input; a file name of "-" stands for standard input.

--input-string instring

read input from the string instring instead of from standard input. All occurrences of the line separator character (default is a semicolon) in instring are converted to newlines before the reading begins.

--line-separator linesep

set the line separator character to linesep. By default this is a semicolon.

--output-file outfile

write output to the file outfile instead of to standard output; a file name of "-" stands for standard output.

INPUT

GeodSolve measures all angles in degrees and all lengths (s12) in meters, and all areas (S12) in meters^2. On input angles (latitude, longitude, azimuth, arc length) can be as decimal degrees or degrees, minutes, seconds. For example, 40d30, 40d30', 40:30, 40.5d, and 40.5 are all equivalent. By default, latitude precedes longitude for each point (the -w flag switches this convention); however on input either may be given first by appending (or prepending) N or S to the latitude and E or W to the longitude. Azimuths are measured clockwise from north; however this may be overridden with E or W.

For details on the allowed formats for angles, see the GEOGRAPHIC COORDINATES section of GeoConvert(1).

AUXILIARY SPHERE

Geodesics on the ellipsoid can be transferred to the auxiliary sphere on which the distance is measured in terms of the arc length a12 (measured in degrees) instead of s12. In terms of a12, 180 degrees is the distance from one equator crossing to the next or from the minimum latitude to the maximum latitude. Geodesics with a12 > 180 degrees do not correspond to shortest paths. With the -a flag, s12 (on both input and output) is replaced by a12. The -a flag does not affect the full output given by the -f flag (which always includes both s12 and a12).

ADDITIONAL QUANTITIES

The -f flag reports four additional quantities.

The reduced length of the geodesic, m12, is defined such that if the initial azimuth is perturbed by dazi1 (radians) then the second point is displaced by m12 dazi1 in the direction perpendicular to the geodesic. m12 is given in meters. On a curved surface the reduced length obeys a symmetry relation, m12 + m21 = 0. On a flat surface, we have m12 = s12.

M12 and M21 are geodesic scales. If two geodesics are parallel at point 1 and separated by a small distance dt, then they are separated by a distance M12 dt at point 2. M21 is defined similarly (with the geodesics being parallel to one another at point 2). M12 and M21 are dimensionless quantities. On a flat surface, we have M12 = M21 = 1.

If points 1, 2, and 3 lie on a single geodesic, then the following addition rules hold:

   s13 = s12 + s23,
   a13 = a12 + a23,
   S13 = S12 + S23,
   m13 = m12 M23 + m23 M21,
   M13 = M12 M23 - (1 - M12 M21) m23 / m12,
   M31 = M32 M21 - (1 - M23 M32) m12 / m23.

Finally, S12 is the area between the geodesic from point 1 to point 2 and the equator; i.e., it is the area, measured counter-clockwise, of the geodesic quadrilateral with corners (lat1,lon1), (0,lon1), (0,lon2), and (lat2,lon2). It is given in meters^2.

PRECISION

prec gives precision of the output with prec = 0 giving 1 m precision, prec = 3 giving 1 mm precision, etc. prec is the number of digits after the decimal point for lengths. For decimal degrees, the number of digits after the decimal point is prec + 5. For DMS (degree, minute, seconds) output, the number of digits after the decimal point in the seconds component is prec + 1. The minimum value of prec is 0 and the maximum is 10.

ERRORS

An illegal line of input will print an error message to standard output beginning with ERROR: and causes GeodSolve to return an exit code of 1. However, an error does not cause GeodSolve to terminate; following lines will be converted.

ACCURACY

Using the (default) series solution, GeodSolve is accurate to about 15 nm (15 nanometers) for the WGS84 ellipsoid. The approximate maximum error (expressed as a distance) for an ellipsoid with the same equatorial radius as the WGS84 ellipsoid and different values of the flattening is

   |f|     error
   0.01    25 nm
   0.02    30 nm
   0.05    10 um
   0.1    1.5 mm
   0.2    300 mm

If -E is specified, GeodSolve is accurate to about 40 nm (40 nanometers) for the WGS84 ellipsoid. The approximate maximum error (expressed as a distance) for an ellipsoid with a quarter meridian of 10000 km and different values of the a/b = 1 - f is

   1-f    error (nm)
   1/128   387
   1/64    345
   1/32    269
   1/16    210
   1/8     115
   1/4      69
   1/2      36
     1      15
     2      25
     4      96
     8     318
    16     985
    32    2352
    64    6008
   128   19024

MULTIPLE SOLUTIONS

The shortest distance returned for the inverse problem is (obviously) uniquely defined. However, in a few special cases there are multiple azimuths which yield the same shortest distance. Here is a catalog of those cases:

lat1 = -lat2 (with neither point at a pole)

If azi1 = azi2, the geodesic is unique. Otherwise there are two geodesics and the second one is obtained by setting [azi1,azi2] = [azi2,azi1], [M12,M21] = [M21,M12], S12 = -S12. (This occurs when the longitude difference is near +/-180 for oblate ellipsoids.)

lon2 = lon1 +/- 180 (with neither point at a pole)

If azi1 = 0 or +/-180, the geodesic is unique. Otherwise there are two geodesics and the second one is obtained by setting [azi1,azi2] = [-azi1,-azi2], S12 = -S12. (This occurs when lat2 is near -lat1 for prolate ellipsoids.)

Points 1 and 2 at opposite poles

There are infinitely many geodesics which can be generated by setting [azi1,azi2] = [azi1,azi2] + [d,-d], for arbitrary d. (For spheres, this prescription applies when points 1 and 2 are antipodal.)

s12 = 0 (coincident points)

There are infinitely many geodesics which can be generated by setting [azi1,azi2] = [azi1,azi2] + [d,d], for arbitrary d.

EXAMPLES

Route from JFK Airport to Singapore Changi Airport:

   echo 40:38:23N 073:46:44W 01:21:33N 103:59:22E |
   GeodSolve -i -: -p 0

   003:18:29.9 177:29:09.2 15347628

Equally spaced waypoints on the route:

   for ((i = 0; i <= 10; ++i)); do echo ${i}e-1; done |
   GeodSolve -I 40:38:23N 073:46:44W 01:21:33N 103:59:22E -F -: -p 0

   40:38:23.0N 073:46:44.0W 003:18:29.9
   54:24:51.3N 072:25:39.6W 004:18:44.1
   68:07:37.7N 069:40:42.9W 006:44:25.4
   81:38:00.4N 058:37:53.9W 017:28:52.7
   83:43:26.0N 080:37:16.9E 156:26:00.4
   70:20:29.2N 097:01:29.4E 172:31:56.4
   56:38:36.0N 100:14:47.6E 175:26:10.5
   42:52:37.1N 101:43:37.2E 176:34:28.6
   29:03:57.0N 102:39:34.8E 177:07:35.2
   15:13:18.6N 103:22:08.0E 177:23:44.7
   01:21:33.0N 103:59:22.0E 177:29:09.2

SEE ALSO

GeoConvert(1).

An online version of this utility is availbable at https://geographiclib.sourceforge.io/cgi-bin/GeodSolve.

The algorithms are described in C. F. F. Karney, Algorithms for geodesics, J. Geodesy 87, 43-55 (2013); DOI: https://doi.org/10.1007/s00190-012-0578-z; addenda: https://geographiclib.sourceforge.io/geod-addenda.html.

The Wikipedia page, Geodesics on an ellipsoid, https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid.

AUTHOR

GeodSolve was written by Charles Karney.

HISTORY

GeodSolve was added to GeographicLib, https://geographiclib.sourceforge.io, in 2009-03. Prior to version 1.30, it was called Geod. (The name was changed to avoid a conflict with the geod utility in proj.4.)

GeographicLib-1.49/man/MagneticField.pod0000644000771000077100000002177513165402514020013 0ustar ckarneyckarney=head1 NAME MagneticField -- compute the earth's magnetic field =head1 SYNOPSIS B [ B<-n> I ] [ B<-d> I ] [ B<-t> I

ConicProj was added to GeographicLib, https://geographiclib.sourceforge.io, in version 1.9.