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

View File

@@ -0,0 +1,18 @@
# Calling the GeographicLib C++ library from other languages
Here are some examples of calling the C++ library from other languages
such as C, Octave, and Python.
Although the geodesic capabilities of GeographicLib have been
implemented natively in several languages. There are no plans to do the
same for its other capabilities since this leads to a large continuing
obligation for maintenance and documentation. (Note however that thet
Octave/MATLAB library includes additional capabilities, UTM, MGRS, etc.)
An alternative strategy is to call the C++ library directly from
another language, possibly via some "wrapper" routines. This can be a
good strategy for a user who only wants to call a few GeographicLib
routines from another language.
Please contribute other examples, either for the languages given here or
for other languages.

View File

@@ -0,0 +1,39 @@
cmake_minimum_required (VERSION 3.13.0)
project (geoidtest)
# Set a default build type for single-configuration cmake generators if
# no build type is set.
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Release)
endif ()
# Make the compiler more picky.
if (MSVC)
string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
string (REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
endif ()
find_package (GeographicLib REQUIRED COMPONENTS SHARED)
add_executable (${PROJECT_NAME} ${PROJECT_NAME}.c cgeoid.cpp)
target_link_libraries (${PROJECT_NAME} ${GeographicLib_LIBRARIES})
get_target_property (GEOGRAPHICLIB_LIB_TYPE ${GeographicLib_LIBRARIES} TYPE)
if (GEOGRAPHICLIB_LIB_TYPE STREQUAL "SHARED_LIBRARY")
if (WIN32)
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
COMMAND
${CMAKE_COMMAND} -E
copy $<TARGET_FILE:${GeographicLib_LIBRARIES}> ${CMAKE_CFG_INTDIR}
COMMENT "Installing shared library in build tree")
else ()
# Set the run time path for shared libraries for non-Windows machines.
set_target_properties (${PROJECT_NAME}
PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
endif ()
endif ()

View File

@@ -0,0 +1,52 @@
# Calling the GeographicLib C++ library from C
The geodesic routines in GeographicLib have been implemented as a native
C library. See
https://geographiclib.sourceforge.io/C/doc/
It is also possible to call the C++ version of GeographicLib directly
from C and this directory contains a small example, which convert
heights above the geoid to heights above the ellipsoid. More
information on calling C++ from C, see
https://isocpp.org/wiki/faq/mixing-c-and-cpp
To build and install this interface, do
```bash
mkdir BUILD
cd BUILD
cmake ..
make
```
This assumes that you have installed GeographicLib somewhere that cmake
can find it. If you want just to use the version of GeographicLib that
you have built in the top-level BUILD directory, include, e.g.,
```bash
-D GeographicLib_DIR=../../BUILD
```
in the invocation of cmake (the directory is relative to the source
directory, wrapper/C). To convert 20m above the geoid at 42N 75W to a
height above the ellipsoid, use
```bash
$ echo 42 -75 20 | ./geoidtest
-10.672
```
Notes:
* The geoid data (`egm2008-1`) should be installed somewhere that
GeographicLib knows about.
* This prescription applies to Linux machines. Similar steps can be
used on Windows and MacOSX machines.
* It is essential that the application be linked with the C++ compiler,
so that the C++ runtime library is included.
* In this example, the main program is compiled with the C compiler. In
more complicated situations, it may be necessary to use the C++
compiler. This is necessary to get static initializations of C++
classes performed. (However, GeographicLib doesn't need any static
initialization.)

View File

@@ -0,0 +1,14 @@
#include "cgeoid.h"
#include "GeographicLib/Geoid.hpp"
extern "C"
double HeightAboveEllipsoid(double lat, double lon, double h) {
try {
// Declare static so that g is only constructed once
static const GeographicLib::Geoid g("egm2008-1");
return h + GeographicLib::Geoid::GEOIDTOELLIPSOID * g(lat, lon);
}
catch (...) {
return GeographicLib::Math::NaN();
}
}

View File

@@ -0,0 +1,9 @@
#if !defined(CGEOID_H)
#define CGEOID_H 1
#if defined(__cplusplus)
extern "C"
#endif
double HeightAboveEllipsoid(double lat, double lon, double h);
#endif /* CGEOID_H */

View File

@@ -0,0 +1,13 @@
#include <stdio.h>
#include "cgeoid.h"
#if defined(_MSC_VER)
/* Squelch warnings about scanf */
# pragma warning (disable: 4996)
#endif
int main() {
double lat, lon, h;
while(scanf("%lf %lf %lf", &lat, &lon, &h) == 3)
printf("%.3f\n", HeightAboveEllipsoid(lat, lon, h));
}

View File

@@ -0,0 +1,53 @@
cmake_minimum_required (VERSION 3.13.0)
project (cgeodesic)
# Set a default build type for single-configuration cmake generators if
# no build type is set.
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Release)
endif ()
# Make the compiler more picky.
if (MSVC)
string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
string (REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
message (WARNING "This has only been tested on Windows")
endif ()
find_package (GeographicLib 1.51 REQUIRED COMPONENTS SHARED)
set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
add_library (${PROJECT_NAME} SHARED ${PROJECT_NAME}.cpp)
target_link_libraries (${PROJECT_NAME} ${GeographicLib_LIBRARIES})
if (WIN32)
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set (INSTALL_MSG
"copy DLLs fron ${CMAKE_CFG_INTDIR} to C:\\Program Files (x86)\\Microsoft Office\\root\\Office16")
else ()
set (INSTALL_MSG "copy DLLs from ${CMAKE_CFG_INTDIR} to C:\\Program Files\\Microsoft Office\\root\\Office16")
endif ()
elseif (APPLE)
set (INSTALL_MSG "copy DYLIBs from ${CMAKE_CFG_INTDIR} to /Library/Application Support/Microsoft")
endif ()
get_target_property (GEOGRAPHICLIB_LIB_TYPE ${GeographicLib_LIBRARIES} TYPE)
if (GEOGRAPHICLIB_LIB_TYPE STREQUAL "SHARED_LIBRARY")
if (TRUE)
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
COMMAND
${CMAKE_COMMAND} -E
copy $<TARGET_FILE:${GeographicLib_LIBRARIES}> ${CMAKE_CFG_INTDIR}
COMMENT "Installing shared library in build tree
${INSTALL_MSG}")
else ()
# Set the run time path for shared libraries for non-Windows machines.
set_target_properties (${PROJECT_NAME}
PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
endif ()
endif ()

View File

@@ -0,0 +1,132 @@
Attribute VB_Name = "Geodesic"
Option Explicit
' Declare the DLL functions
Private Declare PtrSafe Sub gdirect Lib "cgeodesic.dll" _
(ByVal lat1 As Double, ByVal lon1 As Double, _
ByVal azi1 As Double, ByVal s12 As Double, _
ByRef lat2 As Double, ByRef lon2 As Double, ByRef azi2 As Double)
Private Declare PtrSafe Sub ginverse Lib "cgeodesic.dll" _
(ByVal lat1 As Double, ByVal lon1 As Double, _
ByVal lat2 As Double, ByVal lon2 As Double, _
ByRef s12 As Double, ByRef azi1 As Double, ByRef azi2 As Double)
Private Declare PtrSafe Sub rdirect Lib "cgeodesic.dll" _
(ByVal lat1 As Double, ByVal lon1 As Double, _
ByVal azi12 As Double, ByVal s12 As Double, _
ByRef lat2 As Double, ByRef lon2 As Double)
Private Declare PtrSafe Sub rinverse Lib "cgeodesic.dll" _
(ByVal lat1 As Double, ByVal lon1 As Double, _
ByVal lat2 As Double, ByVal lon2 As Double, _
ByRef s12 As Double, ByRef azi12 As Double)
' Define the custom worksheet functions that call the DLL functions
Function geodesic_direct_lat2(lat1 As Double, lon1 As Double, _
azi1 As Double, s12 As Double) As Double
Attribute geodesic_direct_lat2.VB_Description = _
"Solves direct geodesic problem for lat2."
Dim lat2 As Double
Dim lon2 As Double
Dim azi2 As Double
Call gdirect(lat1, lon1, azi1, s12, lat2, lon2, azi2)
geodesic_direct_lat2 = lat2
End Function
Function geodesic_direct_lon2(lat1 As Double, lon1 As Double, _
azi1 As Double, s12 As Double) As Double
Attribute geodesic_direct_lon2.VB_Description = _
"Solves direct geodesic problem for lon2."
Dim lat2 As Double
Dim lon2 As Double
Dim azi2 As Double
Call gdirect(lat1, lon1, azi1, s12, lat2, lon2, azi2)
geodesic_direct_lon2 = lon2
End Function
Function geodesic_direct_azi2(lat1 As Double, lon1 As Double, _
azi1 As Double, s12 As Double) As Double
Attribute geodesic_direct_azi2.VB_Description = _
"Solves direct geodesic problem for azi2."
Dim lat2 As Double
Dim lon2 As Double
Dim azi2 As Double
Call gdirect(lat1, lon1, azi1, s12, lat2, lon2, azi2)
geodesic_direct_azi2 = azi2
End Function
Function geodesic_inverse_s12(lat1 As Double, lon1 As Double, _
lat2 As Double, lon2 As Double) As Double
Attribute geodesic_inverse_s12.VB_Description = _
"Solves inverse geodesic problem for s12."
Dim s12 As Double
Dim azi1 As Double
Dim azi2 As Double
Call ginverse(lat1, lon1, lat2, lon2, s12, azi1, azi2)
geodesic_inverse_s12 = s12
End Function
Function geodesic_inverse_azi1(lat1 As Double, lon1 As Double, _
lat2 As Double, lon2 As Double) As Double
Attribute geodesic_inverse_azi1.VB_Description = _
"Solves inverse geodesic problem for azi1."
Dim s12 As Double
Dim azi1 As Double
Dim azi2 As Double
Call ginverse(lat1, lon1, lat2, lon2, s12, azi1, azi2)
geodesic_inverse_azi1 = azi1
End Function
Function geodesic_inverse_azi2(lat1 As Double, lon1 As Double, _
lat2 As Double, lon2 As Double) As Double
Attribute geodesic_inverse_azi2.VB_Description = _
"Solves inverse geodesic problem for azi2."
Dim s12 As Double
Dim azi1 As Double
Dim azi2 As Double
Call ginverse(lat1, lon1, lat2, lon2, s12, azi1, azi2)
geodesic_inverse_azi2 = azi2
End Function
Function rhumb_direct_lat2(lat1 As Double, lon1 As Double, _
azi12 As Double, s12 As Double) As Double
Attribute rhumb_direct_lat2.VB_Description = _
"Solves direct rhumb problem for lat2."
Dim lat2 As Double
Dim lon2 As Double
Call rdirect(lat1, lon1, azi12, s12, lat2, lon2)
rhumb_direct_lat2 = lat2
End Function
Function rhumb_direct_lon2(lat1 As Double, lon1 As Double, _
azi12 As Double, s12 As Double) As Double
Attribute rhumb_direct_lon2.VB_Description = _
"Solves direct rhumb problem for lon2."
Dim lat2 As Double
Dim lon2 As Double
Call rdirect(lat1, lon1, azi12, s12, lat2, lon2)
rhumb_direct_lon2 = lon2
End Function
Function rhumb_inverse_s12(lat1 As Double, lon1 As Double, _
lat2 As Double, lon2 As Double) As Double
Attribute rhumb_inverse_s12.VB_Description = _
"Solves inverse rhumb problem for s12."
Dim s12 As Double
Dim azi12 As Double
Call rinverse(lat1, lon1, lat2, lon2, s12, azi12)
rhumb_inverse_s12 = s12
End Function
Function rhumb_inverse_azi12(lat1 As Double, lon1 As Double, _
lat2 As Double, lon2 As Double) As Double
Attribute rhumb_inverse_azi12.VB_Description = _
"Solves inverse rhumb problem for azi12."
Dim s12 As Double
Dim azi12 As Double
Call rinverse(lat1, lon1, lat2, lon2, s12, azi12)
rhumb_inverse_azi12 = azi12
End Function

View File

@@ -0,0 +1,94 @@
# Calling the GeographicLib C++ library from Excel
You can call GeographicLib functions from Excel. Thanks to Thomas
Warner <warnerta@gmail.com>, for showing me how. This prescription
has only been tested for Excel running on a Windows machine. Please
let me know if you figure out how to get this working on MacOS
versions of Excel.
Here's the overview
* Write and compile little interface routines to invoke the
functionality you want.
* Copy the resulting DLLs to where Excel can find them.
* Write an interface script in Visual Basic. This tells Visual Basic
about your interfrace routines and it includes definitions of the actual
functions you will see exposed in Excel.
Here are the step-by-step instructions for compiling and using the
sample routines given here (which solve the direct and inverse geodesic
problems and the corresponding rhumb line problems):
1. Install binary distribution for GeographicLib (either 64-bit or
32-bit to match your version of Excel).
2. Install a recent version of cmake.
3. Start a command prompt window and run
```bash
mkdir BUILD
cd BUILD
cmake -G "Visual Studio 16" -A x64 ..
```
This configures your build. Any of Visual Studio 14, 15, or 16
(corresponding the VS 2015, 2017, 2019) will work. If your Excel is
32-bit, change `-A x64` to `-A win32`. If necessary include `-D
CMAKE_PREFIX_PATH=DIR` to specify where GeographicLib is installed
(specified when you ran the GeographicLib installer). Compile the
interface with
```bash
cmake --build . --config Release
```
4. Copy
```bash
Release\cgeodesic.dll # the interface routines
Release\GeographicLib.dll # the main GeographicLib library
```
to the directory where the Excel executable lives. You can find this
directory by launching Excel, launching Task Manager, right-clicking on
Excel within Task Manager and selecting Open file location. It's
probably something like
```bash
C:\Program Files\Microsoft Office\root\Office16
```
and you will probably need administrator privileges to do the copy.
If it's in `Program Files (x86)`, then you have a 32-bit version of
Excel and you need to compile your interface routines in 32-bit by
specitying `-A win32` when you first run cmake.
5. Open the Excel workbook within which you would like to use the
geodesic and rhumb routines.<br>
Type `Alt-F11` to open Excel's Visual Basic editor.<br>
In the left sidebar, right-click on `VBAProject (%yourworksheetname%)`
and select Import File<br>
Browse to `Geodesic.bas`, select it and click Open<br>
Save your Workbook as Excel Macro-Enabled Workbook (`*.xlsm`)
6. You will now have 10 new functions available:
* Solve the direct geodesic problem for
```
lat2: geodesic_direct_lat2(lat1, lon1, azi1, s12)
lon2: geodesic_direct_lon2(lat1, lon1, azi1, s12)
azi2: geodesic_direct_azi2(lat1, lon1, azi1, s12)
```
* Solve the inverse geodesic problem for
```
s12: geodesic_inverse_s12(lat1, lon1, lat2, lon2)
azi1: geodesic_inverse_azi1(lat1, lon1, lat2, lon2)
azi2: geodesic_inverse_azi2(lat1, lon1, lat2, lon2)
```
* Solve the direct rhumb problem for
```
lat2: rhumb_direct_lat2(lat1, lon1, azi12, s12)
lon2: rhumb_direct_lon2(lat1, lon1, azi12, s12)
```
* Solve the inverse rhumb problem for
```
s12: rhumb_inverse_s12(lat1, lon1, lat2, lon2)
azi12: rhumb_inverse_azi12(lat1, lon1, lat2, lon2)
```
Latitudes, longitudes, and azimuths are in degrees. Distances are
in meters.

View File

@@ -0,0 +1,31 @@
#include "cgeodesic.h"
#include "GeographicLib/Geodesic.hpp"
#include "GeographicLib/Rhumb.hpp"
extern "C" {
void gdirect(double lat1, double lon1, double azi1, double s12,
double& lat2, double& lon2, double& azi2) {
GeographicLib::Geodesic::WGS84().Direct(lat1, lon1, azi1, s12,
lat2, lon2, azi2);
}
void ginverse(double lat1, double lon1, double lat2, double lon2,
double& s12, double& azi1, double& azi2) {
GeographicLib::Geodesic::WGS84().Inverse(lat1, lon1, lat2, lon2,
s12, azi1, azi2);
}
void rdirect(double lat1, double lon1, double azi12, double s12,
double& lat2, double& lon2) {
GeographicLib::Rhumb::WGS84().Direct(lat1, lon1, azi12, s12,
lat2, lon2);
}
void rinverse(double lat1, double lon1, double lat2, double lon2,
double& s12, double& azi12) {
GeographicLib::Rhumb::WGS84().Inverse(lat1, lon1, lat2, lon2,
s12, azi12);
}
}

View File

@@ -0,0 +1,24 @@
#if !defined(CGEODESIC_H)
#define CGEODESIC_H 1
#if defined(__cplusplus)
extern "C" {
#endif
void gdirect(double lat1, double lon1, double azi1, double s12,
double& lat2, double& lon2, double& azi2);
void ginverse(double lat1, double lon1, double lat2, double lon2,
double& s12, double& azi1, double& azi2);
void rdirect(double lat1, double lon1, double azi12, double s12,
double& lat2, double& lon2);
void rinverse(double lat1, double lon1, double lat2, double lon2,
double& s12, double& azi12);
#if defined(__cplusplus)
}
#endif
#endif /* CGEODESIC_H */

View File

@@ -0,0 +1,18 @@
# Calling the GeographicLib C++ library from JavaScript
The geodesic routines in GeographicLib have been implemented in
JavaScript package
[geographiclib-geodesic](https://www.npmjs.com/package/geographiclib-geodesic).
For documentation, see
https://geographiclib.sourceforge.io/JavaScript/doc
William Wall <wallw@users.sourceforge.net> has posted a method of
automatically translating the C++ code into JavaScript
https://sourceforge.net/p/geographiclib/discussion/1026620/thread/f6f6b9ff/
This will let you use other capabilities of GeographicLib in JavaScript.
This is implemented in [OpenSphere
ASM](https://github.com/ngageoint/opensphere-asm).

View File

@@ -0,0 +1,4 @@
*.mexw32
*.mex
*.mexa64
*.mexmaci64

View File

@@ -0,0 +1,49 @@
# Calling GeographicLib C++ library from Octave/MATLAB
The Octave/MATLAB package
[geographiclib](https://github.com/geographiclib/geographiclib-octave#readme)
provides a native Octave/MATLAB implementation of a subset of
GeographicLib. This is also available via the MATLAB Central Package
[geographiclib](https://www.mathworks.com/matlabcentral/fileexchange/50605)
It is also possible to call the C++ GeographicLib library directly
from Octave and MATLAB. This gives you access to the full range of
GeographicLib's capabilities.
In order to make use of this facility, it is necessary to write some
interface code. The files in this directory provide a sample of such
interface code. This example solves the inverse geodesic problem for
ellipsoids with arbitrary flattening. (The code `geoddistance.m` does
this as native Matlab code; but it is limited to ellipsoids with a
smaller flattening.)
For full details on how to write the interface code, see
https://www.mathworks.com/help/matlab/write-cc-mex-files.html
To compile the interface code, start Octave or MATLAB and run, e.g.,
```Octave
mex -setup C++
help geographiclibinterface
geographiclibinterface
help geodesicinverse
geodesicinverse([40.6, -73.8, 51.6, -0.5])
ans =
5.1199e+01 1.0782e+02 5.5518e+06
```
The first command allows you to select the compiler to use (which should
be the same as that used to compile GeographicLib).
These routines just offer a simple interface to the corresponding C++
class. Use the help function to get documentation,
```Octave
help geodesicinverse
```
Unfortunately, the help function does not work for compiled functions in
Octave; in this case, just list the .m file, e.g.,
```Octave
type geodesicinverse.m
```

View File

@@ -0,0 +1,116 @@
/**
* \file geodesicinverse.cpp
* \brief Matlab mex file for geographic to UTM/UPS conversions
*
* Copyright (c) Charles Karney (2010-2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
// Compile in Matlab with
// [Unix]
// mex -I/usr/local/include -L/usr/local/lib -Wl,-rpath=/usr/local/lib
// -lGeographicLib geodesicinverse.cpp
// [Windows]
// mex -I../include -L../windows/Release
// -lGeographicLib geodesicinverse.cpp
#include <algorithm>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/GeodesicExact.hpp>
#include <mex.h>
using namespace std;
using namespace GeographicLib;
template<class G> void
compute(double a, double f, mwSize m, const double* latlong,
double* geodesic, double* aux) {
const double* lat1 = latlong;
const double* lon1 = latlong + m;
const double* lat2 = latlong + 2*m;
const double* lon2 = latlong + 3*m;
double* azi1 = geodesic;
double* azi2 = geodesic + m;
double* s12 = geodesic + 2*m;
double* a12 = NULL;
double* m12 = NULL;
double* M12 = NULL;
double* M21 = NULL;
double* S12 = NULL;
if (aux) {
a12 = aux;
m12 = aux + m;
M12 = aux + 2*m;
M21 = aux + 3*m;
S12 = aux + 4*m;
}
const G g(a, f);
for (mwIndex i = 0; i < m; ++i) {
if (abs(lat1[i]) <= 90 && lon1[i] >= -540 && lon1[i] < 540 &&
abs(lat2[i]) <= 90 && lon2[i] >= -540 && lon2[i] < 540) {
if (aux)
a12[i] = g.Inverse(lat1[i], lon1[i], lat2[i], lon2[i],
s12[i], azi1[i], azi2[i],
m12[i], M12[i], M21[i], S12[i]);
else
g.Inverse(lat1[i], lon1[i], lat2[i], lon2[i],
s12[i], azi1[i], azi2[i]);
}
}
}
void mexFunction( int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[] ) {
if (nrhs < 1)
mexErrMsgTxt("One input argument required.");
else if (nrhs > 3)
mexErrMsgTxt("More than three input arguments specified.");
else if (nrhs == 2)
mexErrMsgTxt("Must specify flattening with the equatorial radius.");
else if (nlhs > 2)
mexErrMsgTxt("More than two output arguments specified.");
if (!( mxIsDouble(prhs[0]) && !mxIsComplex(prhs[0]) ))
mexErrMsgTxt("latlong coordinates are not of type double.");
if (mxGetN(prhs[0]) != 4)
mexErrMsgTxt("latlong coordinates must be M x 4 matrix.");
double a = Constants::WGS84_a<double>(), f = Constants::WGS84_f<double>();
if (nrhs == 3) {
if (!( mxIsDouble(prhs[1]) && !mxIsComplex(prhs[1]) &&
mxGetNumberOfElements(prhs[1]) == 1 ))
mexErrMsgTxt("Equatorial radius is not a real scalar.");
a = mxGetScalar(prhs[1]);
if (!( mxIsDouble(prhs[2]) && !mxIsComplex(prhs[2]) &&
mxGetNumberOfElements(prhs[2]) == 1 ))
mexErrMsgTxt("Flattening is not a real scalar.");
f = mxGetScalar(prhs[2]);
}
mwSize m = mxGetM(prhs[0]);
const double* latlong = mxGetPr(prhs[0]);
double* geodesic = mxGetPr(plhs[0] = mxCreateDoubleMatrix(m, 3, mxREAL));
std::fill(geodesic, geodesic + 3*m, Math::NaN<double>());
double* aux =
nlhs == 2 ? mxGetPr(plhs[1] = mxCreateDoubleMatrix(m, 5, mxREAL)) :
NULL;
if (aux)
std::fill(aux, aux + 5*m, Math::NaN<double>());
try {
if (std::abs(f) <= 0.02)
compute<Geodesic>(a, f, m, latlong, geodesic, aux);
else
compute<GeodesicExact>(a, f, m, latlong, geodesic, aux);
}
catch (const std::exception& e) {
mexErrMsgTxt(e.what());
}
}

View File

@@ -0,0 +1,33 @@
function geodesicinverse(~, ~, ~)
%geodesicinverse Solve inverse geodesic problem
%
% [geodesic, aux] = geodesicinverse(latlong)
% [geodesic, aux] = geodesicinverse(latlong, a, f)
%
% latlong is an M x 4 matrix
% latitude of point 1 = latlong(:,1) in degrees
% longitude of point 1 = latlong(:,2) in degrees
% latitude of point 2 = latlong(:,3) in degrees
% longitude of point 2 = latlong(:,4) in degrees
%
% geodesic is an M x 3 matrix
% azimuth at point 1 = geodesic(:,1) in degrees
% azimuth at point 2 = geodesic(:,2) in degrees
% distance between points 1 and 2 = geodesic(:,3) in meters
% aux is an M x 5 matrix
% spherical arc length = aux(:,1) in degrees
% reduced length = aux(:,2) in meters
% geodesic scale 1 to 2 = aux(:,3)
% geodesic scale 2 to 1 = aux(:,4)
% area under geodesic = aux(:,5) in meters^2
%
% a = equatorial radius (meters)
% f = flattening (0 means a sphere)
% If a and f are omitted, the WGS84 values are used.
%
% A native MATLAB implementation is available as GEODDISTANCE.
%
% See also GEODDISTANCE.
error('Error: executing .m file instead of compiled routine');
end

View File

@@ -0,0 +1,63 @@
function geographiclibinterface(incdir, libdir)
% geographiclibinterface Use mex to compile interface to GeographicLib
%
% geographiclibinterface
% geographiclibinterface(INSTALLDIR)
% geographiclibinterface(INCDIR, LIBDIR)
%
% With one argument the library is looked for in INSTALLDIR/lib and the
% include files in INSTALLDIR/include.
%
% With no arguments, INSTALLDIR is taked to be '/usr/local', on Unix and
% Linux systems, and 'C:/Program Files/GeographicLib', on Windows systems
%
% With two arguments, the library is looked for in LIBDIR and the include
% files in INCDIR.
%
% This has been tested with
%
% Octave 3.2.3 and g++ 4.4.4 under Linux
% Octave 3.6.4 and g++ 4.8.3 under Linux
% Matlab 2007a and Visual Studio 2005 under Windows
% Matlab 2008a and Visual Studio 2005 under Windows
% Matlab 2008a and Visual Studio 2008 under Windows
% Matlab 2010b and Visual Studio 2005 under Windows
% Matlab 2010b and Visual Studio 2008 under Windows
% Matlab 2010b and Visual Studio 2010 under Windows
% Matlab 2013b and Visual Studio 2012 under Windows
% Matlab 2014b and Mac OSX 10.10 (Yosemite)
%
% Run 'mex -setup' to configure the C++ compiler for Matlab to use.
funs = { 'geodesicinverse' };
lib='GeographicLib';
if (nargin < 2)
if (nargin == 0)
if ispc
installdir = 'C:/Program Files/GeographicLib';
else
installdir = '/usr/local';
end
else
installdir = incdir;
end
incdir=[installdir '/include'];
libdir=[installdir '/lib'];
end
testheader = [incdir '/GeographicLib/Constants.hpp'];
if (~ exist(testheader, 'file'))
error(['Cannot find ' testheader]);
end
fprintf('Compiling Matlab interface to GeographicLib\n');
fprintf('Include directory: %s\nLibrary directory: %s\n', incdir, libdir);
for i = 1:size(funs,2)
fprintf('Compiling %s...', funs{i});
if ispc || ismac
mex( ['-I' incdir], ['-L' libdir], ['-l' lib], [funs{i} '.cpp'] );
else
mex( ['-I' incdir], ['-L' libdir], ['-l' lib], ...
['-Wl,-rpath=' libdir], [funs{i} '.cpp'] );
end
fprintf(' done.\n');
end
end

View File

@@ -0,0 +1,57 @@
cmake_minimum_required (VERSION 3.13.0)
project (PyGeographicLib)
# Set a default build type for single-configuration cmake generators if
# no build type is set.
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Release)
endif ()
# Make the compiler more picky.
if (MSVC)
string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
endif ()
# The version of python that boost-python uses. Also used for the
# installation directory.
set (PYTHON_VERSION 2.7)
# Requires python + python devel
find_package (PythonLibs ${PYTHON_VERSION} REQUIRED)
# Required boost-python + boost-devel
find_package (Boost REQUIRED COMPONENTS python)
find_package (GeographicLib REQUIRED COMPONENTS SHARED)
include_directories (${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
add_library (${PROJECT_NAME} MODULE ${PROJECT_NAME}.cpp)
get_target_property (GEOGRAPHICLIB_LIB_TYPE ${GeographicLib_LIBRARIES} TYPE)
if (GEOGRAPHICLIB_LIB_TYPE STREQUAL "SHARED_LIBRARY")
if (WIN32)
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
COMMAND
${CMAKE_COMMAND} -E
copy $<TARGET_FILE:${GeographicLib_LIBRARIES}> ${CMAKE_CFG_INTDIR}
COMMENT "Installing shared library in build tree")
else ()
# Set the run time path for shared libraries for non-Windows machines.
set_target_properties (${PROJECT_NAME}
PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
endif ()
endif ()
# Don't include the "lib" prefix on the output name
set_target_properties (${PROJECT_NAME} PROPERTIES PREFIX "")
target_link_libraries (${PROJECT_NAME} ${GeographicLib_LIBRARIES}
${Boost_LIBRARIES} ${PYTHON_LIBRARIES})
install (TARGETS ${PROJECT_NAME} LIBRARY
# if CMAKE_INSTALL_PREFIX=~/.local then this specifies a directory in
# the default path.
DESTINATION lib/python${PYTHON_VERSION}/site-packages)

View File

@@ -0,0 +1,21 @@
#include <boost/python.hpp>
#include <GeographicLib/Geoid.hpp>
using namespace boost::python;
using namespace GeographicLib;
double EllipsoidHeight(Geoid& geoid,
double lat, double lon, double hmsl) {
return hmsl + Geoid::GEOIDTOELLIPSOID * geoid(lat, lon);
}
BOOST_PYTHON_MODULE(PyGeographicLib) {
class_<Geoid, boost::noncopyable>("Geoid", init<std::string>())
.def("EllipsoidHeight", &EllipsoidHeight,
"Return geoid height:\n\
input: lat, lon, height_above_geoid\n\
output: height_above_ellipsoid")
;
}

View File

@@ -0,0 +1,85 @@
# Calling the GeographicLib C++ library from Python
The geodesic routines in GeographicLib have been implemented as a
[native Python library](http://pypi.python.org/pypi/geographiclib).
For documentation see
https://geographiclib.sourceforge.io/Python/doc/
## boost-python
It is also possible to call the C++ version of GeographicLib directly
from Python and this directory contains a small example,
`PyGeographicLib.cpp`, which uses boost-python and the `Geoid` class to
convert heights above the geoid to heights above the ellipsoid. More
information on calling boost-python, see
https://www.boost.org/doc/libs/release/libs/python
To build and install this interface, do
```bash
mkdir BUILD
cd BUILD
cmake -D CMAKE_INSTALL_PREFIX=~/.local ..
make
make install
```
This assumes that you have installed GeographicLib somewhere that cmake
can find it. If you want just to use the version of GeographicLib that
you have built in the top-level BUILD directory, include, e.g.,
```bash
-D GeographicLib_DIR=../../BUILD
```
in the invocation of cmake (the directory is relative to the source
directory, wrapper/python).
`make install` installs PyGeographicLib in
```
~/.local/lib/python2.7/site-packages
```
which is in the default search path for python 2.7. To convert 20m
above the geoid at 42N 75W to a height above the ellipsoid, do
```python
$ python
>>> from PyGeographicLib import Geoid
>>> geoid = Geoid("egm2008-1")
>>> geoid.EllipsoidHeight(42, -75, 20)
-10.671887499999997
>>> help(Geoid.EllipsoidHeight)
```
Notes:
* The geoid data (`egm2008-1`) should be installed somewhere that
GeographicLib knows about.
* This prescription applies to Linux machines. Similar steps can be
used on Windows and MacOSX machines.
* You will need the packages boost-python, boost-devel, python, and
python-devel installed.
* `CMakeLists.txt` specifies the version of python to look for (version
2.7). This must match that used in boost-python. To check do, e.g.,
```bash
ldd /usr/lib64/libboost_python.so
```
* `CMakeLists.txt` looks for a shared-library version of GeographicLib.
This is the default with cmake build on non-Windows platforms. On
Windows, use the cmake option `-D BUILD_SHARED_LIBS=ON` to specify
building a shared library.
Acknowledgment:
Thanks to Jonathan Takahashi <jtakahashi@gmail.com> for the sample code
in PyGeographicLib.cpp and the commands needed to compile and link this.
## Cython
An alternative to boost-python is provided by [Cython](https::/cython.org).
Sergey Serebryakov offers the github project
https://github.com/megaserg/geographiclib-cython-bindings
which provides a fast python interface to the geodesic routines.