From fa6b6d00a4f03f0475ba92f9694eb1df959238da Mon Sep 17 00:00:00 2001 From: cbwu Date: Wed, 12 Jul 2023 14:32:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=80=9A=E8=A7=86=E5=88=86?= =?UTF-8?q?=E6=9E=90=E5=87=BD=E6=95=B0=EF=BC=9B=E6=96=B0=E5=A2=9E=E7=AC=AC?= =?UTF-8?q?=E4=B8=89=E6=96=B9=E5=BA=93=E5=9C=B0=E7=90=86=E8=B7=9D=E7=A6=BB?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E5=BA=93Erkir=EF=BC=8C=E5=88=A9=E7=94=A8?= =?UTF-8?q?=E8=AF=A5=E5=BA=93=E5=B0=81=E8=A3=85=E4=BA=86=E4=B8=A4=E4=B8=AA?= =?UTF-8?q?=E8=B7=9D=E7=A6=BB=E5=87=BD=E6=95=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MapDisplay.pro | 8 + MapDisplay.pro.user | 4 +- bin/bin_x64/erkir.dll | Bin 0 -> 49152 bytes bin/bind_x64/erkird.dll | Bin 0 -> 217600 bytes geocomputation.cpp | 39 ++++- geocomputation.h | 7 + geospatialanalysis.cpp | 62 +++++++ geospatialanalysis.h | 32 ++++ include/erkir/README.md | 148 ++++++++++++++++ include/erkir/cartesianpoint.h | 86 ++++++++++ include/erkir/coordinate.h | 89 ++++++++++ include/erkir/datum.h | 120 +++++++++++++ include/erkir/ellipsoidalpoint.h | 198 +++++++++++++++++++++ include/erkir/export.h | 14 ++ include/erkir/point.h | 70 ++++++++ include/erkir/sphericalpoint.h | 285 +++++++++++++++++++++++++++++++ include/erkir/vector3d.h | 156 +++++++++++++++++ lib/lib_x64/erkir.lib | Bin 0 -> 32590 bytes lib/libd_x64/erkird.lib | Bin 0 -> 32662 bytes mainwindow.cpp | 32 +++- mapdatamaneger.cpp | 2 + 21 files changed, 1340 insertions(+), 12 deletions(-) create mode 100644 bin/bin_x64/erkir.dll create mode 100644 bin/bind_x64/erkird.dll create mode 100644 geospatialanalysis.cpp create mode 100644 geospatialanalysis.h create mode 100644 include/erkir/README.md create mode 100644 include/erkir/cartesianpoint.h create mode 100644 include/erkir/coordinate.h create mode 100644 include/erkir/datum.h create mode 100644 include/erkir/ellipsoidalpoint.h create mode 100644 include/erkir/export.h create mode 100644 include/erkir/point.h create mode 100644 include/erkir/sphericalpoint.h create mode 100644 include/erkir/vector3d.h create mode 100644 lib/lib_x64/erkir.lib create mode 100644 lib/libd_x64/erkird.lib diff --git a/MapDisplay.pro b/MapDisplay.pro index 1ae3afd6..ad85b646 100644 --- a/MapDisplay.pro +++ b/MapDisplay.pro @@ -18,6 +18,7 @@ SOURCES += \ geocomputation.cpp \ geofeatureoperator.cpp \ geofileparser.cpp \ + geospatialanalysis.cpp \ icons.cpp \ importscenedatadialog.cpp \ layeroperator.cpp \ @@ -57,6 +58,7 @@ HEADERS += \ geocomputation.h \ geofeatureoperator.h \ geofileparser.h \ + geospatialanalysis.h \ icons.h \ importscenedatadialog.h \ layeroperator.h \ @@ -114,6 +116,7 @@ DEFINES += _HAS_STD_BYTE=0 INCLUDEPATH += "../../include" INCLUDEPATH += "../../include/private" INCLUDEPATH += "../../sample/extensions4Qt" +INCLUDEPATH += "./include" #附加库(目录以L标记,附加库名以l标记) win32{ @@ -125,6 +128,7 @@ win32{ contains(QMAKE_HOST.arch, x86_64){ DESTDIR = "../../sample/debug/x64" LIBS += -L"../../sample/debug/x64" -lExtensions4Qt + LIBS += -L"$$PWD/lib/libd_x64" -lerkird LIBPATH = "../../lib/libd_x64" } LIBS += -lSuToolkitd \ @@ -163,6 +167,7 @@ win32{ -lSuSymbolMarker3Dd\ -lSuLayer3DFiled\ -lSuLayer3DTreed\ + -lSuGridAnalystd\ # -lSuFileParserGLTFd\ }else:CONFIG(release, debug|release){ @@ -170,10 +175,12 @@ win32{ contains(QMAKE_HOST.arch, x86_64){ DESTDIR = "../../sample/release/x64" LIBS += -L"../../sample/release/x64" -lExtensions4Qt + LIBS += -L"$$PWD/lib/lib_x64" -lerkir LIBPATH = "../../lib/lib_x64" }else{ DESTDIR = "../release/x86" LIBS += -L"../release/x86" -lExtensions4Qt + LIBS += -L"$$PWD/lib/lib_x64" -lerkir LIBPATH = "../../lib/lib" } LIBS += -lSuToolkit \ @@ -211,6 +218,7 @@ win32{ -lSuSymbolMarker3D\ -lSuLayer3DFile\ -lSuLayer3DTree\ + -lSuGridAnalyst\ # -lSuFileParserGLTF\ } } diff --git a/MapDisplay.pro.user b/MapDisplay.pro.user index a7f7efeb..b4847440 100644 --- a/MapDisplay.pro.user +++ b/MapDisplay.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -174,7 +174,7 @@ false - Path=D:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.36.32532\bin\HostX64\x64;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\VC\VCPackages;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\TestWindow;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;D:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\bin\Roslyn;D:\Program Files\Microsoft Visual Studio\2022\Professional\Team Tools\Performance Tools\x64;D:\Program Files\Microsoft Visual Studio\2022\Professional\Team Tools\Performance Tools;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\\x64;C:\Program Files (x86)\Windows Kits\10\bin\\x64;D:\Program Files\Microsoft Visual Studio\2022\Professional\\MSBuild\Current\Bin\amd64;C:\Windows\Microsoft.NET\Framework64\v4.0.30319;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\Tools\;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\libnvvp;D:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;D:\Java\jdk1.8.0_361\bin;D:\Java\jdk1.8.0_361\jre\bin;D:\Program Files\nodejs\node_global;D:\Qt\5.15.2\msvc2019_64\bin;D:\Qt\5.15.2\mingw81_64\bin;D:\Qt\Tools\mingw810_64\bin;D:\Anaconda3;D:\Anaconda3\Scripts;D:\Anaconda3\Library\bin;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\lib;D:\Program Files\CMake\bin;D:\Program Files\nodejs\;D:\Program Files\Git\cmd;C:\Users\wuche\AppData\Local\Microsoft\WindowsApps;D:\Program Files\Microsoft VS Code\bin;C:\Users\wuche\AppData\Roaming\npm;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\VC\Linux\bin\ConnectionManagerExe;D:\supermap-iobjectscpp\bin\bin_x64;D:\supermap-iobjectscpp\bin\bind_x64 + Path=D:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.36.32532\bin\HostX64\x64;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\VC\VCPackages;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\TestWindow;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;D:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\bin\Roslyn;D:\Program Files\Microsoft Visual Studio\2022\Professional\Team Tools\Performance Tools\x64;D:\Program Files\Microsoft Visual Studio\2022\Professional\Team Tools\Performance Tools;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\\x64;C:\Program Files (x86)\Windows Kits\10\bin\\x64;D:\Program Files\Microsoft Visual Studio\2022\Professional\\MSBuild\Current\Bin\amd64;C:\Windows\Microsoft.NET\Framework64\v4.0.30319;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\Tools\;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\libnvvp;D:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;D:\Java\jdk1.8.0_361\bin;D:\Java\jdk1.8.0_361\jre\bin;D:\Program Files\nodejs\node_global;D:\Qt\5.15.2\msvc2019_64\bin;D:\Qt\5.15.2\mingw81_64\bin;D:\Qt\Tools\mingw810_64\bin;D:\Anaconda3;D:\Anaconda3\Scripts;D:\Anaconda3\Library\bin;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\lib;D:\Program Files\CMake\bin;D:\Program Files\nodejs\;D:\Program Files\Git\cmd;C:\Users\wuche\AppData\Local\Microsoft\WindowsApps;D:\Program Files\Microsoft VS Code\bin;C:\Users\wuche\AppData\Roaming\npm;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\VC\Linux\bin\ConnectionManagerExe;D:\supermap-iobjectscpp\bin\bin_x64;D:\supermap-iobjectscpp\bin\bind_x64;D:\supermap-iobjectscpp\MyProject\MapDisplay\bin\bin_x64;D:\supermap-iobjectscpp\MyProject\MapDisplay\bin\bind_x64 __VSCMD_PREINIT_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\libnvvp;D:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;D:\Java\jdk1.8.0_361\bin;D:\Java\jdk1.8.0_361\jre\bin;D:\Program Files\nodejs\node_global;D:\Qt\5.15.2\msvc2019_64\bin;D:\Qt\5.15.2\mingw81_64\bin;D:\Qt\Tools\mingw810_64\bin;D:\Anaconda3;D:\Anaconda3\Scripts;D:\Anaconda3\Library\bin;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\lib;D:\Program Files\CMake\bin;D:\Program Files\nodejs\;D:\Program Files\Git\cmd;C:\Users\wuche\AppData\Local\Microsoft\WindowsApps;D:\Program Files\Microsoft VS Code\bin;C:\Users\wuche\AppData\Roaming\npm;D:\supermap-iobjectscpp\bin\bin_x64 Release diff --git a/bin/bin_x64/erkir.dll b/bin/bin_x64/erkir.dll new file mode 100644 index 0000000000000000000000000000000000000000..b08dd8ca0734e490bbf4406bf305e65617aaf02a GIT binary patch literal 49152 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%0DbFEm-M+&%7$K@WUFu&|ex{ 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 literal 0 HcmV?d00001 diff --git a/geocomputation.cpp b/geocomputation.cpp index 01dfd0ee..62372931 100644 --- a/geocomputation.cpp +++ b/geocomputation.cpp @@ -1,18 +1,47 @@ #include "geocomputation.h" #include "Stream/ugdefs.h" +#include "erkir/sphericalpoint.h" + GeoComputation::GeoComputation() { } +/*@brief 计算两点间球面距离 + * @param lon1(-180至180),lat1(-90到90) 经纬度点1(度) + * @param lon2,lat3 经纬度点2(度) + * @return 距离(m) + */ +double GeoComputation::getSphericalDistance(double lon1, double lat1, double lon2, double lat2) +{ + erkir::spherical::Point p1{ lat1, lon1 }; + erkir::spherical::Point p2{ lat2, lon2 }; + double distance = p1.distanceTo(p2); + return distance; +} + +/*@brief 根据起点坐标、方位角、距离,计算另一点坐标。 +* startPoint:起始点地理坐标点(lat(-90到90),lon(-180,180)) +* bearing:方位角(0-360)(度) +* dist:两点之间距离(m) +*/ +QPointF GeoComputation::getDestinationPoint(double lon1, double lat1, double bearing, double dist) +{ + erkir::spherical::Point p{ lat1, lon1 }; + auto dest = p.destinationPoint(dist, bearing); // 51.5135°N, 000.0983°W + QPointF point(dest.longitude().degrees(),dest.latitude().degrees()); + return point; +} + +/*@brief 根据起点坐标、方位角、距离,计算另一点坐标。 +* 使用Vincenty's公式求解,使用WGS-84椭球 +* startPoint:起始点地理坐标点(lat(-90到90),lon(-180,180)) +* bearing:方位角(度) +* dist:两点之间距离(km) +*/ QPointF GeoComputation::computeOffsetGeoPosition(double lon1, double lat1, double bearing, double dist) { - /*使用Vincenty's公式求解 - * startPoint:起始点地理坐标点(lat(-90到90),lon(-180,180)) - * bearing:方位角(度) - * dist:两点之间距离(km) - */ QPointF endPoint; //角度转化为弧度 // qreal lon1 = (fmod(startPoint.x()+540,360)-180.0)*PI/180; diff --git a/geocomputation.h b/geocomputation.h index a0015fc2..e1386d81 100644 --- a/geocomputation.h +++ b/geocomputation.h @@ -11,9 +11,16 @@ class GeoComputation public: GeoComputation(); + //计算两点间球面距离 + double getSphericalDistance(double lon1, double lat1,double lon2, double lat2); + + //根据起始点、距离、方向角计算目标点坐标 + QPointF getDestinationPoint(double lon1, double lat1, double bearing, double dist); + QPointF computeOffsetGeoPosition(double lon1, double lat1, double bearing, double dist); UGPoint2D DPtoMP(UGMap* pMap, const QPoint &point); //显示坐标转地图坐标 + }; #endif // GEOCOMPUTATION_H diff --git a/geospatialanalysis.cpp b/geospatialanalysis.cpp new file mode 100644 index 00000000..205223ec --- /dev/null +++ b/geospatialanalysis.cpp @@ -0,0 +1,62 @@ + +#include "geospatialanalysis.h" +#include + +GeoSpatialAnalysis::GeoSpatialAnalysis() +{ + +} + +/*@brief 两点间的可视性 + * @param pntView 观察点 + * @param pntObject 目标点 + */ +UG3DAnalyst::SingleResult *GeoSpatialAnalysis::DoublePointVisibility(QMapControl* pMapControl,UGPoint2D pntView, UGPoint2D pntObject) +{ + //通过下面的方法首先判断点所在的位置是否存在高程数据; + UGDatasetRasterPtr viewPtDataset = pMapControl->getDemDataSet(pntView); + UGDatasetRasterPtr objectPtDataset = pMapControl->getDemDataSet(pntObject); + + if(viewPtDataset == NULL || objectPtDataset == NULL) + { + QMessageBox::about(NULL,"提示","无高程数据 "); + return NULL;//-1 + } + + if(viewPtDataset != objectPtDataset) + { + QMessageBox::about(NULL,"提示","观测点与被观测点不属于同一个高程数据集 "); + return NULL;//-1 + } + + UGDatasetRasterPtr datasetRaster = viewPtDataset; + + //3D分析分析实例对象 + UG3DAnalyst visAnalsyt; + UGPoint3D pntView3D,pntObject3D; + + //高程值需根据x,y查询数据集得到 + //得到当前测量点的高程值 + // 1.首先将坐标点转换为栅格数据集对应的行和列 + UGPoint pntviewImg; + double altitude; + datasetRaster->XYToImg(pntView,pntviewImg); + altitude = datasetRaster->GetValue(pntviewImg.x,pntviewImg.y); + pntView3D.x = pntView.x; + pntView3D.y = pntView.y; + pntView3D.z = altitude; + + UGPoint pntObjectImg; + //坐标点转换为栅格数据集对应的行和列 + datasetRaster->XYToImg(pntObject,pntObjectImg); + altitude = datasetRaster->GetValue(pntObjectImg.x,pntObjectImg.y); + pntObject3D.x = pntObject.x; + pntObject3D.y = pntObject.y; + pntObject3D.z = altitude; + + //进行通视分析查询; + UG3DAnalyst::SingleResult* result = visAnalsyt.IsVisible(datasetRaster,pntView3D,pntObject3D); + + return result; + +} diff --git a/geospatialanalysis.h b/geospatialanalysis.h new file mode 100644 index 00000000..65a83bc1 --- /dev/null +++ b/geospatialanalysis.h @@ -0,0 +1,32 @@ +#ifndef GEOSPATIALANALYSIS_H +#define GEOSPATIALANALYSIS_H +/* + * @cbwu + * @brief 空间分析类,实现各种空间分析算法 + */ + +#include "qmapcontrol.h" +#include "Engine/UGDataset.h" +#include "GridAnalyst/UG3DAnalyst.h" + +using namespace UGC; + +//MSVC编译器界面显示乱码问题 +#if _MSC_VER >= 1600 +#pragma execution_character_set("utf-8") +#endif + +class GeoSpatialAnalysis +{ +public: + GeoSpatialAnalysis(); + + //两点间的可视性 + UG3DAnalyst::SingleResult* DoublePointVisibility(QMapControl* pMapControl,UGPoint2D pntView, UGPoint2D pntObject); + +private: + + +}; + +#endif // GEOSPATIALANALYSIS_H diff --git a/include/erkir/README.md b/include/erkir/README.md new file mode 100644 index 00000000..2c22a23d --- /dev/null +++ b/include/erkir/README.md @@ -0,0 +1,148 @@ +# Երկիր (Erkir) - a C++ library for geodesic and trigonometric calculations + +[Erkir (armenian: Երկիր, means Earth)](https://github.com/vahancho/erkir) - is inspired +by and based on the great work of [Chris Veness](https://github.com/chrisveness), +the owner of the [Geodesy functions](https://github.com/chrisveness/geodesy) +project - provides a set of comprehensive API for geodesic and trigonometric calculations. +I would call it a C++ port of JavaScript functions provided by the mentioned Chris Veness' project, +however I designed the library to be more object oriented. Thus the code is organized a +little bit differently, but the implementation itself is preserved. + +[![Latest release](https://img.shields.io/github/v/release/vahancho/erkir?include_prereleases)](https://github.com/vahancho/erkir/releases) +[![Test (CMake)](https://github.com/vahancho/erkir/actions/workflows/cmake.yml/badge.svg)](https://github.com/vahancho/erkir/actions/workflows/cmake.yml) +[![codecov](https://codecov.io/gh/vahancho/erkir/branch/master/graph/badge.svg)](https://codecov.io/gh/vahancho/erkir) + +### Prerequisites + +There are no special requirements and dependencies except *C++11* compliant compiler. +The class is tested with *gcc 4.8.4* and *MSVC 15.x* (Visual Studio 2017). +The library is written with pure STL without any third party dependencies. +For more details see the CI badges (*GitHub Actions*) above. + +### Installation + +No installation required. Just incorporate header files from the *include/* and +source files from *src/* directories in your project and compile them. All library +classes are in *erkir* namespace. + +#### Integration with `CMake` projects + +However, if you use `CMake` and want to integrate the library into your project +you might want to install it first by invoking a `CMake` command from the build directory: + +``` +cmake --install . --prefix= --config=Release +``` + +Once the library is installed you can use it from in your project by adjusting its +`CMake` script. For example: + +``` +[..] +find_package(erkir REQUIRED) + +add_executable(example main.cpp) +target_link_libraries(example erkir) +[..] +``` + +### The API + +The code is virtually split into three domains (namespaces) that represent spherical +and ellipsoidal geodetic coordinates and cartesian (x/y/z) for geocentric ones: +`erkir::spherical`, `erkir::ellipsoidal` and `erkir::cartesian` correspondingly. +Spherical Earth model based calculations are accurate enough for most cases, however +in order to gain more precise measurements use `erkir::ellipsoidal` classes. + +`erkir::spherical::Point` class implements geodetic point on the basis of a spherical +earth (ignoring ellipsoidal effects). It uses formulae to calculate distances between +two points (using haversine formula), initial bearing from a point, final bearing to a point, etc. + +`erkir::ellipsoidal::Point` class represents geodetic point based on ellipsoidal +earth model. It includes ellipsoid parameters and datums for different coordinate +systems, and methods for converting between them and to Cartesian coordinates. + +`erkir::Vector3d` implements 3-d vector manipulation routines. With this class you +can perform basic operations with the vectors, such as calculate dot (scalar) product +of two vectors, multiply vectors, add and subtract them. + +`erkir::cartesian::Point` implements ECEF (earth-centered earth-fixed) geocentric +cartesian (x/y/z) coordinates. + +### Usage Examples: + +```cpp +#include "sphericalpoint.h" +#include "ellipsoidalpoint.h" + +int main(int argc, char **argv) +{ + // Calculate great-circle distance between two points. + erkir::spherical::Point p1{ 52.205, 0.119 }; + erkir::spherical::Point p2{ 48.857, 2.351 }; + auto d = p1.distanceTo(p2); // 404.3 km + + // Get destination point by given distance (shortest) and bearing from start point. + erkir::spherical::Point p3{ 51.4778, -0.0015 }; + auto dest = p3.destinationPoint(7794.0, 300.7); // 51.5135°N, 000.0983°W + + // Convert a point from one coordinates system to another. + erkir::ellipsoidal::Point pWGS84(51.4778, -0.0016, ellipsoidal::Datum::Type::WGS84); + auto pOSGB = pWGS84.toDatum(ellipsoidal::Datum::Type::OSGB36); // 51.4778°N, 000.0000°E + + // Convert to Cartesian coordinates. + auto cartesian = pWGS84.toCartesianPoint(); + + // Convert Cartesian point to a geodetic one. + auto geoPoint = cartesian->toGeoPoint(); + + return 0; +} +``` + +For more usage examples please refer to the unit tests at `/test/test.cpp` file. + +### Building and Testing + +There are unit tests. You can find them in the *test/* directory. +To run them you have to build and run the test application. For doing that you must invoke the following +commands from the terminal, assuming that compiler and environment are already configured: + +#### Linux (gcc) + +``` +mkdir build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTING=True +cmake --build . +ctest +``` + +#### Windows (MSVC Toolchain) + +``` +mkdir build && cd build +cmake .. -DENABLE_TESTING=True -A x64 +cmake --build . --config=Release +ctest -C Release +``` + +For x86 builds use `-A Win32` option instead. + +### Performance Tests + +I measured performance (on Intel Core i5 series processor) for some spherical geodesy +functions (`Point` class). I used similar approach as Chris Veness did in his tests, +i.e. called functions for 5000 random points or pairs of points. And here are my results: + +| Function | Avg. time/calculation (nanoseconds)| +| -------------------- |:----------------------------------:| +| Distance (haversine) | 162 | +| Initial bearing | 190 | +| Destination point | 227 | + +*of course timings are machine dependent* + +## See Also + +* [Movable Type Scripts Latitude/Longitude Calculations Reference](http://www.movable-type.co.uk/scripts/latlong.html) + diff --git a/include/erkir/cartesianpoint.h b/include/erkir/cartesianpoint.h new file mode 100644 index 00000000..bb1c5567 --- /dev/null +++ b/include/erkir/cartesianpoint.h @@ -0,0 +1,86 @@ +/********************************************************************************** +* MIT License * +* * +* Copyright (c) 2020 Vahan Aghajanyan * +* * +* Geodesy tools for conversions between (historical) datums * +* (c) Chris Veness 2005-2019 * +* www.movable-type.co.uk/scripts/latlong-convert-coords.html * +* www.movable-type.co.uk/scripts/geodesy-library.html#latlon-ellipsoidal-datum * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy * +* of this software and associated documentation files (the "Software"), to deal * +* in the Software without restriction, including without limitation the rights * +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * +* copies of the Software, and to permit persons to whom the Software is * +* furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in all * +* copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * +* SOFTWARE. * +***********************************************************************************/ + +#ifndef CARTESIAN_POINT_H +#define CARTESIAN_POINT_H + +#include "datum.h" +#include "vector3d.h" + +#include + +namespace erkir +{ + +namespace ellipsoidal +{ + class Point; +} + +namespace cartesian +{ + +/// ECEF (earth-centered earth-fixed) geocentric Cartesian coordinates. +class ERKIR_EXPORT Point : public Vector3d +{ +public: + /// Creates Cartesian coordinate representing ECEF (earth-centric earth-fixed) point. + /*! + \param x X coordinate in metres (=> 0°N,0°E). + \param y Y coordinate in metres (=> 0°N,90°E). + \param z Z coordinate in metres (=> 90°N). + + \example auto coord = Cartesian(3980581.210, -111.159, 4966824.522); + */ + Point(double x, double y, double z, const ellipsoidal::Datum &datum = {ellipsoidal::Datum::Type::WGS84}); + + /// Converts 'this' (geocentric) cartesian (x/y/z) coordinate to (geodetic) latitude/longitude + /// point( based on the same datum, or WGS84 if unset ). + /*! + \returns {LatLon} Latitude/longitude point defined by cartesian coordinates. + + \example + auto c = cartesian::Point{4027893.924, 307041.993, 4919474.294}; + auto p = c.toGeoPoint(); // 50.7978°N, 004.3592°E + */ + std::unique_ptr toGeoPoint() const; + + /// Converts this point to the \p targetDatum. + Point &toDatum(ellipsoidal::Datum::Type targetDatum); + +private: + ellipsoidal::Datum m_datum; + }; + +} // cartesian + +} // erkir + +#endif // CARTESIAN_POINT_H + diff --git a/include/erkir/coordinate.h b/include/erkir/coordinate.h new file mode 100644 index 00000000..126f5857 --- /dev/null +++ b/include/erkir/coordinate.h @@ -0,0 +1,89 @@ +/********************************************************************************** +* MIT License * +* * +* Copyright (c) 2018 Vahan Aghajanyan * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy * +* of this software and associated documentation files (the "Software"), to deal * +* in the Software without restriction, including without limitation the rights * +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * +* copies of the Software, and to permit persons to whom the Software is * +* furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in all * +* copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * +* SOFTWARE. * +***********************************************************************************/ + +#ifndef COORDINATE_H +#define COORDINATE_H + +#include "export.h" + +namespace erkir +{ + +//! Implements the geographical coordinate abstraction. +class ERKIR_EXPORT Coordinate +{ +public: + //! Constructs a coordinate by the given decimal degrees. + Coordinate(double degrees); + + //! Returns this coordinate's value in decimal degrees. + double degrees() const; + + //! Returns this coordinate's value in radians. + double radians() const; + + /// A helper function to convert radians to degrees. + static double toDegrees(double radians); + + /// A helper function to convert degrees to radians. + static double toRadians(double degrees); + + static double pi(); + + /// Constrain degrees to range 0..360.0 (e.g. for bearings); -1 => 359, 361 => 1. + static double wrap360(double degrees); + +private: + double m_degrees; +}; + +//! Implements the latitude - geographic coordinate that specifies the north–south +//! position of a point on the Earth's surface. +class ERKIR_EXPORT Latitude : public Coordinate +{ +public: + //! Constructs a latitude object. + /*! + \param degree Decimal degrees in the range from 0° to (+/–)90° + \throws std::out_of_range + */ + Latitude(double degree); +}; + +//! Implements the longitude - the measurement east or west of the prime meridian. +class ERKIR_EXPORT Longitude : public Coordinate +{ +public: + //! Constructs a longitude object. + /*! + \param degree Decimal degrees in the range from 0° to (+/–)180° + \throws std::out_of_range + */ + Longitude(double degree); +}; + +} + +#endif // COORDINATE_H + diff --git a/include/erkir/datum.h b/include/erkir/datum.h new file mode 100644 index 00000000..61e12ab3 --- /dev/null +++ b/include/erkir/datum.h @@ -0,0 +1,120 @@ +/********************************************************************************** +* MIT License * +* * +* Copyright (c) 2020 Vahan Aghajanyan * +* * +* Geodesy tools for conversions between (historical) datums * +* (c) Chris Veness 2005-2019 * +* www.movable-type.co.uk/scripts/latlong-convert-coords.html * +* www.movable-type.co.uk/scripts/geodesy-library.html#latlon-ellipsoidal-datum * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy * +* of this software and associated documentation files (the "Software"), to deal * +* in the Software without restriction, including without limitation the rights * +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * +* copies of the Software, and to permit persons to whom the Software is * +* furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in all * +* copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * +* SOFTWARE. * +***********************************************************************************/ + +#ifndef DATUM_H +#define DATUM_H + +#include "export.h" + +namespace erkir +{ + +namespace cartesian +{ + class Point; +} + +namespace ellipsoidal +{ + +/// Implements a geodetic datum. +/*! + Note that precision of various datums will vary, and WGS-84 (original) is not defined to be + accurate to better than ±1 metre. No transformation should be assumed to be accurate to better + than a meter; for many datums somewhat less. +*/ +class ERKIR_EXPORT Datum +{ +public: + enum class Type + { + ED50, /*!< The older European Datum */ + Irl1975, + NAD27, /*!< The older North American Datum, of which NAD83 was basically a readjustment */ + NAD83, /*!< The North American Datum which is very similar to WGS 84 */ + NTF, /*!< Nouvelle Triangulation Francaise */ + OSGB36, /*!< Of the Ordnance Survey of Great Britain */ + Potsdam, /*!< The local datum of Germany with underlying Bessel ellipsoid */ + TokyoJapan, + WGS72, /*!< 72 of the World Geodetic System */ + WGS84 /*!< 84 of the World Geodetic System */ + }; + + //! Constructs a datum with the given \p type. WGS84 is the default datum. + Datum(Type type = Type::WGS84); + + //! Implements a reference ellipsoid. + struct Ellipsoid + { + enum class Type + { + WGS84, + Airy1830, + AiryModified, + Bessel1841, + Clarke1866, + Clarke1880IGN, + GRS80, + Intl1924, // aka Hayford + WGS72 + }; + + Ellipsoid(double a, double b, double f); + + /// Major axis (a). + double m_a{0.0}; + + /// Minor axis (b). + double m_b{0.0}; + + /// Flattening (f). + double m_f{0.0}; + }; + + /// Returns the reference ellipsoid for this datum. + const Ellipsoid &ellipsoid() const; + + /// Returns the type of this datum. + Type type() const; + + /// Converts the given cartesian \p point to the \p targetDatum. + void toDatum(cartesian::Point &point, Type targetDatum) const; + + /// Compares two datums. + bool operator==(const Datum &other) const; + +private: + Type m_type{Type::WGS84}; +}; + +} // ellipsoidal + +} // erkir + +#endif // DATUM_H diff --git a/include/erkir/ellipsoidalpoint.h b/include/erkir/ellipsoidalpoint.h new file mode 100644 index 00000000..5120ffed --- /dev/null +++ b/include/erkir/ellipsoidalpoint.h @@ -0,0 +1,198 @@ +/********************************************************************************** +* MIT License * +* * +* Copyright (c) 2018-2020 Vahan Aghajanyan * +* * +* Geodesy tools for conversions between (historical) datums * +* (c) Chris Veness 2005-2019 * +* www.movable-type.co.uk/scripts/latlong-convert-coords.html * +* www.movable-type.co.uk/scripts/geodesy-library.html#latlon-ellipsoidal-datum * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy * +* of this software and associated documentation files (the "Software"), to deal * +* in the Software without restriction, including without limitation the rights * +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * +* copies of the Software, and to permit persons to whom the Software is * +* furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in all * +* copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * +* SOFTWARE. * +***********************************************************************************/ + +#ifndef ELLIPSOIDAL_POINT_H +#define ELLIPSOIDAL_POINT_H + +#include + +#include "point.h" +#include "datum.h" + + +namespace erkir +{ + +namespace cartesian +{ + class Point; +} + +namespace ellipsoidal +{ + +//! Implements geodetic point based on ellipsoidal earth model. +/*! + Includes ellipsoid parameters and datums for different coordinate systems, and methods for + converting between them and to Cartesian coordinates. +*/ +class ERKIR_EXPORT Point : public erkir::Point +{ +public: + //! Constructs a point with the given \p latitude, \p longitude \p height above ellipsoid in metres and \p datum. + Point(const Latitude &latitude, const Longitude &longitude, double height = 0.0, + const Datum &datum = {Datum::Type::WGS84}); + + /// Return the datum. + Datum datum() const; + + /// Returns height above the ellipsoid. + double height() const; + + /// Converts 'this' point's coordinate system to new one. + /*! + \param toDatum Datum this coordinate is to be converted to. + \returns Reference to this point converted to new datum. + + \example + Point pWGS84(51.47788, -0.00147, Datum::Type::WGS84); + auto pOSGB = pWGS84.toDatum(Datum::Type::OSGB36); // 51.4773°N, 000.0001°E + */ + Point &toDatum(Datum::Type toDatum); + + /// Converts 'this' point from (geodetic) coordinates to (geocentric) Cartesian (x/y/z) coordinates. + /*! + \returns Cartesian point equivalent to lat/lon point, with x, y, z in metres from earth centre. + */ + std::unique_ptr toCartesianPoint(); + + /*! + Returns the distance between 'this' point and destination point along a geodesic on the + surface of the ellipsoid, using Vincenty inverse solution. + + \param point Latitude/longitude of destination point. + \returns Distance in metres between points or NaN if failed to converge. + \example + auto p1 = Point(50.06632, -5.71475); + auto p2 = Point(58.64402, -3.07009); + auto d = p1.distanceTo(p2); // 969,954.166 m + */ + double distanceTo(const Point &point) const; + + /*! + Returns the destination point having travelled the given distance along a geodesic given by + initial bearing from 'this' point, using Vincenty direct solution. + + \param distance Distance travelled along the geodesic in metres. + \param initialBearing Initial bearing in degrees from north. + \returns Destination point. + \example + auto p1 = Point(-37.95103, 144.42487); + auto p2 = p1.destinationPoint(54972.271, 306.86816); // 37.6528°S, 143.9265°E + */ + Point destinationPoint(double distance, double initialBearing) const; + + /*! + Returns the initial bearing (forward azimuth) to travel along a geodesic from ‘this’ point to + the given point, using Vincenty inverse solution. + + \param point Latitude/longitude of destination point. + \returns Initial bearing in degrees from north (0°..360°) or NaN if failed to converge. + \example + auto p1 = Point(50.06632, -5.71475); + auto p2 = Point(58.64402, -3.07009); + auto b1 = p1.initialBearingTo(p2); // 9.1419° + */ + double initialBearingTo(const Point &point) const; + + /*! + Returns the final bearing (reverse azimuth) having travelled along a geodesic from 'this' + point to the given point, using Vincenty inverse solution. + + \param point Latitude/longitude of destination point. + \returns Final bearing in degrees from north (0°..360°) or NaN if failed to converge. + + \example + auto p1 = Point(50.06632, -5.71475); + auto p2 = Point(58.64402, -3.07009); + auto b2 = p1.finalBearingTo(p2); // 11.2972° + */ + double finalBearingTo(const Point &point) const; + + /*! + Returns the final bearing (reverse azimuth) having travelled along a geodesic given by initial + bearing for a given distance from 'this' point, using Vincenty direct solution. + + \param distance Distance travelled along the geodesic in metres. + \param initialBearing Initial bearing in degrees from north. + \returns Final bearing in degrees from north (0°..360°). + + \example + auto p1 = Point(-37.95103, 144.42487); + auto b2 = p1.finalBearingOn(54972.271, 306.86816); // 307.1736° + */ + double finalBearingOn(double distance, double initialBearing) const; + +private: + enum class DirectField + { + Point, + FinalBearing + }; + + //!Vincenty direct calculation. + /*! + Ellipsoid parameters are taken from datum of 'this' point. Height is ignored. + + \param distance Distance along bearing in metres. + \param initialBearing Initial bearing in degrees from north. + \returns Object including point (destination point), finalBearing. + \throws Formula failed to converge. + */ + std::tuple direct(double distance, double initialBearing) const; + + enum class InverseField + { + Distance, + InitialBearing, + FinalBearing + }; + + //! Vincenty inverse calculation. + /*! + Ellipsoid parameters are taken from datum of 'this' point. Height is ignored. + + \param point Latitude/longitude of destination point. + \returns Object including distance, initialBearing, finalBearing. + \throws Invalid point. + \throws Points must be on surface of ellipsoid. + \throws Formula failed to converge. + */ + std::tuple inverse(const Point &point) const; + + double m_height{ 0.0 }; + Datum m_datum; +}; + +} // ellipsoidal + +} // erkir + +#endif // ELLIPSOIDAL_POINT_H + diff --git a/include/erkir/export.h b/include/erkir/export.h new file mode 100644 index 00000000..edcb0b3d --- /dev/null +++ b/include/erkir/export.h @@ -0,0 +1,14 @@ +#ifndef __EXPORT_H_ +#define __EXPORT_H_ + +#ifdef _WIN32 + #ifdef MAKEDLL + # define ERKIR_EXPORT __declspec(dllexport) + #else + # define ERKIR_EXPORT __declspec(dllimport) + #endif +#else + #define ERKIR_EXPORT +#endif + +#endif // __EXPORT_H_ diff --git a/include/erkir/point.h b/include/erkir/point.h new file mode 100644 index 00000000..d23bf8a2 --- /dev/null +++ b/include/erkir/point.h @@ -0,0 +1,70 @@ +/********************************************************************************** +* MIT License * +* * +* Copyright (c) 2018-2019 Vahan Aghajanyan * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy * +* of this software and associated documentation files (the "Software"), to deal * +* in the Software without restriction, including without limitation the rights * +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * +* copies of the Software, and to permit persons to whom the Software is * +* furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in all * +* copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * +* SOFTWARE. * +***********************************************************************************/ + +#ifndef POINT_H +#define POINT_H + +#include "coordinate.h" +#include "export.h" + +#include + +namespace erkir +{ + +/// Base class for all types of geodetic points. +class ERKIR_EXPORT Point +{ +public: + //! Constructs an invalid point object. + Point(); + + //! Constructs a point with the given \p latitude and \p longitude. + Point(const Latitude &latitude, const Longitude &longitude); + + //! Returns the latitude of this point. + const Latitude &latitude() const; + + //! Returns the longitude of this point. + const Longitude &longitude() const; + + //! Returns true if this point is a valid one and false otherwise. + bool isValid() const; + + /// Returns true if two points are equal and false otherwise. + bool operator==(const Point &other) const; + + /// Returns true if two points are different and false otherwise. + bool operator!=(const Point &other) const; + +private: + Latitude m_latitude; + Longitude m_longitude; + bool m_isValid; +}; + +} // erkir + +#endif // POINT_H + diff --git a/include/erkir/sphericalpoint.h b/include/erkir/sphericalpoint.h new file mode 100644 index 00000000..4a411611 --- /dev/null +++ b/include/erkir/sphericalpoint.h @@ -0,0 +1,285 @@ +/********************************************************************************** +* MIT License * +* * +* Copyright (c) 2018-2019 Vahan Aghajanyan * +* * +* Latitude/longitude spherical geodesy tools (c) Chris Veness 2002-2018 * +* www.movable-type.co.uk/scripts/latlong.html * +* www.movable-type.co.uk/scripts/geodesy/docs/module-latlon-spherical.html * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy * +* of this software and associated documentation files (the "Software"), to deal * +* in the Software without restriction, including without limitation the rights * +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * +* copies of the Software, and to permit persons to whom the Software is * +* furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in all * +* copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * +* SOFTWARE. * +***********************************************************************************/ + +#ifndef SPHERICAL_POINT_H +#define SPHERICAL_POINT_H + +#include "point.h" +#include + +namespace erkir +{ + +namespace spherical +{ + +//! Implements the geographical point. +/*! + All formulae in this class are for calculations on the basis of a spherical earth + (ignoring ellipsoidal effects). +*/ +class ERKIR_EXPORT Point : public erkir::Point +{ +public: + //! Constructs an invalid point object. + Point(); + + //! Constructs a point with the given \p latitude and \p longitude. + Point(const Latitude &latitude, const Longitude &longitude); + + /// Returns the distance from this point to destination point(using haversine formula). + /*! + This function uses calculations on the basis of a spherical earth + (ignoring ellipsoidal effects) – which is accurate enough for most purposes. + It uses the 'haversine' formula to calculate the great-circle distance between + two points – that is, the shortest distance over the earth's surface – giving + an 'as-the-crow-flies' distance between the points. + + \param point Latitude/longitude of destination point. + \param radius (Mean)radius of earth(defaults to radius in 6371e3 metres). + \returns Distance between this point and destination point, in same units as radius. + + \example + Point p1{ 52.205, 0.119 }; + Point p2{ 48.857, 2.351 }; + auto d = p1.distanceTo(p2); // 404.3 km + */ + double distanceTo(const Point &point, double radius = 6371e3) const; + + /// Returns the(initial) bearing from 'this' point to destination point. + /*! + \param point Latitude/longitude of destination point. + \returns Initial bearing in degrees from north. + + \example + Point p1{ 52.205, 0.119 }; + Point p2{ 48.857, 2.351 }; + auto b1 = p1.bearingTo(p2); // 156.2° + */ + double bearingTo(const Point &point) const; + + /// Returns final bearing arriving at destination point from 'this' point. + /*! + Returns final bearing arriving at destination point from 'this' point; the final bearing + will differ from the initial bearing by autoying degrees according to distance and latitude. + + \param point - Latitude/longitude of destination point. + \returns Final bearing in degrees from north. + + \example + Point p1{52.205, 0.119}; + Point p2{48.857, 2.351}; + auto b2 = p1.finalBearingTo(p2); // 157.9° + */ + double finalBearingTo(const Point &point) const; + + /// Returns the midpoint between 'this' point and the supplied point. + /*! + \param point - Latitude/longitude of destination point. + \returns Midpoint between this point and the supplied point. + + \example + Point p1{52.205, 0.119}; + Point p2{48.857, 2.351}; + auto pMid = p1.midpointTo(p2); // 50.5363°N, 001.2746°E + */ + Point midpointTo(const Point &point) const; + + /// Returns the point at given fraction between 'this' point and specified point. + /*! + \param point Latitude/longitude of destination point. + \param fraction Fraction between the two points (0 = this point, 1.0 = specified point). + \returns Intermediate point between this point and destination point. + + \example + Point p1{52.205, 0.119}; + Point p2{48.857, 2.351}; + auto pMid = p1.intermediatePointTo(p2, 0.25); // 51.3721°N, 000.7073°E + */ + Point intermediatePointTo(const Point &point, double fraction) const; + + /// Returns the destination point from 'this' point. + /*! + Returns the destination point from 'this' point having travelled the given distance on the + given initial bearing (bearing normally autoies around path followed). + + \param distance Distance travelled, in same units as earth radius (default: metres). + \param bearing Initial bearing in degrees from north. + \param radius (Mean) radius of earth (defaults to radius in 6371e3 metres). + \returns Destination point. + + \example + Point p1{51.4778, -0.0015}; + Point p2 = p1.destinationPoint(7794, 300.7); // 51.5135°N, 000.0983°W + */ + Point destinationPoint(double distance, double bearing, double radius = 6371e3) const; + + /// Returns the point of intersection of two paths defined by point and bearing. + /*! + @param p1 First point. + @param brng1 Initial bearing from first point in degrees. + @param p2 Second point. + @param brng2 Initial bearing from second point in degrees. + @returns Destination point (an invalid point if no unique intersection defined). + + @example + Point p1{51.8853, 0.2545} + auto brng1 = 108.547; + Point p2{49.0034, 2.5735} + auto brng2 = 32.435; + auto pInt = intersection(p1, brng1, p2, brng2); // 50.9078°N, 004.5084°E + */ + static Point intersection(const Point &p1, double brng1, + const Point &p2, double brng2); + + /// Returns (signed) distance from 'this' point to great circle defined by start - point and end - point. + /*! + \param pathStart Start point of great circle path. + \param pathEnd End point of great circle path. + \param radius (Mean) radius of earth (defaults to radius in 6371e3 metres). + \returns Distance to great circle (negative if to left, positive if to right of path). + + \example + Point pCurrent{53.2611, -0.7972}; + Point p1{53.3206, -1.7297}; + Point p2{53.1887, 0.1334}; + auto d = pCurrent.crossTrackDistanceTo(p1, p2); // -307.5 m + */ + double crossTrackDistanceTo(const Point &pathStart, const Point &pathEnd, + double radius = 6371e3) const; + + /// Returns how far 'this' point is along a path from start-point. + /*! + Returns how far 'this' point is along a path from start-point, heading towards end-point. + That is, if a perpendicular is drawn from 'this' point to the (great circle) path, the along-track + distance is the distance from the start point to where the perpendicular crosses the path. + + \param pathStart Start point of great circle path. + \param pathEnd End point of great circle path. + \param radius (Mean) radius of earth (defaults to radius in 6371e3 metres). + \returns Distance along great circle to point nearest 'this' point. + + \example + Point pCurrent{53.2611, -0.7972}; + Point p1{53.3206, -1.7297}; + Point p2{53.1887, 0.1334}; + auto d = pCurrent.alongTrackDistanceTo(p1, p2); // 62.331 km + */ + double alongTrackDistanceTo(const Point &pathStart, const Point &pathEnd, + double radius = 6371e3) const; + + /// Returns maximum latitude reached when travelling on a great circle. + /*! + Returns maximum latitude reached when travelling on a great circle on given bearing from this + point ('Clairaut's formula'). Negate the result for the minimum latitude (in the Southern + hemisphere). + + The maximum latitude is independent of longitude; it will be the same for all points on a given + latitude. + + \param bearing Initial bearing. + \param latitude Starting latitude. + */ + double maxLatitude(double bearing) const; + + /// Returns the distance travelling from 'this' point to destination point along a rhumb line. + /*! + A 'rhumb line' (or loxodrome) is a path of constant bearing, which crosses + all meridians at the same angle. Sailors used to (and sometimes still) navigate + along rhumb lines since it is easier to follow a constant compass bearing than + to be continually adjusting the bearing, as is needed to follow a great circle. + Rhumb lines are straight lines on a Mercator Projec­tion map (also helpful for + naviga­tion). Rhumb lines are generally longer than great-circle (orthodrome) routes. + + \param point Latitude/longitude of destination point. + \param radius (Mean) radius of earth (defaults to radius in 6371e3 metres). + \returns Distance between this point and destination point (same units as radius). + + \example + Point p1{51.127, 1.338}; + Point p2{50.964, 1.853}; + auto d = p1.rhumbDistanceTo(p2); // 40.31 km + */ + double rhumbDistanceTo(const Point &point, double radius = 6371e3) const; + + /// Returns the bearing from 'this' point to destination point along a rhumb line. + /*! + \param point Latitude/longitude of destination point. + \returns Bearing in degrees from north. + + \example + Point p1{51.127, 1.338}; + Point p2{50.964, 1.853}; + auto d = p1.rhumbBearingTo(p2); // 116.7 + */ + double rhumbBearingTo(const Point &point) const; + + /// Returns the destination point having travelled along a rhumb line from 'this' point the given distance on the given bearing. + /*! + \param distance Distance travelled, in same units as earth radius (default: metres). + \param bearing Bearing in degrees from north. + \param radius (Mean)radius of earth(defaults to radius in 6371e3 metres). + \returns Destination point. + + \example + Point p1{51.127, 1.338}; + auto p2 = p1.rhumbDestinationPoint(40300, 116.7); // 50.9642°N, 001.8530°E + */ + Point rhumbDestinationPoint(double distance, double bearing, double radius = 6371e3) const; + + /// Returns the loxodromic midpoint (along a rhumb line) between 'this' point and second point. + /*! + \param point Latitude/longitude of second point. + \returns Midpoint between this point and second point. + + \example + Point p1{51.127, 1.338}; + Point p2{50.964, 1.853}; + auto pMid = p1.rhumbMidpointTo(p2); // 51.0455°N, 001.5957°E + */ + Point rhumbMidpointTo(const Point &point) const; + + /// Calculates the area of a spherical polygon where the sides of the polygon are great circle arcs joining the vertices. + /*! + \param polygon Array of points defining vertices of the polygon + \param radius (Mean)radius of earth(defaults to radius in 6371e3 metres). + \returns The area of the polygon, in the same units as radius. + + \example + std::vector polygon = {{0,0}, {1,0}, {0,1}}; + auto area = Point::areaOf(polygon); // 6.18e9 mІ + */ + static double areaOf(const std::vector &polygon, double radius = 6371e3); +}; + +} // spherical + +} // erkir + +#endif // SPHERICAL_POINT_H + diff --git a/include/erkir/vector3d.h b/include/erkir/vector3d.h new file mode 100644 index 00000000..59a58eec --- /dev/null +++ b/include/erkir/vector3d.h @@ -0,0 +1,156 @@ +/********************************************************************************** +* MIT License * +* * +* Copyright (c) 2018-2019 Vahan Aghajanyan * +* * +* Vector handling functions (c) Chris Veness 2011-2016 * +* www.movable-type.co.uk/scripts/geodesy/docs/module-vector3d.html * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy * +* of this software and associated documentation files (the "Software"), to deal * +* in the Software without restriction, including without limitation the rights * +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * +* copies of the Software, and to permit persons to whom the Software is * +* furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in all * +* copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * +* SOFTWARE. * +***********************************************************************************/ + +#ifndef VECTOR3D_H +#define VECTOR3D_H + +#include "export.h" + +namespace erkir +{ + +/// Implements 3-d vector manipulation routines. +/*! + In a geodesy context, these vectors may be used to represent: + - n-vector representing a normal to point on Earth's surface + - earth-centered, earth fixed vector (= Gade's 'p-vector') + - great circle normal to vector (on spherical earth model) + - motion vector on Earth's surface + - etc + + Functions return vectors as return results, so that operations can be chained. + \example auto v = v1.cross(v2).dot(v3) // equivalent to v1 × v2 . v3 +*/ +class ERKIR_EXPORT Vector3d +{ +public: + /// Creates an invalid 3-d vector. + Vector3d(); + + /// Creates a 3-d vector. + /*! + The vector may be normalised, or use x/y/z values for eg height relative to the sphere or + ellipsoid, distance from earth centre, etc. + + \param x X component of vector. + \param y Y component of vector. + \param z Z component of vector. + */ + Vector3d(double x, double y, double z); + + double x() const; + double y() const; + double z() const; + bool isValid() const; + + /// Dot (scalar) product of two vectors. + double dot(const Vector3d &v) const; + + /// Multiplies vector by the supplied vector using cross (vector) product. + Vector3d cross(const Vector3d &v) const; + + /// Length (magnitude or norm) of 'this' vector + /*! + \returns Magnitude of this vector. + */ + double length() const; + + /// Normalizes a vector to its unit vector + /*! + If the vector is already unit or is zero magnitude, this is a no-op. + \returns Normalised version of this vector. + */ + Vector3d unit() const; + + /// Calculates the angle between 'this' vector and supplied vector. + /*! + \param v Supplied vector + \param n Plane normal: if supplied, angle is -PI..+PI, signed +ve if this->v is + clockwise looking along n, -ve in opposite direction (if not supplied, angle is always 0..PI). + \returns Angle (in radians) between this vector and supplied vector. + */ + double angleTo(const Vector3d &v, const Vector3d &n = Vector3d()) const; + + /// Rotates 'this' point around an axis by a specified angle. + /*! + \param axis The axis being rotated around. + \param theta The angle of rotation (in radians). + \returns The rotated point. + */ + Vector3d rotateAround(const Vector3d &axis, double theta) const; + +private: + double m_x{ 0.0 }; + double m_y{ 0.0 }; + double m_z{ 0.0 }; + + bool m_isValid; +}; + +/// Vector addition +inline Vector3d operator + (const Vector3d &v1, const Vector3d &v2) +{ + return Vector3d(v1.x() + v2.x(), v1.y() + v2.y(), v1.z() + v2.z()); +} + +/// Vector subtraction +inline Vector3d operator - (const Vector3d &v1, const Vector3d & v2) +{ + return Vector3d(v1.x() - v2.x(), v1.y() - v2.y(), v1.z() - v2.z()); +} + +/// Unary negation of a vector +/*! + Negates a vector to point in the opposite direction. +*/ +inline Vector3d operator - (const Vector3d &v1) +{ + return Vector3d(-v1.x(), -v1.y(), -v1.z()); +} + +/// Multiplication of vector and scalar +inline Vector3d operator * (const Vector3d &v1, double s) +{ + return Vector3d(v1.x() * s, v1.y() * s, v1.z() * s); +} + +/// Division of vector and scalar +inline Vector3d operator / (const Vector3d &v1, double s) +{ + return Vector3d(v1.x() / s, v1.y() / s, v1.z() / s); +} + +/// Multiplication of scalar and vector +inline Vector3d operator * (double s, const Vector3d &v1) +{ + return v1 * s; +} + +} // erkir + +#endif // VECTOR3D_H + diff --git a/lib/lib_x64/erkir.lib b/lib/lib_x64/erkir.lib new file mode 100644 index 0000000000000000000000000000000000000000..1ef5595488db57ac451b2ffb4cd7ef77ab9e13cc GIT binary patch literal 32590 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 Dx8BUm literal 0 HcmV?d00001 diff --git a/lib/libd_x64/erkird.lib b/lib/libd_x64/erkird.lib new file mode 100644 index 0000000000000000000000000000000000000000..80e3e797af4444e70406d741ae82377846a3a01a GIT binary patch literal 32662 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 literal 0 HcmV?d00001 diff --git a/mainwindow.cpp b/mainwindow.cpp index 8716814d..581104b1 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -3,6 +3,7 @@ #include "FileParser/UGModelConfigParams.h" #include "computeoffsetpositiondialog.h" #include "displayroutedialog.h" +#include "geospatialanalysis.h" #include "importscenedatadialog.h" #include "maplocationdialog.h" #include "qregularexpression.h" @@ -104,6 +105,8 @@ #include "Symbol/UGMarkerSymbolLib.h" +#include "erkir/sphericalpoint.h" + //工作空间及数据源默认存储路径及别名 const QString wsName = "MapWorkspace"; //工作空间别名 QString wsFullName; //工作空间存储路径 @@ -380,11 +383,29 @@ MainWindow::MainWindow(QWidget *parent) bool s = m_pWorkspace->GetResources()->GetMarkerSymbolLib()->IsIDExisted(318); qDebug()<<"***********s2:"<addDEMDataset(demName); + + UGPoint2D ptView(119.703784,32.228956); + UGPoint2D ptObject(119.707676,32.227302); + GeoSpatialAnalysis geoSAnalysis; + UG3DAnalyst::SingleResult* result = geoSAnalysis.DoublePointVisibility(qMapControl,ptView,ptObject); + if(!result==NULL) + { + qDebug()<<"*******************bVisible:"<bVisible; + qDebug()<<"*******************x:"<pnt3D.x; + qDebug()<<"*******************y:"<pnt3D.y; + qDebug()<<"*******************z:"<pnt3D.z; + } + + erkir::spherical::Point p1{ 52.205, 0.119 }; + erkir::spherical::Point p2{ 48.857, 2.351 }; + auto d = p1.distanceTo(p2); // 404.3 km -// int id = ms->GetSymbolAt(0)->GetID(); -// QString name = Translator::UGStr2QStr(ms->GetSymbolAt(0)->GetName()); -// qDebug()<<"****************:"; + erkir::spherical::Point p3{ 51.4778, -0.0015 }; + auto dest = p3.destinationPoint(7794.0, 300.7); // 51.5135°N, 000.0983°W + qDebug()<<"*******************z:"; /* qDebug()<<"****************:" <GetDataSource(0)->GetDataset(line3DSetAlias).get(); @@ -547,8 +568,9 @@ void MainWindow::initMapControl() { //实例化一个地图窗口对象,即QMapControl对象 qMapControl = new QMapControl; - qMapControl->GetUGMapWnd()->SetAfterGeometryAddedFunc(AfterGeometryAddedCallback,(UGlong)qMapControl); + qMapControl->GetMap()->SetWorkspace(m_pWorkspace); + qMapControl->GetUGMapWnd()->SetAfterGeometryAddedFunc(AfterGeometryAddedCallback,(UGlong)qMapControl); qMapControl->GetUGMapWnd()->SetAfterPointInputFunc(AfterPointInputCallback,(UGlong)qMapControl); qMapControl->GetUGMapWnd()->SetGeometrySelectedFunc(GeometrySelectedCallback,(UGlong)qMapControl); // qMapControl->GetUGMapWnd()->SetSingleGeometrySelectedFunc(SingleGeometrySelectedCallback,(UGlong)qMapControl); @@ -2468,8 +2490,8 @@ void MainWindow::Edit() // qDebug()<<"*********************1:"<GetUGLayer3Ds()->GetInnerCount(); } - } + #pragma endregion } /****************地图量算操作**********************/ diff --git a/mapdatamaneger.cpp b/mapdatamaneger.cpp index ad7925b6..7b4b08a7 100644 --- a/mapdatamaneger.cpp +++ b/mapdatamaneger.cpp @@ -57,6 +57,8 @@ UGDatasetVectorPtr MapDataManeger::createVectorSet(UGDataSource *ds, UGDataset:: return ds->CreateDatasetVector(vectorInfo); } + + //UGLayer3D *MapDataManeger::createTemporaryLayer3D(UGDataSource *ds, UGLayer3Ds *pLayers, UGint nUGLayerType, UGString datasetName) //{