ADD: new track message, Entity class and Position class

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

21
libs/geographiclib/tools/.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
.deps
.libs
Makefile.in
Makefile
TAGS
CMakeFiles
cmake_install.cmake
geographiclib-get-geoids
geographiclib-get-gravity
geographiclib-get-magnetic
*.log
CartConvert
ConicProj
GeoConvert
GeodSolve
GeodesicProj
GeoidEval
Gravity
MagneticField
Planimeter
TransverseMercatorProj

View File

@@ -0,0 +1,79 @@
# Build the tools...
# Where to find the *.usage files for the --help option.
if (RELEASE)
set (MANDIR ${PROJECT_SOURCE_DIR}/man)
else ()
set (MANDIR ${PROJECT_BINARY_DIR}/man)
endif ()
include_directories (${MANDIR})
# Only needed if target_compile_definitions is not supported
add_definitions (${PROJECT_DEFINITIONS})
# Loop over all the tools, specifying the source and library.
add_custom_target (tools ALL)
foreach (TOOL ${TOOLS})
add_executable (${TOOL} ${TOOL}.cpp)
if (NOT RELEASE)
add_dependencies (${TOOL} usage)
endif ()
add_dependencies (tools ${TOOL})
set_source_files_properties (${TOOL}.cpp PROPERTIES
OBJECT_DEPENDS ${MANDIR}/${TOOL}.usage)
target_link_libraries (${TOOL} ${PROJECT_LIBRARIES} ${HIGHPREC_LIBRARIES})
endforeach ()
if (MSVC OR CMAKE_CONFIGURATION_TYPES)
# Add _d suffix for your debug versions of the tools
set_target_properties (${TOOLS} PROPERTIES
DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}")
endif ()
if (APPLE AND RELATIVE_LIBDIR)
# Ensure that the package is relocatable
set_target_properties (${TOOLS} PROPERTIES
INSTALL_RPATH "@loader_path/${RELATIVE_LIBDIR}")
endif ()
# Specify where the tools are installed, adding them to the export targets
if (BINDIR)
install (TARGETS ${TOOLS} EXPORT targets DESTINATION ${BINDIR})
endif ()
if (MSVC AND PACKAGE_DEBUG_LIBS)
# Possibly don't EXPORT the debug versions of the tools and then this
# wouldn't be necessary. However, including the debug versions of the
# tools in the installer package is innocuous.
foreach (TOOL ${TOOLS})
install (PROGRAMS
"${PROJECT_BINARY_DIR}/bin/Debug/${TOOL}${CMAKE_DEBUG_POSTFIX}.exe"
DESTINATION bin CONFIGURATIONS Release)
endforeach ()
endif ()
# Put all the tools into a folder in the IDE
set_property (TARGET tools ${TOOLS} PROPERTY FOLDER tools)
# Create the scripts for downloading the data files on non-Windows
# systems. This needs to substitute ${GEOGRAPHICLIB_DATA} as the
# default data directory. These are installed under sbin, because it is
# expected to be run with write access to /usr/local.
if (NOT CMAKE_HOST_WIN32)
foreach (SCRIPT ${SCRIPTS})
configure_file (${SCRIPT}.sh scripts/${SCRIPT} @ONLY)
add_custom_command (OUTPUT ${SCRIPT}
COMMAND ${CMAKE_COMMAND} -E
copy scripts/${SCRIPT} ${SCRIPT} && chmod +x ${SCRIPT}
DEPENDS ${SCRIPT}.sh)
if (SBINDIR)
install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${SCRIPT}
DESTINATION ${SBINDIR})
endif ()
endforeach ()
add_custom_target (scripts ALL DEPENDS ${SCRIPTS})
endif ()

View File

