From f3971a05f18a03c3483db5ff12f1990c5468de9b Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Sat, 19 Jul 2014 12:27:14 -0400 Subject: [PATCH] mpfr works with Apple. Set mpreal precision with GEOGRAPHICLIB_DIGITS. Add -p prec to all the *Proj utilities. --- CMakeLists.txt | 176 ++++++++++++++++-------------- doc/GeographicLib.dox | 9 +- include/GeographicLib/Math.hpp | 9 +- include/GeographicLib/Utility.hpp | 12 ++ man/ConicProj.pod | 10 +- man/GeodesicProj.pod | 10 +- src/CMakeLists.txt | 8 ++ src/Utility.cpp | 16 +++ tools/CartConvert.cpp | 14 +-- tools/ConicProj.cpp | 31 ++++-- tools/GeoConvert.cpp | 2 +- tools/GeodSolve.cpp | 2 +- tools/GeodesicProj.cpp | 31 ++++-- tools/GeoidEval.cpp | 2 +- tools/Gravity.cpp | 8 +- tools/MagneticField.cpp | 4 +- tools/Planimeter.cpp | 2 +- tools/TransverseMercatorProj.cpp | 2 +- 18 files changed, 221 insertions(+), 127 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f0cce07..69fd5d06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,6 +231,56 @@ set (GEOGRAPHICLIB_HAVE_LONG_DOUBLE ${HAVE_LONG_DOUBLE}) include (TestBigEndian) test_big_endian (GEOGRAPHICLIB_WORDS_BIGENDIAN) +# Make the compiler more picky. +if (MSVC) + string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") +else () + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") + # check for C++11 support. If available, the C++11 static_assert is + # used. This flag is *not* propagated to clients that use + # GeographicLib. However, this is of no consequence. When the client + # code is being compiled (and the GeographicLib headers being + # included), a work-alike substitution is used. + include (CheckCXXCompilerFlag) + set (CXX11_FLAG "-std=c++11") + check_cxx_compiler_flag (${CXX11_FLAG} CXX11TEST1) + if (NOT CXX11TEST1) + set (CXX11_FLAG "-std=c++0x") + check_cxx_compiler_flag (${CXX11_FLAG} CXX11TEST2) + if (NOT CXX11TEST2) + unset (CXX11_FLAG) + endif () + endif () + if (CXX11_FLAG) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAG}") + endif () +endif () + +# Check whether the C++11 math function: std::expm1, std::atanh, +# etc. are available. This flag is *not* propagated to clients that use +# GeographicLib. However, this is of no consequence. When the client +# code is being compiled (and the GeographicLib headers being included), +# work-alike substitutions are used. +include (CheckCXXSourceCompiles) +set (CMAKE_REQUIRED_FLAGS "${CMAKE_CXX_FLAGS}") +check_cxx_source_compiles ( + "#include +int main() { + return int(std::hypot(3.0, 4.0) + std::expm1(0.5) + std::log1p(2.0) + + std::asinh(10.0) + std::atanh(0.8) + std::cbrt(8.0)) + + std::isfinite(4.0) + std::isnan(0.0); +}\n" CXX11_MATH) +if (CXX11_MATH) + add_definitions (-DGEOGRAPHICLIB_CXX11_MATH=1) +else () + add_definitions (-DGEOGRAPHICLIB_CXX11_MATH=0) +endif () + +# Set the include directories. Look in ${PROJECT_BINARY_DIR}/include +# first because that's where Config.h will be +include_directories ("${PROJECT_BINARY_DIR}/include" include) + if (GEOGRAPHICLIB_PRECISION EQUAL 1) message (WARNING "Compiling with floats which results in poor accuracy") elseif (GEOGRAPHICLIB_PRECISION EQUAL 2) @@ -241,7 +291,7 @@ elseif (GEOGRAPHICLIB_PRECISION EQUAL 3) set (GEOGRAPHICLIB_PRECISION 2) endif () elseif (GEOGRAPHICLIB_PRECISION EQUAL 4) - if (CMAKE_CXX_COMPILER_ID STREQUAL GNU) + if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CXX11_MATH) # quad precision numbers appeared in Boost 1.54. find_package (Boost 1.54) if (Boost_FOUND) @@ -261,29 +311,55 @@ elseif (GEOGRAPHICLIB_PRECISION EQUAL 4) set (GEOGRAPHICLIB_PRECISION 2) endif () elseif (GEOGRAPHICLIB_PRECISION EQUAL 5) - if (WIN32) - if (MSCV AND NOT MSVC_VERSION LESS 1800) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - set (_ARCH x64) - else () - set (_ARCH Win32) + if (CXX11_MATH) + # Install MPFR C++ version 3.5.9 or later from + # http://www.holoborodko.com/pavel/mpfr and install mpreal.h in the + # include directory. NOTE: MPFR C++ is covered by the GPL; be sure + # to abide by the terms of this license. + # + # For Linux, use system versions of mpfr and gmp. For Apple, use + # brew install mpfr. For Windows, download + # MPFR-MPIR-x86-x64-MSVC2010.zip from the MPFR C++ site and unpack + # in the top-level directory. NOTE: mpfr, gmp, and mpir are covered + # by the LGPL; be sure to abide by the terms of this license. + if (WIN32) + if (MSCV AND NOT MSVC_VERSION LESS 1800) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + set (_ARCH x64) + else () + set (_ARCH Win32) + endif () + include_directories (mpfr_mpir_x86_x64_msvc2010/mpfr + mpfr_mpir_x86_x64_msvc2010/mpir/dll/${_ARCH}/Release) + # These are C libraries so it's OK to use release versions for + # debug builds. Also these work for later versions of Visual + # Studio (specifically version 12). + link_directories (mpfr_mpir_x86_x64_msvc2010/mpfr/dll/${_ARCH}/Release + mpfr_mpir_x86_x64_msvc2010/mpir/dll/${_ARCH}/Release) + set (MPFR_LIBRARIES mpfr mpir) + # Suppress the myriad of "conditional expression is constant" + # warnings + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4127") endif () - include_directories (mpfr_mpir_x86_x64_msvc2010/mpfr - mpfr_mpir_x86_x64_msvc2010/mpir/dll/${_ARCH}/Release) - # These are C libraries so it's OK to use release versions for debug - # builds. Also these will presumably work for later versions of - # Visual Studio. - link_directories (mpfr_mpir_x86_x64_msvc2010/mpfr/dll/${_ARCH}/Release - mpfr_mpir_x86_x64_msvc2010/mpir/dll/${_ARCH}/Release) - set (MPFR_LIBRARIES mpfr mpir) - # Suppress the myriad of "conditional expression is constant" warnings - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4127") else () - message (WARNING "Cannot support mpfr, switching to double") - set (GEOGRAPHICLIB_PRECISION 2) + if (APPLE) + include_directories (/usr/local/include) + link_directories (/usr/local/lib) + endif () + set (MPFR_LIBRARIES mpfr gmp) endif () - else () - set (MPFR_LIBRARIES mpfr gmp) + endif () + if (NOT MPFR_LIBRARIES) + message (WARNING "Cannot support mpfr, switching to double") + set (GEOGRAPHICLIB_PRECISION 2) + endif () +endif () + +if (APPLE AND GEOGRAPHICLIB_PRECISION EQUAL 2) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "i.86" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "amd64" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "x86") + set (CMAKE_OSX_ARCHITECTURES "i386 -arch x86_64") endif () endif () @@ -359,60 +435,6 @@ if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set (CMAKE_BUILD_TYPE Release) endif () -# Make the compiler more picky. -if (MSVC) - string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") -else () - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") - # check for C++11 support. If available, the C++11 static_assert is - # used. This flag is *not* propagated to clients that use - # GeographicLib. However, this is of no consequence. When the client - # code is being compiled (and the GeographicLib headers being - # included), a work-alike substitution is used. - include (CheckCXXCompilerFlag) - set (CXX11_FLAG "-std=c++11") - check_cxx_compiler_flag (${CXX11_FLAG} CXX11TEST1) - if (NOT CXX11TEST1) - set (CXX11_FLAG "-std=c++0x") - check_cxx_compiler_flag (${CXX11_FLAG} CXX11TEST2) - if (NOT CXX11TEST2) - unset (CXX11_FLAG) - endif () - endif () - if (CXX11_FLAG) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAG}") - endif () -endif () - -# Check whether the C++11 math function: std::expm1, std::atanh, -# etc. are available. This flag is *not* propagated to clients that use -# GeographicLib. However, this is of no consequence. When the client -# code is being compiled (and the GeographicLib headers being included), -# work-alike substitutions are used. -include (CheckCXXSourceCompiles) -set (CMAKE_REQUIRED_FLAGS "${CMAKE_CXX_FLAGS}") -check_cxx_source_compiles ( - "#include -int main() { - return int(std::hypot(3.0, 4.0) + std::expm1(0.5) + std::log1p(2.0) + - std::asinh(10.0) + std::atanh(0.8) + std::cbrt(8.0)) + - std::isfinite(4.0) + std::isnan(0.0); -}\n" CXX11_MATH) -if (CXX11_MATH) - add_definitions (-DGEOGRAPHICLIB_CXX11_MATH=1) -else () - add_definitions (-DGEOGRAPHICLIB_CXX11_MATH=0) -endif () - -if (APPLE) - if (CMAKE_SYSTEM_PROCESSOR MATCHES "i.86" OR - CMAKE_SYSTEM_PROCESSOR MATCHES "amd64" OR - CMAKE_SYSTEM_PROCESSOR MATCHES "x86") - set (CMAKE_OSX_ARCHITECTURES "i386 -arch x86_64") - endif () -endif () - # The list of tools (to be installed into, e.g., /usr/local/bin) set (TOOLS CartConvert ConicProj GeodesicProj GeoConvert GeodSolve GeoidEval Gravity MagneticField Planimeter TransverseMercatorProj) @@ -422,10 +444,6 @@ set (SCRIPTS set_property (GLOBAL PROPERTY USE_FOLDERS ON) -# Set the include directories. Look in ${PROJECT_BINARY_DIR}/include -# first because that's where Config.h will be -include_directories ("${PROJECT_BINARY_DIR}/include" include) - # The list of subdirectories to process add_subdirectory (src) add_subdirectory (include/GeographicLib) diff --git a/doc/GeographicLib.dox b/doc/GeographicLib.dox index 38609ce8..28788c40 100644 --- a/doc/GeographicLib.dox +++ b/doc/GeographicLib.dox @@ -4827,9 +4827,9 @@ of the git repository for GeographicLib. - Support quad precision. - Support mpreal - Add PolygonAreaT and PolygonAreaExact - - Add -E and -p options to Planimeter - - Add -Q option to Planimeter - - Add -p option to TransverseMercatorProj + - Add -E and -Q options to Planimeter + - Add -p option to Planimeter, ConicProj, GeodesicProj, and + TransverseMercatorProj. - Retire Windows XP common data path. - Simplify cross-platform support for C++11 mathematical functions. - In NormalGravity, use Newton's method to determine f from J2. @@ -4837,8 +4837,7 @@ of the git repository for GeographicLib. - In NormalGravity constructor allow omega = 0 (i.e., treat spherical case). - Change way area coefficients are given in GeodesicExact to improve compile times. - - STILL TO DO: add GravityModel for grs80. - - STILL TO DO: add -p prec for other utilities (where applicable) + - Add GravityModel for grs80. - Version 1.36 (released 2014-05-13) diff --git a/include/GeographicLib/Math.hpp b/include/GeographicLib/Math.hpp index e4fc3be8..e63f1d83 100644 --- a/include/GeographicLib/Math.hpp +++ b/include/GeographicLib/Math.hpp @@ -155,16 +155,15 @@ namespace GeographicLib { /** * Set the binary precision of a real number. * - * @param[in] prec the number of bits of precision. The default is 256 (or - * about 77 decimal digits). + * @param[in] digits the number of bits of precision. * * This only has an effect when GEOGRAPHICLIB_PRECISION == 5. **********************************************************************/ - static inline void set_digits(int prec = 256) { + static inline void set_digits(int digits) { #if GEOGRAPHICLIB_PRECISION != 5 - (void)prec; + (void)digits; #else - mpfr::mpreal::set_default_prec(prec >= 2 ? prec : 2); + mpfr::mpreal::set_default_prec(digits >= 2 ? digits : 2); #endif } diff --git a/include/GeographicLib/Utility.hpp b/include/GeographicLib/Utility.hpp index 19ff0f5b..20926700 100644 --- a/include/GeographicLib/Utility.hpp +++ b/include/GeographicLib/Utility.hpp @@ -538,6 +538,18 @@ namespace GeographicLib { static bool ParseLine(const std::string& line, std::string& key, std::string& val); + /** + * Set the binary precision of a real number. + * + * @param[in] digits the number of bits of precision. If digits is 0 (the + * default), then determine the precision from the environment variable + * GEOGRAPHICLIB_DIGITS. If this is undefined, use digits = 256 (i.e., + * about 77 decimal digits). + * + * This only has an effect when GEOGRAPHICLIB_PRECISION == 5. + **********************************************************************/ + static void set_digits(int digits = 0); + }; } // namespace GeographicLib diff --git a/man/ConicProj.pod b/man/ConicProj.pod index 59e25615..20f39cb4 100644 --- a/man/ConicProj.pod +++ b/man/ConicProj.pod @@ -6,7 +6,7 @@ ConicProj -- perform conic projections B ( B<-c> | B<-a> ) I I [ B<-l> I ] [ B<-k> I ] [ B<-r> ] -[ B<-e> I I ] +[ B<-e> I I ] [ B<-p> I ] [ B<--comment-delimiter> I ] [ B<--version> | B<-h> | B<--help> ] [ B<--input-file> I | B<--input-string> I ] @@ -82,6 +82,14 @@ is allowed for I. (Also, if I E 1, the flattening is set to 1/I.) By default, the WGS84 ellipsoid is used, I = 6378137 m, I = 1/298.257223563. +=item B<-p> + +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> set the comment delimiter to I (e.g., "#" or "//"). If diff --git a/man/GeodesicProj.pod b/man/GeodesicProj.pod index 7fff8baf..d271d25a 100644 --- a/man/GeodesicProj.pod +++ b/man/GeodesicProj.pod @@ -5,7 +5,7 @@ GeodesicProj -- perform projections based on geodesics =head1 SYNOPSIS B ( B<-z> | B<-c> | B<-g> ) I I [ B<-r> ] -[ B<-e> I I ] +[ B<-e> I I ] [ B<-p> I ] [ B<--comment-delimiter> I ] [ B<--version> | B<-h> | B<--help> ] [ B<--input-file> I | B<--input-string> I ] @@ -68,6 +68,14 @@ is allowed for I. (Also, if I E 1, the flattening is set to 1/I.) By default, the WGS84 ellipsoid is used, I = 6378137 m, I = 1/298.257223563. +=item B<-p> + +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> set the comment delimiter to I (e.g., "#" or "//"). If diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d5e7fec7..6ea0e363 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -45,6 +45,14 @@ else () ${PROJECT_SHARED_LIBRARIES} ${PROJECT_STATIC_LIBRARIES} PROPERTIES VERSION "${LIBVERSIONFULL}" SOVERSION "${LIBVERSION}" OUTPUT_NAME ${LIBNAME}) + if (APPLE AND GEOGRAPHICLIB_PRECISION EQUAL 5) + if (GEOGRAPHICLIB_SHARED_LIB) + target_link_libraries (${PROJECT_SHARED_LIBRARIES} ${MPFR_LIBRARIES}) + endif () + if (GEOGRAPHICLIB_STATIC_LIB) + target_link_libraries (${PROJECT_STATIC_LIBRARIES} ${MPFR_LIBRARIES}) + endif () + endif () endif () # Specify where the library is installed, adding it to the export depends diff --git a/src/Utility.cpp b/src/Utility.cpp index b8c62238..537615a8 100644 --- a/src/Utility.cpp +++ b/src/Utility.cpp @@ -7,6 +7,7 @@ * http://geographiclib.sourceforge.net/ **********************************************************************/ +#include #include namespace GeographicLib { @@ -39,4 +40,19 @@ namespace GeographicLib { return true; } + void Utility::set_digits(int digits) { +#if GEOGRAPHICLIB_PRECISION != 5 + (void)digits; +#else + if (digits <= 0) { + char* digitenv = getenv("GEOGRAPHICLIB_DIGITS"); + if (digitenv) + digits = strtol(digitenv, NULL, 0); + if (digits <= 0) + digits = 256; + } + Math::set_digits(digits); +#endif + } + } // namespace GeographicLib diff --git a/tools/CartConvert.cpp b/tools/CartConvert.cpp index 751190ec..ba591736 100644 --- a/tools/CartConvert.cpp +++ b/tools/CartConvert.cpp @@ -39,7 +39,7 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); bool localcartesian = false, reverse = false; real a = Constants::WGS84_a(), @@ -177,17 +177,17 @@ int main(int argc, char* argv[]) { lc.Reverse(x, y, z, lat, lon, h); else ec.Reverse(x, y, z, lat, lon, h); - *output << Utility::str(lat, 15) << " " - << Utility::str(lon, 15) << " " - << Utility::str(h, 12) << eol; + *output << Utility::str(lat, 15 + Math::extra_digits()) << " " + << Utility::str(lon, 15 + Math::extra_digits()) << " " + << Utility::str(h, 12 + Math::extra_digits()) << eol; } else { if (localcartesian) lc.Forward(lat, lon, h, x, y, z); else ec.Forward(lat, lon, h, x, y, z); - *output << Utility::str(x, 10) << " " - << Utility::str(y, 10) << " " - << Utility::str(z, 10) << eol; + *output << Utility::str(x, 10 + Math::extra_digits()) << " " + << Utility::str(y, 10 + Math::extra_digits()) << " " + << Utility::str(z, 10 + Math::extra_digits()) << eol; } } catch (const std::exception& e) { diff --git a/tools/ConicProj.cpp b/tools/ConicProj.cpp index 9fc0e746..583ec694 100644 --- a/tools/ConicProj.cpp +++ b/tools/ConicProj.cpp @@ -39,12 +39,13 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); bool lcc = false, albers = false, reverse = false; real lat1 = 0, lat2 = 0, lon0 = 0, k1 = 1; real a = Constants::WGS84_a(), f = Constants::WGS84_f(); + int prec = 6; std::string istring, ifile, ofile, cdelim; char lsep = ';'; @@ -106,6 +107,15 @@ int main(int argc, char* argv[]) { return 1; } m += 2; + } else if (arg == "-p") { + if (++m == argc) return usage(1, true); + try { + prec = Utility::num(std::string(argv[m])); + } + catch (const std::exception&) { + std::cerr << "Precision " << argv[m] << " is not a number\n"; + return 1; + } } else if (arg == "--input-string") { if (++m == argc) return usage(1, true); istring = argv[m]; @@ -184,6 +194,9 @@ int main(int argc, char* argv[]) { albers ? AlbersEqualArea(a, f, lat1, lat2, k1) : AlbersEqualArea(1, 0, 0, 0, 1); + // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm), + // 10^-11 sec (= 0.3 nm). + prec = std::min(10 + Math::extra_digits(), std::max(0, prec)); std::string s; int retval = 0; std::cout << std::fixed; @@ -215,19 +228,19 @@ int main(int argc, char* argv[]) { lproj.Reverse(lon0, x, y, lat, lon, gamma, k); else aproj.Reverse(lon0, x, y, lat, lon, gamma, k); - *output << Utility::str(lat, 15) << " " - << Utility::str(lon, 15) << " " - << Utility::str(gamma, 16) << " " - << Utility::str(k, 16) << eol; + *output << Utility::str(lat, prec + 5) << " " + << Utility::str(lon, prec + 5) << " " + << Utility::str(gamma, prec + 6) << " " + << Utility::str(k, prec + 6) << eol; } else { if (lcc) lproj.Forward(lon0, lat, lon, x, y, gamma, k); else aproj.Forward(lon0, lat, lon, x, y, gamma, k); - *output << Utility::str(x, 10) << " " - << Utility::str(y, 10) << " " - << Utility::str(gamma, 16) << " " - << Utility::str(k, 16) << eol; + *output << Utility::str(x, prec) << " " + << Utility::str(y, prec) << " " + << Utility::str(gamma, prec + 6) << " " + << Utility::str(k, prec + 6) << eol; } } catch (const std::exception& e) { diff --git a/tools/GeoConvert.cpp b/tools/GeoConvert.cpp index ce90cb0b..5f699168 100644 --- a/tools/GeoConvert.cpp +++ b/tools/GeoConvert.cpp @@ -40,7 +40,7 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); enum { GEOGRAPHIC, DMS, UTMUPS, MGRS, CONVERGENCE }; int outputmode = GEOGRAPHIC; int prec = 0; diff --git a/tools/GeodSolve.cpp b/tools/GeodSolve.cpp index a0a7eb3a..3fcd9644 100644 --- a/tools/GeodSolve.cpp +++ b/tools/GeodSolve.cpp @@ -75,7 +75,7 @@ real ReadDistance(const std::string& s, bool arcmode) { int main(int argc, char* argv[]) { try { using namespace GeographicLib; - Math::set_digits(); + Utility::set_digits(); bool linecalc = false, inverse = false, arcmode = false, dms = false, full = false, exact = false; real diff --git a/tools/GeodesicProj.cpp b/tools/GeodesicProj.cpp index b2e9076f..1912de55 100644 --- a/tools/GeodesicProj.cpp +++ b/tools/GeodesicProj.cpp @@ -44,12 +44,13 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); bool azimuthal = false, cassini = false, gnomonic = false, reverse = false; real lat0 = 0, lon0 = 0; real a = Constants::WGS84_a(), f = Constants::WGS84_f(); + int prec = 6; std::string istring, ifile, ofile, cdelim; char lsep = ';'; @@ -83,6 +84,15 @@ int main(int argc, char* argv[]) { return 1; } m += 2; + } else if (arg == "-p") { + if (++m == argc) return usage(1, true); + try { + prec = Utility::num(std::string(argv[m])); + } + catch (const std::exception&) { + std::cerr << "Precision " << argv[m] << " is not a number\n"; + return 1; + } } else if (arg == "--input-string") { if (++m == argc) return usage(1, true); istring = argv[m]; @@ -160,6 +170,9 @@ int main(int argc, char* argv[]) { const AzimuthalEquidistant az(geod); const Gnomonic gn(geod); + // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm), + // 10^-11 sec (= 0.3 nm). + prec = std::min(10 + Math::extra_digits(), std::max(0, prec)); std::string s; int retval = 0; std::cout << std::fixed; @@ -193,10 +206,10 @@ int main(int argc, char* argv[]) { az.Reverse(lat0, lon0, x, y, lat, lon, azi, rk); else gn.Reverse(lat0, lon0, x, y, lat, lon, azi, rk); - *output << Utility::str(lat, 15) << " " - << Utility::str(lon, 15) << " " - << Utility::str(azi, 15) << " " - << Utility::str(rk, 16) << eol; + *output << Utility::str(lat, prec + 5) << " " + << Utility::str(lon, prec + 5) << " " + << Utility::str(azi, prec + 5) << " " + << Utility::str(rk, prec + 6) << eol; } else { if (cassini) cs.Forward(lat, lon, x, y, azi, rk); @@ -204,10 +217,10 @@ int main(int argc, char* argv[]) { az.Forward(lat0, lon0, lat, lon, x, y, azi, rk); else gn.Forward(lat0, lon0, lat, lon, x, y, azi, rk); - *output << Utility::str(x, 10) << " " - << Utility::str(y, 10) << " " - << Utility::str(azi, 15) << " " - << Utility::str(rk, 16) << eol; + *output << Utility::str(x, prec) << " " + << Utility::str(y, prec) << " " + << Utility::str(azi, prec + 5) << " " + << Utility::str(rk, prec + 6) << eol; } } catch (const std::exception& e) { diff --git a/tools/GeoidEval.cpp b/tools/GeoidEval.cpp index 5b5b4146..40700ff3 100644 --- a/tools/GeoidEval.cpp +++ b/tools/GeoidEval.cpp @@ -42,7 +42,7 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); bool cacheall = false, cachearea = false, verbose = false, cubic = true, gradp = false; real caches, cachew, cachen, cachee; diff --git a/tools/Gravity.cpp b/tools/Gravity.cpp index 0b245b3d..8073168d 100644 --- a/tools/Gravity.cpp +++ b/tools/Gravity.cpp @@ -43,7 +43,7 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); bool verbose = false; std::string dir; std::string model = GravityModel::DefaultGravityName(); @@ -179,15 +179,15 @@ int main(int argc, char* argv[]) { switch (mode) { case GRAVITY: - prec = std::min(16, prec < 0 ? 5 : prec); + prec = std::min(16 + Math::extra_digits(), prec < 0 ? 5 : prec); break; case DISTURBANCE: case ANOMALY: - prec = std::min(14, prec < 0 ? 3 : prec); + prec = std::min(14 + Math::extra_digits(), prec < 0 ? 3 : prec); break; case UNDULATION: default: - prec = std::min(12, prec < 0 ? 4 : prec); + prec = std::min(12 + Math::extra_digits(), prec < 0 ? 4 : prec); break; } int retval = 0; diff --git a/tools/MagneticField.cpp b/tools/MagneticField.cpp index d5e2c93b..69753b4f 100644 --- a/tools/MagneticField.cpp +++ b/tools/MagneticField.cpp @@ -41,7 +41,7 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); bool verbose = false; std::string dir; std::string model = MagneticModel::DefaultMagneticName(); @@ -200,7 +200,7 @@ int main(int argc, char* argv[]) { tguard = std::max(real(0), tguard); hguard = std::max(real(0), hguard); - prec = std::min(10, std::max(0, prec)); + prec = std::min(10 + Math::extra_digits(), std::max(0, prec)); int retval = 0; try { const MagneticModel m(model, dir); diff --git a/tools/Planimeter.cpp b/tools/Planimeter.cpp index f42a5ee6..b6643a95 100644 --- a/tools/Planimeter.cpp +++ b/tools/Planimeter.cpp @@ -44,7 +44,7 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); real a = Constants::WGS84_a(), f = Constants::WGS84_f(); diff --git a/tools/TransverseMercatorProj.cpp b/tools/TransverseMercatorProj.cpp index 517de677..8cfc0b4c 100644 --- a/tools/TransverseMercatorProj.cpp +++ b/tools/TransverseMercatorProj.cpp @@ -41,7 +41,7 @@ int main(int argc, char* argv[]) { try { using namespace GeographicLib; typedef Math::real real; - Math::set_digits(); + Utility::set_digits(); bool exact = true, extended = false, series = false, reverse = false; real a = Constants::WGS84_a(),