@@ -0,0 +1,213 @@
/**
* \file CartConvert.cpp
* \brief Command line utility for geodetic to cartesian coordinate conversions
*
* Copyright (c) Charles Karney (2009-2017) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="CartConvert.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/Geocentric.hpp>
#include <GeographicLib/LocalCartesian.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions and potentially
// uninitialized local variables
# pragma warning (disable: 4127 4701)
#endif
#include "CartConvert.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
bool localcartesian = false, reverse = false, longfirst = false;
real
a = Constants::WGS84_a(),
f = Constants::WGS84_f();
int prec = 6;
real lat0 = 0, lon0 = 0, h0 = 0;
std::string istring, ifile, ofile, cdelim;
char lsep = ';';
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-r")
reverse = true;
else if (arg == "-l") {
localcartesian = true;
if (m + 3 >= argc) return usage(1, true);
try {
DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
lat0, lon0, longfirst);
h0 = Utility::val<real>(std::string(argv[m + 3]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -l: " << e.what() << "\n";
return 1;
}
m += 3;
} else if (arg == "-e") {
if (m + 2 >= argc) return usage(1, true);
try {
a = Utility::val<real>(std::string(argv[m + 1]));
f = Utility::fract<real>(std::string(argv[m + 2]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
return 1;
}
m += 2;
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(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];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else
return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
const Geocentric ec(a, f);
const LocalCartesian lc(lat0, lon0, h0, ec);
// 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, eol, stra, strb, strc, strd;
std::istringstream str;
int retval = 0;
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
str.clear(); str.str(s);
// initial values to suppress warnings
real lat, lon, h, x = 0, y = 0, z = 0;
if (!(str >> stra >> strb >> strc))
throw GeographicErr("Incomplete input: " + s);
if (reverse) {
x = Utility::val<real>(stra);
y = Utility::val<real>(strb);
z = Utility::val<real>(strc);
} else {
DMS::DecodeLatLon(stra, strb, lat, lon, longfirst);
h = Utility::val<real>(strc);
}
if (str >> strd)
throw GeographicErr("Extraneous input: " + strd);
if (reverse) {
if (localcartesian)
lc.Reverse(x, y, z, lat, lon, h);
else
ec.Reverse(x, y, z, lat, lon, h);
*output << Utility::str(longfirst ? lon : lat, prec + 5) << " "
<< Utility::str(longfirst ? lat : lon, prec + 5) << " "
<< Utility::str(h, prec) << 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, prec) << " "
<< Utility::str(y, prec) << " "
<< Utility::str(z, prec) << eol;
}
}
catch (const std::exception& e) {
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,249 @@
/**
* \file ConicProj.cpp
* \brief Command line utility for conical projections
*
* Copyright (c) Charles Karney (2009-2017) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="ConicProj.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/LambertConformalConic.hpp>
#include <GeographicLib/AlbersEqualArea.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions and potentially
// uninitialized local variables
# pragma warning (disable: 4127 4701)
#endif
#include "ConicProj.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
bool lcc = false, albers = false, reverse = false, longfirst = 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 = ';';
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-r")
reverse = true;
else if (arg == "-c" || arg == "-a") {
lcc = arg == "-c";
albers = arg == "-a";
if (m + 2 >= argc) return usage(1, true);
try {
for (int i = 0; i < 2; ++i) {
DMS::flag ind;
(i ? lat2 : lat1) = DMS::Decode(std::string(argv[++m]), ind);
if (ind == DMS::LONGITUDE)
throw GeographicErr("Bad hemisphere");
}
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-l") {
if (++m == argc) return usage(1, true);
try {
DMS::flag ind;
lon0 = DMS::Decode(std::string(argv[m]), ind);
if (ind == DMS::LATITUDE)
throw GeographicErr("Bad hemisphere");
lon0 = Math::AngNormalize(lon0);
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-k") {
if (++m == argc) return usage(1, true);
try {
k1 = Utility::val<real>(std::string(argv[m]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-e") {
if (m + 2 >= argc) return usage(1, true);
try {
a = Utility::val<real>(std::string(argv[m + 1]));
f = Utility::fract<real>(std::string(argv[m + 2]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
return 1;
}
m += 2;
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(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];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else
return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
if (!(lcc || albers)) {
std::cerr << "Must specify \"-c lat1 lat2\" or "
<< "\"-a lat1 lat2\"\n";
return 1;
}
const LambertConformalConic lproj =
lcc ? LambertConformalConic(a, f, lat1, lat2, k1)
: LambertConformalConic(1, 0, 0, 0, 1);
const AlbersEqualArea aproj =
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, eol, stra, strb, strc;
std::istringstream str;
int retval = 0;
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
str.clear(); str.str(s);
real lat, lon, x, y, gamma, k;
if (!(str >> stra >> strb))
throw GeographicErr("Incomplete input: " + s);
if (reverse) {
x = Utility::val<real>(stra);
y = Utility::val<real>(strb);
} else
DMS::DecodeLatLon(stra, strb, lat, lon, longfirst);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
if (reverse) {
if (lcc)
lproj.Reverse(lon0, x, y, lat, lon, gamma, k);
else
aproj.Reverse(lon0, x, y, lat, lon, gamma, k);
*output << Utility::str(longfirst ? lon : lat, prec + 5) << " "
<< Utility::str(longfirst ? lat : 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, prec) << " "
<< Utility::str(y, prec) << " "
<< Utility::str(gamma, prec + 6) << " "
<< Utility::str(k, prec + 6) << eol;
}
}
catch (const std::exception& e) {
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,245 @@
/**
* \file GeoConvert.cpp
* \brief Command line utility for geographic coordinate conversions
*
* Copyright (c) Charles Karney (2008-2017) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="GeoConvert.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/GeoCoords.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#include <GeographicLib/MGRS.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (disable: 4127)
#endif
#include "GeoConvert.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
enum { GEOGRAPHIC, DMS, UTMUPS, MGRS, CONVERGENCE };
int outputmode = GEOGRAPHIC;
int prec = 0;
int zone = UTMUPS::MATCH;
bool centerp = true, longfirst = false;
std::string istring, ifile, ofile, cdelim;
char lsep = ';', dmssep = char(0);
bool sethemisphere = false, northp = false, abbrev = true, latch = false;
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-g")
outputmode = GEOGRAPHIC;
else if (arg == "-d") {
outputmode = DMS;
dmssep = '\0';
} else if (arg == "-:") {
outputmode = DMS;
dmssep = ':';
} else if (arg == "-u")
outputmode = UTMUPS;
else if (arg == "-m")
outputmode = MGRS;
else if (arg == "-c")
outputmode = CONVERGENCE;
else if (arg == "-n")
centerp = false;
else if (arg == "-z") {
if (++m == argc) return usage(1, true);
std::string zonestr(argv[m]);
try {
UTMUPS::DecodeZone(zonestr, zone, northp);
sethemisphere = true;
}
catch (const std::exception&) {
std::istringstream str(zonestr);
char c;
if (!(str >> zone) || (str >> c)) {
std::cerr << "Zone " << zonestr
<< " is not a number or zone+hemisphere\n";
return 1;
}
if (!(zone >= UTMUPS::MINZONE && zone <= UTMUPS::MAXZONE)) {
std::cerr << "Zone " << zone << " not in [0, 60]\n";
return 1;
}
sethemisphere = false;
}
latch = false;
} else if (arg == "-s") {
zone = UTMUPS::STANDARD;
sethemisphere = false;
latch = false;
} else if (arg == "-S") {
zone = UTMUPS::STANDARD;
sethemisphere = false;
latch = true;
} else if (arg == "-t") {
zone = UTMUPS::UTM;
sethemisphere = false;
latch = false;
} else if (arg == "-T") {
zone = UTMUPS::UTM;
sethemisphere = false;
latch = true;
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(std::string(argv[m]));
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-l")
abbrev = false;
else if (arg == "-a")
abbrev = true;
else if (arg == "--input-string") {
if (++m == argc) return usage(1, true);
istring = argv[m];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
MGRS::Check();
return 0;
} else
return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
GeoCoords p;
std::string s, eol;
std::string os;
int retval = 0;
while (std::getline(*input, s)) {
eol = "\n";
try {
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
p.Reset(s, centerp, longfirst);
p.SetAltZone(zone);
switch (outputmode) {
case GEOGRAPHIC:
os = p.GeoRepresentation(prec, longfirst);
break;
case DMS:
os = p.DMSRepresentation(prec, longfirst, dmssep);
break;
case UTMUPS:
os = (sethemisphere
? p.AltUTMUPSRepresentation(northp, prec, abbrev)
: p.AltUTMUPSRepresentation(prec, abbrev));
break;
case MGRS:
os = p.AltMGRSRepresentation(prec);
break;
case CONVERGENCE:
{
real
gamma = p.AltConvergence(),
k = p.AltScale();
int prec1 = std::max(-5, std::min(Math::extra_digits() + 8, prec));
os = Utility::str(gamma, prec1 + 5) + " "
+ Utility::str(k, prec1 + 7);
}
}
if (latch &&
zone < UTMUPS::MINZONE && p.AltZone() >= UTMUPS::MINZONE) {
zone = p.AltZone();
northp = p.Northp();
sethemisphere = true;
latch = false;
}
}
catch (const std::exception& e) {
// Write error message to cout so output lines match input lines
os = std::string("ERROR: ") + e.what();
retval = 1;
}
*output << os << eol;
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,406 @@
/**
* \file GeodSolve.cpp
* \brief Command line utility for geodesic calculations
*
* Copyright (c) Charles Karney (2009-2019) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="GeodSolve.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/GeodesicLine.hpp>
#include <GeographicLib/GeodesicExact.hpp>
#include <GeographicLib/GeodesicLineExact.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions and potentially
// uninitialized local variables
# pragma warning (disable: 4127 4701)
#endif
#include "GeodSolve.usage"
typedef GeographicLib::Math::real real;
std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep,
bool longfirst) {
using namespace GeographicLib;
std::string
latstr = dms ? DMS::Encode(lat, prec + 5, DMS::LATITUDE, dmssep) :
DMS::Encode(lat, prec + 5, DMS::NUMBER),
lonstr = dms ? DMS::Encode(lon, prec + 5, DMS::LONGITUDE, dmssep) :
DMS::Encode(lon, prec + 5, DMS::NUMBER);
return
(longfirst ? lonstr : latstr) + " " + (longfirst ? latstr : lonstr);
}
std::string AzimuthString(real azi, int prec, bool dms, char dmssep) {
using namespace GeographicLib;
return dms ? DMS::Encode(azi, prec + 5, DMS::AZIMUTH, dmssep) :
DMS::Encode(azi, prec + 5, DMS::NUMBER);
}
std::string DistanceStrings(real s12, real a12,
bool full, bool arcmode, int prec, bool dms) {
using namespace GeographicLib;
std::string s;
if (full || !arcmode)
s += Utility::str(s12, prec);
if (full)
s += " ";
if (full || arcmode)
s += DMS::Encode(a12, prec + 5, dms ? DMS::NONE : DMS::NUMBER);
return s;
}
real ReadDistance(const std::string& s, bool arcmode, bool fraction = false) {
using namespace GeographicLib;
return fraction ? Utility::fract<real>(s) :
(arcmode ? DMS::DecodeAngle(s) : Utility::val<real>(s));
}
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
enum { NONE = 0, LINE, DIRECT, INVERSE };
Utility::set_digits();
bool inverse = false, arcmode = false,
dms = false, full = false, exact = false, unroll = false,
longfirst = false, azi2back = false, fraction = false,
arcmodeline = false;
real
a = Constants::WGS84_a(),
f = Constants::WGS84_f();
real lat1, lon1, azi1, lat2, lon2, azi2, s12, m12, a12, M12, M21, S12,
mult = 1;
int linecalc = NONE, prec = 3;
std::string istring, ifile, ofile, cdelim;
char lsep = ';', dmssep = char(0);
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-i") {
inverse = true;
linecalc = NONE;
} else if (arg == "-a")
arcmode = !arcmode;
else if (arg == "-F")
fraction = true;
else if (arg == "-L" || arg == "-l") { // -l is DEPRECATED
inverse = false;
linecalc = LINE;
if (m + 3 >= argc) return usage(1, true);
try {
DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
lat1, lon1, longfirst);
azi1 = DMS::DecodeAzimuth(std::string(argv[m + 3]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -L: " << e.what() << "\n";
return 1;
}
m += 3;
} else if (arg == "-D") {
inverse = false;
linecalc = DIRECT;
if (m + 4 >= argc) return usage(1, true);
try {
DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
lat1, lon1, longfirst);
azi1 = DMS::DecodeAzimuth(std::string(argv[m + 3]));
s12 = ReadDistance(std::string(argv[m + 4]), arcmode);
arcmodeline = arcmode;
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -D: " << e.what() << "\n";
return 1;
}
m += 4;
} else if (arg == "-I") {
inverse = false;
linecalc = INVERSE;
if (m + 4 >= argc) return usage(1, true);
try {
DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
lat1, lon1, longfirst);
DMS::DecodeLatLon(std::string(argv[m + 3]), std::string(argv[m + 4]),
lat2, lon2, longfirst);
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -I: " << e.what() << "\n";
return 1;
}
m += 4;
} else if (arg == "-e") {
if (m + 2 >= argc) return usage(1, true);
try {
a = Utility::val<real>(std::string(argv[m + 1]));
f = Utility::fract<real>(std::string(argv[m + 2]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
return 1;
}
m += 2;
} else if (arg == "-u")
unroll = true;
else if (arg == "-d") {
dms = true;
dmssep = '\0';
} else if (arg == "-:") {
dms = true;
dmssep = ':';
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-b")
azi2back = true;
else if (arg == "-f")
full = true;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(std::string(argv[m]));
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-E")
exact = true;
else if (arg == "--input-string") {
if (++m == argc) return usage(1, true);
istring = argv[m];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else
return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
// GeodesicExact mask values are the same as Geodesic
unsigned outmask = Geodesic::LATITUDE | Geodesic::LONGITUDE |
Geodesic::AZIMUTH; // basic output quantities
outmask |= inverse ? Geodesic::DISTANCE : // distance-related flags
(arcmode ? Geodesic::NONE : Geodesic::DISTANCE_IN);
// longitude unrolling
outmask |= unroll ? Geodesic::LONG_UNROLL : Geodesic::NONE;
// full output -- don't use Geodesic::ALL since this includes DISTANCE_IN
outmask |= full ? (Geodesic::DISTANCE | Geodesic::REDUCEDLENGTH |
Geodesic::GEODESICSCALE | Geodesic::AREA) :
Geodesic::NONE;
const Geodesic geods(a, f);
const GeodesicExact geode(a, f);
GeodesicLine ls;
GeodesicLineExact le;
if (linecalc) {
if (linecalc == LINE) fraction = false;
if (exact) {
le = linecalc == DIRECT ?
geode.GenDirectLine(lat1, lon1, azi1, arcmodeline, s12, outmask) :
linecalc == INVERSE ?
geode.InverseLine(lat1, lon1, lat2, lon2, outmask) :
// linecalc == LINE
geode.Line(lat1, lon1, azi1, outmask);
mult = fraction ? le.GenDistance(arcmode) : 1;
if (linecalc == INVERSE) azi1 = le.Azimuth();
} else {
ls = linecalc == DIRECT ?
geods.GenDirectLine(lat1, lon1, azi1, arcmodeline, s12, outmask) :
linecalc == INVERSE ?
geods.InverseLine(lat1, lon1, lat2, lon2, outmask) :
// linecalc == LINE
geods.Line(lat1, lon1, azi1, outmask);
mult = fraction ? ls.GenDistance(arcmode) : 1;
if (linecalc == INVERSE) azi1 = ls.Azimuth();
}
}
// 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, eol, slat1, slon1, slat2, slon2, sazi1, ss12, strc;
std::istringstream str;
int retval = 0;
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
str.clear(); str.str(s);
if (inverse) {
if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
throw GeographicErr("Incomplete input: " + s);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
DMS::DecodeLatLon(slat1, slon1, lat1, lon1, longfirst);
DMS::DecodeLatLon(slat2, slon2, lat2, lon2, longfirst);
a12 = exact ?
geode.GenInverse(lat1, lon1, lat2, lon2, outmask,
s12, azi1, azi2, m12, M12, M21, S12) :
geods.GenInverse(lat1, lon1, lat2, lon2, outmask,
s12, azi1, azi2, m12, M12, M21, S12);
if (full) {
if (unroll) {
real e;
lon2 = lon1 + Math::AngDiff(lon1, lon2, e);
lon2 += e;
} else {
lon1 = Math::AngNormalize(lon1);
lon2 = Math::AngNormalize(lon2);
}
*output << LatLonString(lat1, lon1, prec, dms, dmssep, longfirst)
<< " ";
}
*output << AzimuthString(azi1, prec, dms, dmssep) << " ";
if (full)
*output << LatLonString(lat2, lon2, prec, dms, dmssep, longfirst)
<< " ";
if (azi2back) {
using std::copysign;
// map +/-0 -> -/+180; +/-180 -> -/+0
// this depends on abs(azi2) <= 180
azi2 = copysign(azi2 + copysign(real(Math::hd), -azi2), -azi2);
}
*output << AzimuthString(azi2, prec, dms, dmssep) << " "
<< DistanceStrings(s12, a12, full, arcmode, prec, dms);
if (full)
*output << " " << Utility::str(m12, prec)
<< " " << Utility::str(M12, prec+7)
<< " " << Utility::str(M21, prec+7)
<< " " << Utility::str(S12, std::max(prec-7, 0));
*output << eol;
} else {
if (linecalc) {
if (!(str >> ss12))
throw GeographicErr("Incomplete input: " + s);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
// In fraction mode input is read as a distance
s12 = ReadDistance(ss12, !fraction && arcmode, fraction) * mult;
a12 = exact ?
le.GenPosition(arcmode, s12, outmask,
lat2, lon2, azi2, s12, m12, M12, M21, S12) :
ls.GenPosition(arcmode, s12, outmask,
lat2, lon2, azi2, s12, m12, M12, M21, S12);
} else {
if (!(str >> slat1 >> slon1 >> sazi1 >> ss12))
throw GeographicErr("Incomplete input: " + s);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
DMS::DecodeLatLon(slat1, slon1, lat1, lon1, longfirst);
azi1 = DMS::DecodeAzimuth(sazi1);
s12 = ReadDistance(ss12, arcmode);
a12 = exact ?
geode.GenDirect(lat1, lon1, azi1, arcmode, s12, outmask,
lat2, lon2, azi2, s12, m12, M12, M21, S12) :
geods.GenDirect(lat1, lon1, azi1, arcmode, s12, outmask,
lat2, lon2, azi2, s12, m12, M12, M21, S12);
}
if (full)
*output
<< LatLonString(lat1, unroll ? lon1 : Math::AngNormalize(lon1),
prec, dms, dmssep, longfirst)
<< " " << AzimuthString(azi1, prec, dms, dmssep) << " ";
if (azi2back) {
using std::copysign;
// map +/-0 -> -/+180; +/-180 -> -/+0
// this depends on abs(azi2) <= 180
azi2 = copysign(azi2 + copysign(real(Math::hd), -azi2), -azi2);
}
*output << LatLonString(lat2, lon2, prec, dms, dmssep, longfirst)
<< " " << AzimuthString(azi2, prec, dms, dmssep);
if (full)
*output << " "
<< DistanceStrings(s12, a12, full, arcmode, prec, dms)
<< " " << Utility::str(m12, prec)
<< " " << Utility::str(M12, prec+7)
<< " " << Utility::str(M21, prec+7)
<< " " << Utility::str(S12, std::max(prec-7, 0));
*output << eol;
}
}
catch (const std::exception& e) {
// Write error message cout so output lines match input lines
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,231 @@
/**
* \file GeodesicProj.cpp
* \brief Command line utility for geodesic projections
*
* Copyright (c) Charles Karney (2009-2017) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="GeodesicProj.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/AzimuthalEquidistant.hpp>
#include <GeographicLib/CassiniSoldner.hpp>
#include <GeographicLib/Gnomonic.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions and potentially
// uninitialized local variables
# pragma warning (disable: 4127 4701)
#endif
#include "GeodesicProj.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
bool azimuthal = false, cassini = false, gnomonic = false, reverse = false,
longfirst = 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 = ';';
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-r")
reverse = true;
else if (arg == "-c" || arg == "-z" || arg == "-g") {
cassini = azimuthal = gnomonic = false;
cassini = arg == "-c";
azimuthal = arg == "-z";
gnomonic = arg == "-g";
if (m + 2 >= argc) return usage(1, true);
try {
DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
lat0, lon0, longfirst);
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of " << arg << ": "
<< e.what() << "\n";
return 1;
}
m += 2;
} else if (arg == "-e") {
if (m + 2 >= argc) return usage(1, true);
try {
a = Utility::val<real>(std::string(argv[m + 1]));
f = Utility::fract<real>(std::string(argv[m + 2]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
return 1;
}
m += 2;
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(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];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else
return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
if (!(azimuthal || cassini || gnomonic)) {
std::cerr << "Must specify \"-z lat0 lon0\" or "
<< "\"-c lat0 lon0\" or \"-g lat0 lon0\"\n";
return 1;
}
const Geodesic geod(a, f);
const CassiniSoldner cs = cassini ?
CassiniSoldner(lat0, lon0, geod) : CassiniSoldner(geod);
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, eol, stra, strb, strc;
std::istringstream str;
int retval = 0;
std::cout << std::fixed;
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
str.clear(); str.str(s);
real lat, lon, x, y, azi, rk;
if (!(str >> stra >> strb))
throw GeographicErr("Incomplete input: " + s);
if (reverse) {
x = Utility::val<real>(stra);
y = Utility::val<real>(strb);
} else
DMS::DecodeLatLon(stra, strb, lat, lon, longfirst);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
if (reverse) {
if (cassini)
cs.Reverse(x, y, lat, lon, azi, rk);
else if (azimuthal)
az.Reverse(lat0, lon0, x, y, lat, lon, azi, rk);
else
gn.Reverse(lat0, lon0, x, y, lat, lon, azi, rk);
*output << Utility::str(longfirst ? lon : lat, prec + 5) << " "
<< Utility::str(longfirst ? lat : 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);
else if (azimuthal)
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, prec) << " "
<< Utility::str(y, prec) << " "
<< Utility::str(azi, prec + 5) << " "
<< Utility::str(rk, prec + 6) << eol;
}
}
catch (const std::exception& e) {
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,279 @@
/**
* \file GeoidEval.cpp
* \brief Command line utility for evaluating geoid heights
*
* Copyright (c) Charles Karney (2009-2017) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="GeoidEval.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/Geoid.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#include <GeographicLib/GeoCoords.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions and potentially
// uninitialized local variables
# pragma warning (disable: 4127 4701)
#endif
#include "GeoidEval.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
bool cacheall = false, cachearea = false, verbose = false, cubic = true;
real caches, cachew, cachen, cachee;
std::string dir;
std::string geoid = Geoid::DefaultGeoidName();
Geoid::convertflag heightmult = Geoid::NONE;
std::string istring, ifile, ofile, cdelim;
char lsep = ';';
bool northp = false, longfirst = false;
int zonenum = UTMUPS::INVALID;
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-a") {
cacheall = true;
cachearea = false;
}
else if (arg == "-c") {
if (m + 4 >= argc) return usage(1, true);
cacheall = false;
cachearea = true;
try {
DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
caches, cachew, longfirst);
DMS::DecodeLatLon(std::string(argv[m + 3]), std::string(argv[m + 4]),
cachen, cachee, longfirst);
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of -c: " << e.what() << "\n";
return 1;
}
m += 4;
} else if (arg == "--msltohae")
heightmult = Geoid::GEOIDTOELLIPSOID;
else if (arg == "--haetomsl")
heightmult = Geoid::ELLIPSOIDTOGEOID;
else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-z") {
if (++m == argc) return usage(1, true);
std::string zone = argv[m];
try {
UTMUPS::DecodeZone(zone, zonenum, northp);
}
catch (const std::exception& e) {
std::cerr << "Error decoding zone: " << e.what() << "\n";
return 1;
}
if (!(zonenum >= UTMUPS::MINZONE && zonenum <= UTMUPS::MAXZONE)) {
std::cerr << "Illegal zone " << zone << "\n";
return 1;
}
} else if (arg == "-n") {
if (++m == argc) return usage(1, true);
geoid = argv[m];
} else if (arg == "-d") {
if (++m == argc) return usage(1, true);
dir = argv[m];
} else if (arg == "-l")
cubic = false;
else if (arg == "-v")
verbose = true;
else if (arg == "--input-string") {
if (++m == argc) return usage(1, true);
istring = argv[m];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else {
int retval = usage(!(arg == "-h" || arg == "--help"), arg != "--help");
if (arg == "-h")
std::cout
<< "\nDefault geoid path = \"" << Geoid::DefaultGeoidPath()
<< "\"\nDefault geoid name = \"" << Geoid::DefaultGeoidName()
<< "\"\n";
return retval;
}
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
int retval = 0;
try {
const Geoid g(geoid, dir, cubic);
try {
if (cacheall)
g.CacheAll();
else if (cachearea)
g.CacheArea(caches, cachew, cachen, cachee);
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << "\nProceeding without a cache\n";
}
if (verbose) {
std::cerr << "Geoid file: " << g.GeoidFile() << "\n"
<< "Description: " << g.Description() << "\n"
<< "Interpolation: " << g.Interpolation() << "\n"
<< "Date & Time: " << g.DateTime() << "\n"
<< "Offset (m): " << g.Offset() << "\n"
<< "Scale (m): " << g.Scale() << "\n"
<< "Max error (m): " << g.MaxError() << "\n"
<< "RMS error (m): " << g.RMSError() << "\n";
if (g.Cache())
std::cerr
<< "Caching:"
<< "\n SW Corner: " << g.CacheSouth() << " " << g.CacheWest()
<< "\n NE Corner: " << g.CacheNorth() << " " << g.CacheEast()
<< "\n";
}
GeoCoords p;
std::string s, eol, suff;
const char* spaces = " \t\n\v\f\r,"; // Include comma as space
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
std::string::size_type m1 =
m > 0 ? s.find_last_not_of(spaces, m - 1) : std::string::npos;
s = s.substr(0, m1 != std::string::npos ? m1 + 1 : m);
}
}
real height = 0;
if (zonenum != UTMUPS::INVALID) {
// Expect "easting northing" if heightmult == 0, or
// "easting northing height" if heightmult != 0.
std::string::size_type pa = 0, pb = 0;
real easting = 0, northing = 0;
for (int i = 0; i < (heightmult ? 3 : 2); ++i) {
if (pb == std::string::npos)
throw GeographicErr("Incomplete input: " + s);
// Start of i'th token
pa = s.find_first_not_of(spaces, pb);
if (pa == std::string::npos)
throw GeographicErr("Incomplete input: " + s);
// End of i'th token
pb = s.find_first_of(spaces, pa);
(i == 2 ? height : (i == 0 ? easting : northing)) =
Utility::val<real>(s.substr(pa, (pb == std::string::npos ?
pb : pb - pa)));
}
p.Reset(zonenum, northp, easting, northing);
if (heightmult) {
suff = pb == std::string::npos ? "" : s.substr(pb);
s = s.substr(0, pa);
}
} else {
if (heightmult) {
// Treat last token as height
// pb = last char of last token
// pa = last char preceding white space
// px = last char of 2nd last token
std::string::size_type pb = s.find_last_not_of(spaces);
std::string::size_type pa = s.find_last_of(spaces, pb);
if (pa == std::string::npos || pb == std::string::npos)
throw GeographicErr("Incomplete input: " + s);
height = Utility::val<real>(s.substr(pa + 1, pb - pa));
s = s.substr(0, pa + 1);
}
p.Reset(s, true, longfirst);
}
if (heightmult) {
real h = g(p.Latitude(), p.Longitude());
*output << s
<< Utility::str(height + real(heightmult) * h, 4)
<< suff << eol;
} else {
real h = g(p.Latitude(), p.Longitude());
*output << Utility::str(h, 4) << eol;
}
}
catch (const std::exception& e) {
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
}
catch (const std::exception& e) {
std::cerr << "Error reading " << geoid << ": " << e.what() << "\n";
retval = 1;
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,335 @@
/**
* \file Gravity.cpp
* \brief Command line utility for evaluating gravity fields
*
* Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="Gravity.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/GravityModel.hpp>
#include <GeographicLib/GravityCircle.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional and enum-float expressions
// and potentially uninitialized local variables
# pragma warning (disable: 4127 5055 4701)
#endif
#include "Gravity.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
bool verbose = false, longfirst = false;
std::string dir;
std::string model = GravityModel::DefaultGravityName();
std::string istring, ifile, ofile, cdelim;
char lsep = ';';
real lat = 0, h = 0;
bool circle = false;
int prec = -1, Nmax = -1, Mmax = -1;
enum {
GRAVITY = 0,
DISTURBANCE = 1,
ANOMALY = 2,
UNDULATION = 3,
};
unsigned mode = GRAVITY;
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-n") {
if (++m == argc) return usage(1, true);
model = argv[m];
} else if (arg == "-d") {
if (++m == argc) return usage(1, true);
dir = argv[m];
} else if (arg == "-N") {
if (++m == argc) return usage(1, true);
try {
Nmax = Utility::val<int>(std::string(argv[m]));
if (Nmax < 0) {
std::cerr << "Maximum degree " << argv[m] << " is negative\n";
return 1;
}
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-M") {
if (++m == argc) return usage(1, true);
try {
Mmax = Utility::val<int>(std::string(argv[m]));
if (Mmax < 0) {
std::cerr << "Maximum order " << argv[m] << " is negative\n";
return 1;
}
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-G")
mode = GRAVITY;
else if (arg == "-D")
mode = DISTURBANCE;
else if (arg == "-A")
mode = ANOMALY;
else if (arg == "-H")
mode = UNDULATION;
else if (arg == "-c") {
if (m + 2 >= argc) return usage(1, true);
try {
using std::fabs;
DMS::flag ind;
lat = DMS::Decode(std::string(argv[++m]), ind);
if (ind == DMS::LONGITUDE)
throw GeographicErr("Bad hemisphere letter on latitude");
if (!(fabs(lat) <= Math::qd))
throw GeographicErr("Latitude not in [-" + std::to_string(Math::qd)
+ "d, " + std::to_string(Math::qd) + "d]");
h = Utility::val<real>(std::string(argv[++m]));
circle = true;
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(std::string(argv[m]));
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-v")
verbose = true;
else if (arg == "--input-string") {
if (++m == argc) return usage(1, true);
istring = argv[m];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else {
int retval = usage(!(arg == "-h" || arg == "--help"), arg != "--help");
if (arg == "-h")
std::cout<< "\nDefault gravity path = \""
<< GravityModel::DefaultGravityPath()
<< "\"\nDefault gravity name = \""
<< GravityModel::DefaultGravityName()
<< "\"\n";
return retval;
}
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
switch (mode) {
case GRAVITY:
prec = std::min(16 + Math::extra_digits(), prec < 0 ? 5 : prec);
break;
case DISTURBANCE:
case ANOMALY:
prec = std::min(14 + Math::extra_digits(), prec < 0 ? 3 : prec);
break;
case UNDULATION:
default:
prec = std::min(12 + Math::extra_digits(), prec < 0 ? 4 : prec);
break;
}
int retval = 0;
try {
using std::isfinite;
const GravityModel g(model, dir, Nmax, Mmax);
if (circle) {
if (!isfinite(h))
throw GeographicErr("Bad height");
else if (mode == UNDULATION && h != 0)
throw GeographicErr("Height should be zero for geoid undulations");
}
if (verbose) {
std::cerr << "Gravity file: " << g.GravityFile() << "\n"
<< "Name: " << g.GravityModelName() << "\n"
<< "Description: " << g.Description() << "\n"
<< "Date & Time: " << g.DateTime() << "\n";
}
unsigned mask = (mode == GRAVITY ? GravityModel::GRAVITY :
(mode == DISTURBANCE ? GravityModel::DISTURBANCE :
(mode == ANOMALY ? GravityModel::SPHERICAL_ANOMALY :
GravityModel::GEOID_HEIGHT))); // mode == UNDULATION
const GravityCircle c(circle ? g.Circle(lat, h, mask) : GravityCircle());
std::string s, eol, stra, strb;
std::istringstream str;
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
str.clear(); str.str(s);
real lon;
if (circle) {
if (!(str >> strb))
throw GeographicErr("Incomplete input: " + s);
DMS::flag ind;
lon = DMS::Decode(strb, ind);
if (ind == DMS::LATITUDE)
throw GeographicErr("Bad hemisphere letter on " + strb);
} else {
if (!(str >> stra >> strb))
throw GeographicErr("Incomplete input: " + s);
DMS::DecodeLatLon(stra, strb, lat, lon, longfirst);
h = 0;
if (!(str >> h)) // h is optional
str.clear();
if (mode == UNDULATION && h != 0)
throw GeographicErr("Height must be zero for geoid heights");
}
if (str >> stra)
throw GeographicErr("Extra junk in input: " + s);
switch (mode) {
case GRAVITY:
{
real gx, gy, gz;
if (circle) {
c.Gravity(lon, gx, gy, gz);
} else {
g.Gravity(lat, lon, h, gx, gy, gz);
}
*output << Utility::str(gx, prec) << " "
<< Utility::str(gy, prec) << " "
<< Utility::str(gz, prec) << eol;
}
break;
case DISTURBANCE:
{
real deltax, deltay, deltaz;
if (circle) {
c.Disturbance(lon, deltax, deltay, deltaz);
} else {
g.Disturbance(lat, lon, h, deltax, deltay, deltaz);
}
// Convert to mGals
*output << Utility::str(deltax * 100000, prec) << " "
<< Utility::str(deltay * 100000, prec) << " "
<< Utility::str(deltaz * 100000, prec)
<< eol;
}
break;
case ANOMALY:
{
real Dg01, xi, eta;
if (circle)
c.SphericalAnomaly(lon, Dg01, xi, eta);
else
g.SphericalAnomaly(lat, lon, h, Dg01, xi, eta);
Dg01 *= 100000; // Convert to mGals
xi *= Math::ds; // Convert to arcsecs
eta *= Math::ds;
*output << Utility::str(Dg01, prec) << " "
<< Utility::str(xi, prec) << " "
<< Utility::str(eta, prec) << eol;
}
break;
case UNDULATION:
default:
{
real N = circle ? c.GeoidHeight(lon) : g.GeoidHeight(lat, lon);
*output << Utility::str(N, prec) << eol;
}
break;
}
}
catch (const std::exception& e) {
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
}
catch (const std::exception& e) {
std::cerr << "Error reading " << model << ": " << e.what() << "\n";
retval = 1;
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,367 @@
/**
* \file MagneticField.cpp
* \brief Command line utility for evaluating magnetic fields
*
* Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="MagneticField.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/MagneticModel.hpp>
#include <GeographicLib/MagneticCircle.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional and enum-float expressions
# pragma warning (disable: 4127 5055)
#endif
#include "MagneticField.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
bool verbose = false, longfirst = false;
std::string dir;
std::string model = MagneticModel::DefaultMagneticName();
std::string istring, ifile, ofile, cdelim;
char lsep = ';';
real time = 0, lat = 0, h = 0;
bool timeset = false, circle = false, rate = false;
real hguard = 500000, tguard = 50;
int prec = 1, Nmax = -1, Mmax = -1;
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-n") {
if (++m == argc) return usage(1, true);
model = argv[m];
} else if (arg == "-d") {
if (++m == argc) return usage(1, true);
dir = argv[m];
} else if (arg == "-N") {
if (++m == argc) return usage(1, true);
try {
Nmax = Utility::val<int>(std::string(argv[m]));
if (Nmax < 0) {
std::cerr << "Maximum degree " << argv[m] << " is negative\n";
return 1;
}
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-M") {
if (++m == argc) return usage(1, true);
try {
Mmax = Utility::val<int>(std::string(argv[m]));
if (Mmax < 0) {
std::cerr << "Maximum order " << argv[m] << " is negative\n";
return 1;
}
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-t") {
if (++m == argc) return usage(1, true);
try {
time = Utility::fractionalyear<real>(std::string(argv[m]));
timeset = true;
circle = false;
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-c") {
if (m + 3 >= argc) return usage(1, true);
try {
using std::fabs;
time = Utility::fractionalyear<real>(std::string(argv[++m]));
DMS::flag ind;
lat = DMS::Decode(std::string(argv[++m]), ind);
if (ind == DMS::LONGITUDE)
throw GeographicErr("Bad hemisphere letter on latitude");
if (!(fabs(lat) <= Math::qd))
throw GeographicErr("Latitude not in [-" + std::to_string(Math::qd)
+ "d, " + std::to_string(Math::qd) + "d]");
h = Utility::val<real>(std::string(argv[++m]));
timeset = false;
circle = true;
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-r")
rate = !rate;
else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(std::string(argv[m]));
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-T") {
if (++m == argc) return usage(1, true);
try {
tguard = Utility::val<real>(std::string(argv[m]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-H") {
if (++m == argc) return usage(1, true);
try {
hguard = Utility::val<real>(std::string(argv[m]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-v")
verbose = true;
else if (arg == "--input-string") {
if (++m == argc) return usage(1, true);
istring = argv[m];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else {
int retval = usage(!(arg == "-h" || arg == "--help"), arg != "--help");
if (arg == "-h")
std::cout<< "\nDefault magnetic path = \""
<< MagneticModel::DefaultMagneticPath()
<< "\"\nDefault magnetic name = \""
<< MagneticModel::DefaultMagneticName()
<< "\"\n";
return retval;
}
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
using std::fmax;
tguard = fmax(real(0), tguard);
hguard = fmax(real(0), hguard);
prec = std::min(10 + Math::extra_digits(), std::max(0, prec));
int retval = 0;
try {
using std::isfinite;
const MagneticModel m(model, dir, Geocentric::WGS84(), Nmax, Mmax);
if ((timeset || circle)
&& (!isfinite(time) ||
time < m.MinTime() - tguard ||
time > m.MaxTime() + tguard))
throw GeographicErr("Time " + Utility::str(time) +
" too far outside allowed range [" +
Utility::str(m.MinTime()) + "," +
Utility::str(m.MaxTime()) + "]");
if (circle
&& (!isfinite(h) ||
h < m.MinHeight() - hguard ||
h > m.MaxHeight() + hguard))
throw GeographicErr("Height " + Utility::str(h/1000) +
"km too far outside allowed range [" +
Utility::str(m.MinHeight()/1000) + "km," +
Utility::str(m.MaxHeight()/1000) + "km]");
if (verbose) {
std::cerr << "Magnetic file: " << m.MagneticFile() << "\n"
<< "Name: " << m.MagneticModelName() << "\n"
<< "Description: " << m.Description() << "\n"
<< "Date & Time: " << m.DateTime() << "\n"
<< "Time range: ["
<< m.MinTime() << ","
<< m.MaxTime() << "]\n"
<< "Height range: ["
<< m.MinHeight()/1000 << "km,"
<< m.MaxHeight()/1000 << "km]\n";
}
if ((timeset || circle) && (time < m.MinTime() || time > m.MaxTime()))
std::cerr << "WARNING: Time " << time
<< " outside allowed range ["
<< m.MinTime() << "," << m.MaxTime() << "]\n";
if (circle && (h < m.MinHeight() || h > m.MaxHeight()))
std::cerr << "WARNING: Height " << h/1000
<< "km outside allowed range ["
<< m.MinHeight()/1000 << "km,"
<< m.MaxHeight()/1000 << "km]\n";
const MagneticCircle c(circle ? m.Circle(time, lat, h) :
MagneticCircle());
std::string s, eol, stra, strb;
std::istringstream str;
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type n = s.find(cdelim);
if (n != std::string::npos) {
eol = " " + s.substr(n) + "\n";
s = s.substr(0, n);
}
}
str.clear(); str.str(s);
if (!(timeset || circle)) {
if (!(str >> stra))
throw GeographicErr("Incomplete input: " + s);
time = Utility::fractionalyear<real>(stra);
if (time < m.MinTime() - tguard || time > m.MaxTime() + tguard)
throw GeographicErr("Time " + Utility::str(time) +
" too far outside allowed range [" +
Utility::str(m.MinTime()) + "," +
Utility::str(m.MaxTime()) +
"]");
if (time < m.MinTime() || time > m.MaxTime())
std::cerr << "WARNING: Time " << time
<< " outside allowed range ["
<< m.MinTime() << "," << m.MaxTime() << "]\n";
}
real lon;
if (circle) {
if (!(str >> strb))
throw GeographicErr("Incomplete input: " + s);
DMS::flag ind;
lon = DMS::Decode(strb, ind);
if (ind == DMS::LATITUDE)
throw GeographicErr("Bad hemisphere letter on " + strb);
} else {
if (!(str >> stra >> strb))
throw GeographicErr("Incomplete input: " + s);
DMS::DecodeLatLon(stra, strb, lat, lon, longfirst);
h = 0; // h is optional
if (str >> h) {
if (h < m.MinHeight() - hguard || h > m.MaxHeight() + hguard)
throw GeographicErr("Height " + Utility::str(h/1000) +
"km too far outside allowed range [" +
Utility::str(m.MinHeight()/1000) + "km," +
Utility::str(m.MaxHeight()/1000) + "km]");
if (h < m.MinHeight() || h > m.MaxHeight())
std::cerr << "WARNING: Height " << h/1000
<< "km outside allowed range ["
<< m.MinHeight()/1000 << "km,"
<< m.MaxHeight()/1000 << "km]\n";
}
else
str.clear();
}
if (str >> stra)
throw GeographicErr("Extra junk in input: " + s);
real bx, by, bz, bxt, byt, bzt;
if (circle)
c(lon, bx, by, bz, bxt, byt, bzt);
else
m(time, lat, lon, h, bx, by, bz, bxt, byt, bzt);
real H, F, D, I, Ht, Ft, Dt, It;
MagneticModel::FieldComponents(bx, by, bz, bxt, byt, bzt,
H, F, D, I, Ht, Ft, Dt, It);
*output << DMS::Encode(D, prec + 1, DMS::NUMBER) << " "
<< DMS::Encode(I, prec + 1, DMS::NUMBER) << " "
<< Utility::str(H, prec) << " "
<< Utility::str(by, prec) << " "
<< Utility::str(bx, prec) << " "
<< Utility::str(-bz, prec) << " "
<< Utility::str(F, prec) << eol;
if (rate)
*output << DMS::Encode(Dt, prec + 1, DMS::NUMBER) << " "
<< DMS::Encode(It, prec + 1, DMS::NUMBER) << " "
<< Utility::str(Ht, prec) << " "
<< Utility::str(byt, prec) << " "
<< Utility::str(bxt, prec) << " "
<< Utility::str(-bzt, prec) << " "
<< Utility::str(Ft, prec) << eol;
}
catch (const std::exception& e) {
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
}
catch (const std::exception& e) {
std::cerr << "Error reading " << model << ": " << e.what() << "\n";
retval = 1;
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,163 @@
#
# Makefile.am
#
# Copyright (C) 2009, Francesco P. Lovergine <frankie@debian.org>
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include \
-I$(top_builddir)/man -I$(top_srcdir)/man -Wall -Wextra
LDADD = $(top_builddir)/src/libGeographicLib.la
DEPS = $(top_builddir)/src/libGeographicLib.la
bin_PROGRAMS = CartConvert \
ConicProj \
GeoConvert \
GeodSolve \
GeodesicProj \
GeoidEval \
Gravity \
MagneticField \
Planimeter \
RhumbSolve \
TransverseMercatorProj
CartConvert_SOURCES = CartConvert.cpp \
../man/CartConvert.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/Geocentric.hpp \
../include/GeographicLib/LocalCartesian.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/Utility.hpp
ConicProj_SOURCES = ConicProj.cpp \
../man/ConicProj.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/AlbersEqualArea.hpp \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/LambertConformalConic.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/Utility.hpp
GeoConvert_SOURCES = GeoConvert.cpp \
../man/GeoConvert.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/GeoCoords.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/UTMUPS.hpp \
../include/GeographicLib/Utility.hpp
GeodSolve_SOURCES = GeodSolve.cpp \
../man/GeodSolve.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/Geodesic.hpp \
../include/GeographicLib/GeodesicExact.hpp \
../include/GeographicLib/GeodesicLine.hpp \
../include/GeographicLib/GeodesicLineExact.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/Utility.hpp
GeodesicProj_SOURCES = GeodesicProj.cpp \
../man/GeodesicProj.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/AzimuthalEquidistant.hpp \
../include/GeographicLib/CassiniSoldner.hpp \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/Geodesic.hpp \
../include/GeographicLib/GeodesicLine.hpp \
../include/GeographicLib/Gnomonic.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/Utility.hpp
GeoidEval_SOURCES = GeoidEval.cpp \
../man/GeoidEval.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/GeoCoords.hpp \
../include/GeographicLib/Geoid.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/UTMUPS.hpp \
../include/GeographicLib/Utility.hpp
Gravity_SOURCES = Gravity.cpp \
../man/Gravity.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/CircularEngine.hpp \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/Geocentric.hpp \
../include/GeographicLib/GravityCircle.hpp \
../include/GeographicLib/GravityModel.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/NormalGravity.hpp \
../include/GeographicLib/SphericalEngine.hpp \
../include/GeographicLib/SphericalHarmonic.hpp \
../include/GeographicLib/SphericalHarmonic1.hpp \
../include/GeographicLib/Utility.hpp
MagneticField_SOURCES = MagneticField.cpp \
../man/MagneticField.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/CircularEngine.hpp \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/Geocentric.hpp \
../include/GeographicLib/MagneticCircle.hpp \
../include/GeographicLib/MagneticModel.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/SphericalEngine.hpp \
../include/GeographicLib/SphericalHarmonic.hpp \
../include/GeographicLib/Utility.hpp
Planimeter_SOURCES = Planimeter.cpp \
../man/Planimeter.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/Accumulator.hpp \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/Ellipsoid.hpp \
../include/GeographicLib/GeoCoords.hpp \
../include/GeographicLib/Geodesic.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/PolygonArea.hpp \
../include/GeographicLib/Rhumb.hpp \
../include/GeographicLib/UTMUPS.hpp \
../include/GeographicLib/Utility.hpp
RhumbSolve_SOURCES = RhumbSolve.cpp \
../man/RhumbSolve.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/Ellipsoid.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/Utility.hpp
TransverseMercatorProj_SOURCES = TransverseMercatorProj.cpp \
../man/TransverseMercatorProj.usage \
../include/GeographicLib/Config.h \
../include/GeographicLib/Constants.hpp \
../include/GeographicLib/DMS.hpp \
../include/GeographicLib/EllipticFunction.hpp \
../include/GeographicLib/Math.hpp \
../include/GeographicLib/TransverseMercator.hpp \
../include/GeographicLib/TransverseMercatorExact.hpp \
../include/GeographicLib/Utility.hpp
sbin_SCRIPTS = geographiclib-get-geoids \
geographiclib-get-gravity \
geographiclib-get-magnetic
geographiclib_data = $(datadir)/GeographicLib
geographiclib-get-geoids: geographiclib-get-geoids.sh
sed -e "s%@GEOGRAPHICLIB_DATA@%$(geographiclib_data)%" $< > $@
chmod +x $@
geographiclib-get-gravity: geographiclib-get-gravity.sh
sed -e "s%@GEOGRAPHICLIB_DATA@%$(geographiclib_data)%" $< > $@
chmod +x $@
geographiclib-get-magnetic: geographiclib-get-magnetic.sh
sed -e "s%@GEOGRAPHICLIB_DATA@%$(geographiclib_data)%" $< > $@
chmod +x $@
CLEANFILES = $(sbin_SCRIPTS)
EXTRA_DIST = CMakeLists.txt \
geographiclib-get-geoids.sh geographiclib-get-gravity.sh \
geographiclib-get-magnetic.sh

View File

@@ -0,0 +1,248 @@
/**
* \file Planimeter.cpp
* \brief Command line utility for measuring the area of geodesic polygons
*
* Copyright (c) Charles Karney (2010-2022) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="Planimeter.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/PolygonArea.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#include <GeographicLib/GeoCoords.hpp>
#include <GeographicLib/Ellipsoid.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (disable: 4127)
#endif
#include "Planimeter.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
enum { GEODESIC, EXACT, AUTHALIC, RHUMB };
real
a = Constants::WGS84_a(),
f = Constants::WGS84_f();
bool reverse = false, sign = true, polyline = false, longfirst = false,
geoconvert_compat = false;
int linetype = GEODESIC;
int prec = 6;
std::string istring, ifile, ofile, cdelim;
char lsep = ';';
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-r")
reverse = !reverse;
else if (arg == "-s")
sign = !sign;
else if (arg == "-l")
polyline = !polyline;
else if (arg == "-e") {
if (m + 2 >= argc) return usage(1, true);
try {
a = Utility::val<real>(std::string(argv[m + 1]));
f = Utility::fract<real>(std::string(argv[m + 2]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
return 1;
}
m += 2;
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(std::string(argv[m]));
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-G")
linetype = GEODESIC;
else if (arg == "-E")
linetype = EXACT;
else if (arg == "-Q")
linetype = AUTHALIC;
else if (arg == "-R")
linetype = RHUMB;
else if (arg == "--geoconvert-input")
geoconvert_compat = true;
else if (arg == "--input-string") {
if (++m == argc) return usage(1, true);
istring = argv[m];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else
return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
const Ellipsoid ellip(a, f);
if (linetype == AUTHALIC) {
using std::sqrt;
a = sqrt(ellip.Area() / (4 * Math::pi()));
f = 0;
}
const Geodesic geod(a, f);
const GeodesicExact geode(a, f);
const Rhumb rhumb(a, f);
PolygonArea poly(geod, polyline);
PolygonAreaExact polye(geode, polyline);
PolygonAreaRhumb polyr(rhumb, polyline);
GeoCoords p;
// 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, eol("\n");
real perimeter, area;
unsigned num;
std::istringstream str;
std::string slat, slon, junk;
real lat = 0, lon = 0;
while (std::getline(*input, s)) {
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
bool endpoly = s.empty();
if (!endpoly) {
try {
using std::isnan;
if (geoconvert_compat) {
p.Reset(s, true, longfirst);
lat = p.Latitude(); lon = p.Longitude();
} else {
str.clear(); str.str(s);
if (!(str >> slat >> slon))
throw GeographicErr("incomplete input");
if (str >> junk)
throw GeographicErr("extra input");
DMS::DecodeLatLon(slat, slon, lat, lon, longfirst);
}
if (isnan(lat) || isnan(lon))
endpoly = true;
}
catch (const GeographicErr&) {
endpoly = true;
}
}
if (endpoly) {
num =
linetype == EXACT ? polye.Compute(reverse, sign, perimeter, area) :
linetype == RHUMB ? polyr.Compute(reverse, sign, perimeter, area) :
poly.Compute(reverse, sign, perimeter, area); // geodesic + authalic
if (num > 0) {
*output << num << " " << Utility::str(perimeter, prec);
if (!polyline) {
*output << " " << Utility::str(area, std::max(0, prec - 5));
}
*output << eol;
}
linetype == EXACT ? polye.Clear() :
linetype == RHUMB ? polyr.Clear() : poly.Clear();
eol = "\n";
} else {
linetype == EXACT ? polye.AddPoint(lat, lon) :
linetype == RHUMB ? polyr.AddPoint(lat, lon) :
poly.AddPoint(linetype == AUTHALIC ? ellip.AuthalicLatitude(lat) :
lat, lon);
}
}
num =
linetype == EXACT ? polye.Compute(reverse, sign, perimeter, area) :
linetype == RHUMB ? polyr.Compute(reverse, sign, perimeter, area) :
poly.Compute(reverse, sign, perimeter, area);
if (num > 0) {
*output << num << " " << Utility::str(perimeter, prec);
if (!polyline) {
*output << " " << Utility::str(area, std::max(0, prec - 5));
}
*output << eol;
}
linetype == EXACT ? polye.Clear() :
linetype == RHUMB ? polyr.Clear() : poly.Clear();
eol = "\n";
return 0;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,244 @@
/**
* \file RhumbSolve.cpp
* \brief Command line utility for rhumb line calculations
*
* Copyright (c) Charles Karney (2014-2017) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="RhumbSolve.1.html">man page</a> for usage information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <cmath>
#include <limits>
#include <GeographicLib/Rhumb.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions and potentially
// uninitialized local variables
# pragma warning (disable: 4127 4701)
#endif
#include "RhumbSolve.usage"
using namespace GeographicLib;
typedef Math::real real;
std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep,
bool longfirst) {
using namespace GeographicLib;
std::string
latstr = dms ? DMS::Encode(lat, prec + 5, DMS::LATITUDE, dmssep) :
DMS::Encode(lat, prec + 5, DMS::NUMBER),
lonstr = dms ? DMS::Encode(lon, prec + 5, DMS::LONGITUDE, dmssep) :
DMS::Encode(lon, prec + 5, DMS::NUMBER);
return
(longfirst ? lonstr : latstr) + " " + (longfirst ? latstr : lonstr);
}
std::string AzimuthString(real azi, int prec, bool dms, char dmssep) {
return dms ? DMS::Encode(azi, prec + 5, DMS::AZIMUTH, dmssep) :
DMS::Encode(azi, prec + 5, DMS::NUMBER);
}
int main(int argc, const char* const argv[]) {
try {
Utility::set_digits();
bool linecalc = false, inverse = false, dms = false, exact = true,
longfirst = false;
real
a = Constants::WGS84_a(),
f = Constants::WGS84_f();
real lat1, lon1, azi12 = Math::NaN(), lat2, lon2, s12, S12;
int prec = 3;
std::string istring, ifile, ofile, cdelim;
char lsep = ';', dmssep = char(0);
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-i") {
inverse = true;
linecalc = false;
} else if (arg == "-L" || arg == "-l") { // -l is DEPRECATED
inverse = false;
linecalc = true;
if (m + 3 >= argc) return usage(1, true);
try {
DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
lat1, lon1, longfirst);
azi12 = DMS::DecodeAzimuth(std::string(argv[m + 3]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -L: " << e.what() << "\n";
return 1;
}
m += 3;
} else if (arg == "-e") {
if (m + 2 >= argc) return usage(1, true);
try {
a = Utility::val<real>(std::string(argv[m + 1]));
f = Utility::fract<real>(std::string(argv[m + 2]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
return 1;
}
m += 2;
}
else if (arg == "-d") {
dms = true;
dmssep = '\0';
} else if (arg == "-:") {
dms = true;
dmssep = ':';
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(std::string(argv[m]));
}
catch (const std::exception&) {
std::cerr << "Precision " << argv[m] << " is not a number\n";
return 1;
}
} else if (arg == "-s")
exact = false;
else if (arg == "--input-string") {
if (++m == argc) return usage(1, true);
istring = argv[m];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else
return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
const Rhumb rh(a, f, exact);
const RhumbLine rhl(linecalc ? rh.Line(lat1, lon1, azi12) :
rh.Line(0, 0, Math::qd));
// 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, eol, slat1, slon1, slat2, slon2, sazi, ss12, strc;
std::istringstream str;
int retval = 0;
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
str.clear(); str.str(s);
if (linecalc) {
if (!(str >> s12))
throw GeographicErr("Incomplete input: " + s);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
rhl.Position(s12, lat2, lon2, S12);
*output << LatLonString(lat2, lon2, prec, dms, dmssep, longfirst)
<< " " << Utility::str(S12, std::max(prec-7, 0)) << eol;
} else if (inverse) {
if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
throw GeographicErr("Incomplete input: " + s);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
DMS::DecodeLatLon(slat1, slon1, lat1, lon1, longfirst);
DMS::DecodeLatLon(slat2, slon2, lat2, lon2, longfirst);
rh.Inverse(lat1, lon1, lat2, lon2, s12, azi12, S12);
*output << AzimuthString(azi12, prec, dms, dmssep) << " "
<< Utility::str(s12, prec) << " "
<< Utility::str(S12, std::max(prec-7, 0)) << eol;
} else { // direct
if (!(str >> slat1 >> slon1 >> sazi >> s12))
throw GeographicErr("Incomplete input: " + s);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
DMS::DecodeLatLon(slat1, slon1, lat1, lon1, longfirst);
azi12 = DMS::DecodeAzimuth(sazi);
rh.Direct(lat1, lon1, azi12, s12, lat2, lon2, S12);
*output << LatLonString(lat2, lon2, prec, dms, dmssep, longfirst)
<< " " << Utility::str(S12, std::max(prec-7, 0)) << eol;
}
}
catch (const std::exception& e) {
// Write error message cout so output lines match input lines
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,239 @@
/**
* \file TransverseMercatorProj.cpp
* \brief Command line utility for transverse Mercator projections
*
* Copyright (c) Charles Karney (2008-2017) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* See the <a href="TransverseMercatorProj.1.html">man page</a> for usage
* information.
**********************************************************************/
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <GeographicLib/TransverseMercatorExact.hpp>
#include <GeographicLib/TransverseMercator.hpp>
#include <GeographicLib/DMS.hpp>
#include <GeographicLib/Utility.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions and potentially
// uninitialized local variables
# pragma warning (disable: 4127 4701)
#endif
#include "TransverseMercatorProj.usage"
int main(int argc, const char* const argv[]) {
try {
using namespace GeographicLib;
typedef Math::real real;
Utility::set_digits();
bool exact = true, extended = false, series = false, reverse = false,
longfirst = false;
real
a = Constants::WGS84_a(),
f = Constants::WGS84_f(),
k0 = Constants::UTM_k0(),
lon0 = 0;
int prec = 6;
std::string istring, ifile, ofile, cdelim;
char lsep = ';';
for (int m = 1; m < argc; ++m) {
std::string arg(argv[m]);
if (arg == "-r")
reverse = true;
else if (arg == "-t") {
exact = true;
extended = true;
series = false;
} else if (arg == "-s") {
exact = false;
extended = false;
series = true;
} else if (arg == "-l") {
if (++m >= argc) return usage(1, true);
try {
DMS::flag ind;
lon0 = DMS::Decode(std::string(argv[m]), ind);
if (ind == DMS::LATITUDE)
throw GeographicErr("Bad hemisphere");
lon0 = Math::AngNormalize(lon0);
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-k") {
if (++m >= argc) return usage(1, true);
try {
k0 = Utility::val<real>(std::string(argv[m]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding argument of " << arg << ": "
<< e.what() << "\n";
return 1;
}
} else if (arg == "-e") {
if (m + 2 >= argc) return usage(1, true);
try {
a = Utility::val<real>(std::string(argv[m + 1]));
f = Utility::fract<real>(std::string(argv[m + 2]));
}
catch (const std::exception& e) {
std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
return 1;
}
m += 2;
} else if (arg == "-w")
longfirst = !longfirst;
else if (arg == "-p") {
if (++m == argc) return usage(1, true);
try {
prec = Utility::val<int>(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];
} else if (arg == "--input-file") {
if (++m == argc) return usage(1, true);
ifile = argv[m];
} else if (arg == "--output-file") {
if (++m == argc) return usage(1, true);
ofile = argv[m];
} else if (arg == "--line-separator") {
if (++m == argc) return usage(1, true);
if (std::string(argv[m]).size() != 1) {
std::cerr << "Line separator must be a single character\n";
return 1;
}
lsep = argv[m][0];
} else if (arg == "--comment-delimiter") {
if (++m == argc) return usage(1, true);
cdelim = argv[m];
} else if (arg == "--version") {
std::cout << argv[0] << ": GeographicLib version "
<< GEOGRAPHICLIB_VERSION_STRING << "\n";
return 0;
} else
return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
}
if (!ifile.empty() && !istring.empty()) {
std::cerr << "Cannot specify --input-string and --input-file together\n";
return 1;
}
if (ifile == "-") ifile.clear();
std::ifstream infile;
std::istringstream instring;
if (!ifile.empty()) {
infile.open(ifile.c_str());
if (!infile.is_open()) {
std::cerr << "Cannot open " << ifile << " for reading\n";
return 1;
}
} else if (!istring.empty()) {
std::string::size_type m = 0;
while (true) {
m = istring.find(lsep, m);
if (m == std::string::npos)
break;
istring[m] = '\n';
}
instring.str(istring);
}
std::istream* input = !ifile.empty() ? &infile :
(!istring.empty() ? &instring : &std::cin);
std::ofstream outfile;
if (ofile == "-") ofile.clear();
if (!ofile.empty()) {
outfile.open(ofile.c_str());
if (!outfile.is_open()) {
std::cerr << "Cannot open " << ofile << " for writing\n";
return 1;
}
}
std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
const TransverseMercator& TMS =
series ? TransverseMercator(a, f, k0) : TransverseMercator(1, 0, 1);
const TransverseMercatorExact& TME =
exact ? TransverseMercatorExact(a, f, k0, extended)
: TransverseMercatorExact(1, real(0.1), 1, false);
// 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, eol, stra, strb, strc;
std::istringstream str;
int retval = 0;
std::cout << std::fixed;
while (std::getline(*input, s)) {
try {
eol = "\n";
if (!cdelim.empty()) {
std::string::size_type m = s.find(cdelim);
if (m != std::string::npos) {
eol = " " + s.substr(m) + "\n";
s = s.substr(0, m);
}
}
str.clear(); str.str(s);
real lat, lon, x, y;
if (!(str >> stra >> strb))
throw GeographicErr("Incomplete input: " + s);
if (reverse) {
x = Utility::val<real>(stra);
y = Utility::val<real>(strb);
} else
DMS::DecodeLatLon(stra, strb, lat, lon, longfirst);
if (str >> strc)
throw GeographicErr("Extraneous input: " + strc);
real gamma, k;
if (reverse) {
if (series)
TMS.Reverse(lon0, x, y, lat, lon, gamma, k);
else
TME.Reverse(lon0, x, y, lat, lon, gamma, k);
*output << Utility::str(longfirst ? lon : lat, prec + 5) << " "
<< Utility::str(longfirst ? lat : lon, prec + 5) << " "
<< Utility::str(gamma, prec + 6) << " "
<< Utility::str(k, prec + 6) << eol;
} else {
if (series)
TMS.Forward(lon0, lat, lon, x, y, gamma, k);
else
TME.Forward(lon0, lat, lon, x, y, gamma, k);
*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) {
*output << "ERROR: " << e.what() << "\n";
retval = 1;
}
}
return retval;
}
catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
return 1;
}
catch (...) {
std::cerr << "Caught unknown exception\n";
return 1;
}
}

View File

@@ -0,0 +1,211 @@
#! /bin/sh
#
# Download geoid datasets for use by GeographicLib::Geoid. This is
# modeled on a similar script geographiclib-datasets-download by
# Francesco P. Lovergine <frankie@debian.org>
#
# Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and
# licensed under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
DEFAULTDIR="@GEOGRAPHICLIB_DATA@"
SUBDIR=geoids
NAME=geoid
MODEL=geoid
CLASS=Geoid
TOOL=GeoidEval
EXT=pgm
usage() {
cat <<EOF
usage: $0 [-p parentdir] [-f] [-d] [-h] $MODEL...
This program downloads and installs the datasets used by the
GeographicLib::$CLASS class and the $TOOL tool to compute geoid
heights. These datasets are NGA earth gravity models evaluated on a
rectangular grid in latitude and longitude. $MODEL is one of more of the
names from this table:
size (MB)
name geoid grid tar.bz2 disk
egm84-30 EGM84 30' 0.5 0.6
egm84-15 EGM84 15' 1.5 2.1
egm96-15 EGM96 15' 1.5 2.1
egm96-5 EGM96 5' 11 19
egm2008-5 EGM2008 5' 11 19
egm2008-2_5 EGM2008 2.5' 35 75
egm2008-1 EGM2008 1' 170 470
The size columns give the download and installed sizes of the datasets.
In addition you can specify
all = all of the supported geoids
minimal = emg96-5
best = egm84-15 egm96-5 egm2008-1 (the highest resolution for each
earth gravity model)
good = same as best but substitute egm2008-2_5 for egm2008-1 to save
on disk space
-p parentdir (default $DEFAULTDIR) specifies where the
datasets should be stored. The "Default $NAME path" listed when running
$TOOL -h
should be parentdir/$SUBDIR. This script must be run by a user with
write access to this directory.
Normally only datasets which are not already in parentdir are
downloaded. You can force the download and reinstallation with -f.
The -f flag also let you download new models (not yet in the set
defined by "all").
If -d is provided, the temporary directory which holds the downloads,
\$TMPDIR/$NAME-XXXXXXXX or ${TMPDIR:-/tmp}/$NAME-XXXXXXXX,
will be saved. -h prints this help.
For more information on the $NAME datasets, visit
https://geographiclib.sourceforge.io/C++/doc/$NAME.html
EOF
}
PARENTDIR="$DEFAULTDIR"
DEBUG=
FORCE=
while getopts hp:fd c; do
case $c in
h )
usage;
exit 0
;;
p ) PARENTDIR="$OPTARG"
;;
f ) FORCE=y
;;
d ) DEBUG=y
;;
* )
usage 1>&2;
exit 1
;;
esac
done
shift `expr $OPTIND - 1`
if test $# -eq 0; then
usage 1>&2;
exit 1
fi
test -d "$PARENTDIR"/$SUBDIR || mkdir -p "$PARENTDIR"/$SUBDIR 2> /dev/null
if test ! -d "$PARENTDIR"/$SUBDIR; then
echo Cannot create directory $PARENTDIR/$SUBDIR 1>&2
exit 1
fi
TEMP=
if test -z "$DEBUG"; then
trap 'trap "" 0; test "$TEMP" && rm -rf "$TEMP"; exit 1' 1 2 3 9 15
trap 'test "$TEMP" && rm -rf "$TEMP"' 0
fi
TEMP=`mktemp -d -q -t $NAME-XXXXXXXX`
if test -z "$TEMP" -o ! -d "$TEMP"; then
echo Cannot create temporary directory 1>&2
exit 1
fi
WRITETEST="$PARENTDIR"/$SUBDIR/write-test-`basename $TEMP`
if touch "$WRITETEST" 2> /dev/null; then
rm -f "$WRITETEST"
else
echo Cannot write in directory $PARENTDIR/$SUBDIR 1>&2
exit 1
fi
set -e
cat > $TEMP/all <<EOF
egm84-30
egm84-15
egm96-15
egm96-5
egm2008-5
egm2008-2_5
egm2008-1
EOF
while test $# -gt 0; do
if grep "^$1\$" $TEMP/all > /dev/null; then
echo $1
else
case "$1" in
all )
cat $TEMP/all
;;
minimal )
echo egm96-5
;;
best ) # highest resolution models
cat <<EOF
egm2008-1
egm96-5
egm84-15
EOF
;;
good ) # like best but with egm2008-1 -> egm2008-2_5
cat <<EOF
egm2008-2_5
egm96-5
egm84-15
EOF
;;
* )
if test -n "$FORCE"; then
echo $1
else
echo Unknown $MODEL $1 1>&2
exit 1
fi
;;
esac
fi
shift
done > $TEMP/list
sort -u $TEMP/list > $TEMP/todo
while read file; do
if test -z "$FORCE" -a -s $PARENTDIR/$SUBDIR/$file.$EXT; then
echo $PARENTDIR/$SUBDIR/$file.$EXT already installed, skipping $file...
echo $file >> $TEMP/skip
continue
fi
echo download $file.tar.bz2 ...
echo $file >> $TEMP/download
URL="https://downloads.sourceforge.net/project/geographiclib/$SUBDIR-distrib/$file.tar.bz2?use_mirror=autoselect"
ARCHIVE=$TEMP/$file.tar.bz2
wget -O$ARCHIVE $URL
echo unpack $file.tar.bz2 ...
tar vxojf $ARCHIVE -C $PARENTDIR
echo $MODEL $file installed.
done < $TEMP/todo
if test "$DEBUG"; then
echo Saving temporary directory $TEMP
fi
echo
if test -s $TEMP/download; then
n=`wc -l < $TEMP/download`
s=; test $n -gt 1 && s=s
cat <<EOF
Installed $NAME dataset$s `tr '\n' ' ' < $TEMP/download`in $PARENTDIR/$SUBDIR.
EOF
fi
if test -s $TEMP/skip; then
n=`wc -l < $TEMP/skip`
s=; test $n -gt 1 && s=s
cat <<EOF
Skipped $NAME dataset$s `tr '\n' ' ' < $TEMP/skip | sed 's/ $//'`.
EOF
fi
echo

View File

@@ -0,0 +1,186 @@
#! /bin/sh
#
# Download gravity models for use by GeographicLib::GravityModel.
#
# Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and
# licensed under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
DEFAULTDIR="@GEOGRAPHICLIB_DATA@"
SUBDIR=gravity
NAME=gravity
MODEL=gravitymodel
CLASS=GravityModel
TOOL=Gravity
EXT=egm.cof
usage() {
cat <<EOF
usage: $0 [-p parentdir] [-f] [-d] [-h] $MODEL...
This program downloads and installs the datasets used by the
GeographicLib::$CLASS class and the $TOOL tool to compute
gravity fields. $MODEL is one of more of the names from this
table:
size (kB)
name degree tar.bz2 disk
egm84 18 27 26
egm96 360 2100 2100
egm2008 2190 76000 75000
wgs84 20 1 1
grs80 20 1 1
The size columns give the download and installed sizes of the datasets.
In addition you can specify
all = all of the supported gravity models
minimal = egm96 wgs84
-p parentdir (default $DEFAULTDIR) specifies where the
datasets should be stored. The "Default $NAME path" listed when running
$TOOL -h
should be parentdir/$SUBDIR. This script must be run by a user with
write access to this directory.
Normally only datasets which are not already in parentdir are
downloaded. You can force the download and reinstallation with -f.
The -f flag also let you download new models (not yet in the set
defined by "all").
If -d is provided, the temporary directory which holds the downloads,
\$TMPDIR/$NAME-XXXXXXXX or ${TMPDIR:-/tmp}/$NAME-XXXXXXXX,
will be saved. -h prints this help.
For more information on the $NAME datasets, visit
https://geographiclib.sourceforge.io/C++/doc/$NAME.html
EOF
}
PARENTDIR="$DEFAULTDIR"
DEBUG=
FORCE=
while getopts hp:fd c; do
case $c in
h )
usage;
exit 0
;;
p ) PARENTDIR="$OPTARG"
;;
f ) FORCE=y
;;
d ) DEBUG=y
;;
* )
usage 1>&2;
exit 1
;;
esac
done
shift `expr $OPTIND - 1`
if test $# -eq 0; then
usage 1>&2;
exit 1
fi
test -d "$PARENTDIR"/$SUBDIR || mkdir -p "$PARENTDIR"/$SUBDIR 2> /dev/null
if test ! -d "$PARENTDIR"/$SUBDIR; then
echo Cannot create directory $PARENTDIR/$SUBDIR 1>&2
exit 1
fi
TEMP=
if test -z "$DEBUG"; then
trap 'trap "" 0; test "$TEMP" && rm -rf "$TEMP"; exit 1' 1 2 3 9 15
trap 'test "$TEMP" && rm -rf "$TEMP"' 0
fi
TEMP=`mktemp -d -q -t $NAME-XXXXXXXX`
if test -z "$TEMP" -o ! -d "$TEMP"; then
echo Cannot create temporary directory 1>&2
exit 1
fi
WRITETEST="$PARENTDIR"/$SUBDIR/write-test-`basename $TEMP`
if touch "$WRITETEST" 2> /dev/null; then
rm -f "$WRITETEST"
else
echo Cannot write in directory $PARENTDIR/$SUBDIR 1>&2
exit 1
fi
set -e
cat > $TEMP/all <<EOF
egm84
egm96
egm2008
grs80
wgs84
EOF
while test $# -gt 0; do
if grep "^$1\$" $TEMP/all > /dev/null; then
echo $1
else
case "$1" in
all )
cat $TEMP/all
;;
minimal )
echo egm96; echo wgs84
;;
* )
if test -n "$FORCE"; then
echo $1
else
echo Unknown $MODEL $1 1>&2
exit 1
fi
;;
esac
fi
shift
done > $TEMP/list
sort -u $TEMP/list > $TEMP/todo
while read file; do
if test -z "$FORCE" -a -s $PARENTDIR/$SUBDIR/$file.$EXT; then
echo $PARENTDIR/$SUBDIR/$file.$EXT already installed, skipping $file...
echo $file >> $TEMP/skip
continue
fi
echo download $file.tar.bz2 ...
echo $file >> $TEMP/download
URL="https://downloads.sourceforge.net/project/geographiclib/$SUBDIR-distrib/$file.tar.bz2?use_mirror=autoselect"
ARCHIVE=$TEMP/$file.tar.bz2
wget -O$ARCHIVE $URL
echo unpack $file.tar.bz2 ...
tar vxojf $ARCHIVE -C $PARENTDIR
echo $MODEL $file installed.
done < $TEMP/todo
if test "$DEBUG"; then
echo Saving temporary directory $TEMP
fi
echo
if test -s $TEMP/download; then
n=`wc -l < $TEMP/download`
s=; test $n -gt 1 && s=s
cat <<EOF
Installed $NAME dataset$s `tr '\n' ' ' < $TEMP/download`in $PARENTDIR/$SUBDIR.
EOF
fi
if test -s $TEMP/skip; then
n=`wc -l < $TEMP/skip`
s=; test $n -gt 1 && s=s
cat <<EOF
Skipped $NAME dataset$s `tr '\n' ' ' < $TEMP/skip | sed 's/ $//'`.
EOF
fi
echo

View File

@@ -0,0 +1,195 @@
#! /bin/sh
#
# Download magnetic models for use by GeographicLib::MagneticModel.
#
# Copyright (c) Charles Karney (2011-2022) <charles@karney.com> and
# licensed under the MIT/X11 License. For more information, see
# https://geographiclib.sourceforge.io/
DEFAULTDIR="@GEOGRAPHICLIB_DATA@"
SUBDIR=magnetic
NAME=magnetic
MODEL=magneticmodel
CLASS=MagneticModel
TOOL=MagneticField
EXT=wmm.cof
usage() {
cat <<EOF
usage: $0 [-p parentdir] [-f] [-d] [-h] $MODEL...
This program downloads and installs the datasets used by the
GeographicLib::$CLASS class and the $TOOL tool to compute
magnetic fields. $MODEL is one of more of the names from this
table:
size (kB)
name degree years tar.bz2 disk
wmm2010 12 2010-2015 2 3
wmm2015 12 2015-2020 2 3 *deprecated*
wmm2015v2 12 2015-2020 2 3
wmm2020 12 2020-2025 2 3
igrf11 13 1900-2015 7 25
igrf12 13 1900-2020 7 26
igrf13 13 1900-2025 7 28
emm2010 739 2010-2015 3700 4400
emm2015 729 2000-2020 660 4300
emm2017 790 2000-2022 1740 5050
The size columns give the download and installed sizes of the datasets.
In addition you can specify
all = all of the supported magnetic models
minimal = wmm2020 igrf13
-p parentdir (default $DEFAULTDIR) specifies where the
datasets should be stored. The "Default $NAME path" listed when running
$TOOL -h
should be parentdir/$SUBDIR. This script must be run by a user with
write access to this directory.
Normally only datasets which are not already in parentdir are
downloaded. You can force the download and reinstallation with -f.
The -f flag also let you download new models (not yet in the set
defined by "all").
If -d is provided, the temporary directory which holds the downloads,
\$TMPDIR/$NAME-XXXXXXXX or ${TMPDIR:-/tmp}/$NAME-XXXXXXXX,
will be saved. -h prints this help.
For more information on the magnetic models, visit
https://geographiclib.sourceforge.io/C++/doc/$NAME.html
EOF
}
PARENTDIR="$DEFAULTDIR"
FORCE=
while getopts hp:fd c; do
case $c in
h )
usage;
exit 0
;;
p ) PARENTDIR="$OPTARG"
;;
f ) FORCE=y
;;
d ) DEBUG=y
;;
* )
usage 1>&2;
exit 1
;;
esac
done
shift `expr $OPTIND - 1`
if test $# -eq 0; then
usage 1>&2;
exit 1
fi
test -d "$PARENTDIR"/$SUBDIR || mkdir -p "$PARENTDIR"/$SUBDIR 2> /dev/null
if test ! -d "$PARENTDIR"/$SUBDIR; then
echo Cannot create directory $PARENTDIR/$SUBDIR 1>&2
exit 1
fi
TEMP=
if test -z "$DEBUG"; then
trap 'trap "" 0; test "$TEMP" && rm -rf "$TEMP"; exit 1' 1 2 3 9 15
trap 'test "$TEMP" && rm -rf "$TEMP"' 0
fi
TEMP=`mktemp -d -q -t $NAME-XXXXXXXX`
if test -z "$TEMP" -o ! -d "$TEMP"; then
echo Cannot create temporary directory 1>&2
exit 1
fi
WRITETEST="$PARENTDIR"/$SUBDIR/write-test-`basename $TEMP`
if touch "$WRITETEST" 2> /dev/null; then
rm -f "$WRITETEST"
else
echo Cannot write in directory $PARENTDIR/$SUBDIR 1>&2
exit 1
fi
set -e
cat > $TEMP/all <<EOF
wmm2010
wmm2015
wmm2015v2
wmm2020
emm2010
emm2015
emm2017
igrf11
igrf12
igrf13
EOF
while test $# -gt 0; do
if grep "^$1\$" $TEMP/all > /dev/null; then
echo $1
else
case "$1" in
all )
cat $TEMP/all
;;
minimal )
echo wmm2020; echo igrf13
;;
* )
if test -n "$FORCE"; then
echo $1
else
echo Unknown $MODEL $1 1>&2
exit 1
fi
;;
esac
fi
shift
done > $TEMP/list
sort -u $TEMP/list > $TEMP/todo
while read file; do
if test -z "$FORCE" -a -s $PARENTDIR/$SUBDIR/$file.$EXT; then
echo $PARENTDIR/$SUBDIR/$file.$EXT already installed, skipping $file...
echo $file >> $TEMP/skip
continue
fi
echo download $file.tar.bz2 ...
echo $file >> $TEMP/download
URL="https://downloads.sourceforge.net/project/geographiclib/$SUBDIR-distrib/$file.tar.bz2?use_mirror=autoselect"
ARCHIVE=$TEMP/$file.tar.bz2
wget -O$ARCHIVE $URL
echo unpack $file.tar.bz2 ...
tar vxojf $ARCHIVE -C $PARENTDIR
echo $MODEL $file installed.
done < $TEMP/todo
if test "$DEBUG"; then
echo Saving temporary directory $TEMP
fi
echo
if test -s $TEMP/download; then
n=`wc -l < $TEMP/download`
s=; test $n -gt 1 && s=s
cat <<EOF
Installed $NAME dataset$s `tr '\n' ' ' < $TEMP/download`in $PARENTDIR/$SUBDIR.
EOF
fi
if test -s $TEMP/skip; then
n=`wc -l < $TEMP/skip`
s=; test $n -gt 1 && s=s
cat <<EOF
Skipped $NAME dataset$s `tr '\n' ' ' < $TEMP/skip | sed 's/ $//'`.
EOF
fi
echo