From 396faa4171ed6a35b734da5a49a305d2d2450baf Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 8 Feb 2020 22:40:00 +0700 Subject: [PATCH 1/5] Added tests for SphericalUtil class --- .../SphericalUtil/computeAngleBetween.cpp | 18 +-- tests/SphericalUtil/computeArea.cpp | 19 +++ .../SphericalUtil/computeDistanceBetween.cpp | 10 +- .../SphericalUtil/computeHeading.cpp | 20 +-- tests/SphericalUtil/computeLength.cpp | 22 +++ tests/SphericalUtil/computeOffset.cpp | 39 +++++ tests/SphericalUtil/computeOffsetOrigin.cpp | 32 ++++ tests/SphericalUtil/computeSignedArea.cpp | 16 ++ tests/SphericalUtil/interpolate.cpp | 58 ++++++++ tests/packages.config | 4 + tests/tests.vcxproj | 139 ++++++++++++++++++ tests/tests.vcxproj.filters | 40 +++++ 12 files changed, 393 insertions(+), 24 deletions(-) rename {functional_tests => tests}/SphericalUtil/computeAngleBetween.cpp (85%) create mode 100644 tests/SphericalUtil/computeArea.cpp rename {functional_tests => tests}/SphericalUtil/computeDistanceBetween.cpp (56%) rename {functional_tests => tests}/SphericalUtil/computeHeading.cpp (74%) create mode 100644 tests/SphericalUtil/computeLength.cpp create mode 100644 tests/SphericalUtil/computeOffset.cpp create mode 100644 tests/SphericalUtil/computeOffsetOrigin.cpp create mode 100644 tests/SphericalUtil/computeSignedArea.cpp create mode 100644 tests/SphericalUtil/interpolate.cpp create mode 100644 tests/packages.config create mode 100644 tests/tests.vcxproj create mode 100644 tests/tests.vcxproj.filters diff --git a/functional_tests/SphericalUtil/computeAngleBetween.cpp b/tests/SphericalUtil/computeAngleBetween.cpp similarity index 85% rename from functional_tests/SphericalUtil/computeAngleBetween.cpp rename to tests/SphericalUtil/computeAngleBetween.cpp index 7c9d274..20fa58e 100644 --- a/functional_tests/SphericalUtil/computeAngleBetween.cpp +++ b/tests/SphericalUtil/computeAngleBetween.cpp @@ -1,15 +1,15 @@ -#include "gtest/gtest.h" +#include -#include +#include "SphericalUtil.hpp" TEST(SphericalUtil, computeAngleBetween) { - LatLng up(90, 0); - LatLng down(-90, 0); - LatLng front(0, 0); - LatLng right(0, 90); - LatLng back(0, -180); - LatLng left(0, -90); + LatLng up = { 90.0, 0.0 }; + LatLng down = {-90.0, 0.0 }; + LatLng front = { 0.0, 0.0 }; + LatLng right = { 0.0, 90.0 }; + LatLng back = { 0.0, -180.0 }; + LatLng left = { 0.0, -90.0 }; EXPECT_NEAR(SphericalUtil::computeAngleBetween(up, up), 0, 1e-6); EXPECT_NEAR(SphericalUtil::computeAngleBetween(down, down), 0, 1e-6); @@ -38,4 +38,4 @@ TEST(SphericalUtil, computeAngleBetween) { EXPECT_NEAR(SphericalUtil::computeAngleBetween(up, down), M_PI, 1e-6); EXPECT_NEAR(SphericalUtil::computeAngleBetween(front, back), M_PI, 1e-6); EXPECT_NEAR(SphericalUtil::computeAngleBetween(left, right), M_PI, 1e-6); -} \ No newline at end of file +} diff --git a/tests/SphericalUtil/computeArea.cpp b/tests/SphericalUtil/computeArea.cpp new file mode 100644 index 0000000..1120398 --- /dev/null +++ b/tests/SphericalUtil/computeArea.cpp @@ -0,0 +1,19 @@ +#include + +#include "SphericalUtil.hpp" + + +TEST(SphericalUtil, computeArea) { + LatLng up = { 90.0, 0.0 }; + LatLng down = {-90.0, 0.0 }; + LatLng front = { 0.0, 0.0 }; + LatLng right = { 0.0, 90.0 }; + LatLng back = { 0.0, -180.0 }; + LatLng left = { 0.0, -90.0 }; + + std::vector first = { right, up, front, down, right }; + EXPECT_NEAR(SphericalUtil::computeArea(first), M_PI * MathUtil::EARTH_RADIUS * MathUtil::EARTH_RADIUS, .4); + + std::vector second = { right, down, front, up, right }; + EXPECT_NEAR(SphericalUtil::computeArea(second), M_PI * MathUtil::EARTH_RADIUS * MathUtil::EARTH_RADIUS, .4); +} diff --git a/functional_tests/SphericalUtil/computeDistanceBetween.cpp b/tests/SphericalUtil/computeDistanceBetween.cpp similarity index 56% rename from functional_tests/SphericalUtil/computeDistanceBetween.cpp rename to tests/SphericalUtil/computeDistanceBetween.cpp index c534ea5..85a24ba 100644 --- a/functional_tests/SphericalUtil/computeDistanceBetween.cpp +++ b/tests/SphericalUtil/computeDistanceBetween.cpp @@ -1,11 +1,11 @@ -#include "gtest/gtest.h" +#include -#include +#include "SphericalUtil.hpp" TEST(SphericalUtil, computeDistanceBetween) { - LatLng up(90, 0); - LatLng down(-90, 0); + LatLng up = { 90.0, 0.0}; + LatLng down = {-90.0, 0.0}; EXPECT_NEAR(SphericalUtil::computeDistanceBetween(up, down), M_PI * MathUtil::EARTH_RADIUS, 1e-6); -} \ No newline at end of file +} diff --git a/functional_tests/SphericalUtil/computeHeading.cpp b/tests/SphericalUtil/computeHeading.cpp similarity index 74% rename from functional_tests/SphericalUtil/computeHeading.cpp rename to tests/SphericalUtil/computeHeading.cpp index cbc674b..481f80b 100644 --- a/functional_tests/SphericalUtil/computeHeading.cpp +++ b/tests/SphericalUtil/computeHeading.cpp @@ -1,19 +1,19 @@ -#include "gtest/gtest.h" +#include -#include +#include "SphericalUtil.hpp" TEST(SphericalUtil, computeHeading) { - LatLng up(90, 0); - LatLng down(-90, 0); - LatLng front(0, 0); - LatLng right(0, 90); - LatLng back(0, -180); - LatLng left(0, -90); + LatLng up = { 90.0, 0.0 }; + LatLng down = {-90.0, 0.0 }; + LatLng front = { 0.0, 0.0 }; + LatLng right = { 0.0, 90.0 }; + LatLng back = { 0.0, -180.0 }; + LatLng left = { 0.0, -90.0 }; // Opposing vertices for which there is a result EXPECT_NEAR(SphericalUtil::computeHeading(up, down), -180, 1e-6); - EXPECT_NEAR(SphericalUtil::computeHeading(down, up), 0, 1e-6); + EXPECT_NEAR(SphericalUtil::computeHeading(down, up), 0, 1e-6); // Adjacent vertices for which there is a result EXPECT_NEAR(SphericalUtil::computeHeading(front, up), 0, 1e-6); @@ -31,4 +31,4 @@ TEST(SphericalUtil, computeHeading) { EXPECT_NEAR(SphericalUtil::computeHeading(front, right), 90, 1e-6); EXPECT_NEAR(SphericalUtil::computeHeading(back, right), -90, 1e-6); -} \ No newline at end of file +} diff --git a/tests/SphericalUtil/computeLength.cpp b/tests/SphericalUtil/computeLength.cpp new file mode 100644 index 0000000..6ecd0b9 --- /dev/null +++ b/tests/SphericalUtil/computeLength.cpp @@ -0,0 +1,22 @@ +#include + +#include "SphericalUtil.hpp" + + +TEST(SphericalUtil, computeLength) { + // List without points + std::vector latLngs; + EXPECT_NEAR(SphericalUtil::computeLength(latLngs), 0, 1e-6); + + // List with one point + latLngs.push_back(LatLng(0, 0)); + EXPECT_NEAR(SphericalUtil::computeLength(latLngs), 0, 1e-6); + + // List with two points + latLngs.push_back(LatLng(0.1, 0.1)); + EXPECT_NEAR(SphericalUtil::computeLength(latLngs), deg2rad(0.1) * sqrt(2) * MathUtil::EARTH_RADIUS, 1); + + // List with three points + std::vector latLngs2 = { {0, 0}, {90, 0}, {0, 90} }; + EXPECT_NEAR(SphericalUtil::computeLength(latLngs2), M_PI * MathUtil::EARTH_RADIUS, 1e-6); +} diff --git a/tests/SphericalUtil/computeOffset.cpp b/tests/SphericalUtil/computeOffset.cpp new file mode 100644 index 0000000..1fb91b8 --- /dev/null +++ b/tests/SphericalUtil/computeOffset.cpp @@ -0,0 +1,39 @@ +#include + +#include "SphericalUtil.hpp" + +inline void EXPECT_NEAR_LatLan(LatLng actual, LatLng expected) { + EXPECT_NEAR(actual.lat, expected.lat, 1e-6); + // Issue #2 + // Account for the convergence of longitude lines at the poles + // double cosLat = cos(deg2rad(actual.lat)); + // EXPECT_NEAR(cosLat * actual.lng, cosLat * expected.lng, 1e-6); +} + +TEST(SphericalUtil, computeOffset) { + LatLng up = { 90.0, 0.0 }; + LatLng down = {-90.0, 0.0 }; + LatLng front = { 0.0, 0.0 }; + LatLng right = { 0.0, 90.0 }; + LatLng back = { 0.0, -180.0 }; + LatLng left = { 0.0, -90.0 }; + + EXPECT_NEAR_LatLan(front, SphericalUtil::computeOffset(front, 0, 0)); + EXPECT_NEAR_LatLan(up, SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS / 2, 0)); + EXPECT_NEAR_LatLan(down, SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS / 2, 180)); + EXPECT_NEAR_LatLan(left, SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS / 2, -90)); + EXPECT_NEAR_LatLan(right, SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS / 2, 90)); + EXPECT_NEAR_LatLan(back, SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS, 0)); + EXPECT_NEAR_LatLan(back, SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS, 90)); + + // From left + EXPECT_NEAR_LatLan(left, SphericalUtil::computeOffset(left, 0, 0)); + EXPECT_NEAR_LatLan(up, SphericalUtil::computeOffset(left, M_PI * MathUtil::EARTH_RADIUS / 2, 0)); + EXPECT_NEAR_LatLan(down, SphericalUtil::computeOffset(left, M_PI * MathUtil::EARTH_RADIUS / 2, 180)); + EXPECT_NEAR_LatLan(front, SphericalUtil::computeOffset(left, M_PI * MathUtil::EARTH_RADIUS / 2, 90)); + EXPECT_NEAR_LatLan(back, SphericalUtil::computeOffset(left, M_PI * MathUtil::EARTH_RADIUS / 2, -90)); + EXPECT_NEAR_LatLan(right, SphericalUtil::computeOffset(left, M_PI * MathUtil::EARTH_RADIUS, 0)); + EXPECT_NEAR_LatLan(right, SphericalUtil::computeOffset(left, M_PI * MathUtil::EARTH_RADIUS, 90)); + + // NOTE: Heading is undefined at the poles, so we do not test from up/down. +} diff --git a/tests/SphericalUtil/computeOffsetOrigin.cpp b/tests/SphericalUtil/computeOffsetOrigin.cpp new file mode 100644 index 0000000..381dad1 --- /dev/null +++ b/tests/SphericalUtil/computeOffsetOrigin.cpp @@ -0,0 +1,32 @@ +#include + +#include "SphericalUtil.hpp" + + +inline void EXPECT_NEAR_LatLan(LatLng actual, LatLng expected) { + EXPECT_NEAR(actual.lat, expected.lat, 1e-6); + // Issue #2 + // Account for the convergence of longitude lines at the poles + // double cosLat = cos(deg2rad(actual.lat)); + // EXPECT_NEAR(cosLat * actual.lng, cosLat * expected.lng, 1e-6); +} + +TEST(SphericalUtil, computeOffsetOrigin) { + LatLng front = { 0.0, 0.0 }; + + EXPECT_NEAR_LatLan(front, SphericalUtil::computeOffsetOrigin(front, 0, 0)); + + EXPECT_NEAR_LatLan(front, SphericalUtil::computeOffsetOrigin(LatLng( 0, 45), M_PI * MathUtil::EARTH_RADIUS / 4, 90)); + EXPECT_NEAR_LatLan(front, SphericalUtil::computeOffsetOrigin(LatLng( 0, -45), M_PI * MathUtil::EARTH_RADIUS / 4, -90)); + EXPECT_NEAR_LatLan(front, SphericalUtil::computeOffsetOrigin(LatLng( 45, 0), M_PI * MathUtil::EARTH_RADIUS / 4, 0)); + EXPECT_NEAR_LatLan(front, SphericalUtil::computeOffsetOrigin(LatLng(-45, 0), M_PI * MathUtil::EARTH_RADIUS / 4, 180)); + + // Issue #3 + // Situations with no solution, should return null. + // + // First 'over' the pole. + // EXPECT_NULL(SphericalUtil::computeOffsetOrigin(LatLng(80, 0), M_PI * MathUtil::EARTH_RADIUS / 4, 180)); + + // Second a distance that doesn't fit on the earth. + // EXPECT_NULL(SphericalUtil::computeOffsetOrigin(LatLng(80, 0), M_PI * MathUtil::EARTH_RADIUS / 4, 90)); +} diff --git a/tests/SphericalUtil/computeSignedArea.cpp b/tests/SphericalUtil/computeSignedArea.cpp new file mode 100644 index 0000000..761cd79 --- /dev/null +++ b/tests/SphericalUtil/computeSignedArea.cpp @@ -0,0 +1,16 @@ +#include + +#include "SphericalUtil.hpp" + + +TEST(SphericalUtil, computeSignedArea) { + LatLng up = { 90.0, 0.0 }; + LatLng down = {-90.0, 0.0 }; + LatLng front = { 0.0, 0.0 }; + LatLng right = { 0.0, 90.0 }; + + std::vector path = { right, up, front, down, right }; + std::vector pathReversed = { right, down, front, up, right }; + + EXPECT_NEAR(-SphericalUtil::computeSignedArea(path), SphericalUtil::computeSignedArea(pathReversed), 0); +} diff --git a/tests/SphericalUtil/interpolate.cpp b/tests/SphericalUtil/interpolate.cpp new file mode 100644 index 0000000..b5baf1b --- /dev/null +++ b/tests/SphericalUtil/interpolate.cpp @@ -0,0 +1,58 @@ +#include + +#include "SphericalUtil.hpp" + + +inline void EXPECT_NEAR_LatLan(LatLng actual, LatLng expected) { + EXPECT_NEAR(actual.lat, expected.lat, 1e-6); + // Issue #2 + // Account for the convergence of longitude lines at the poles + // double cosLat = cos(deg2rad(actual.lat)); + // EXPECT_NEAR(cosLat * actual.lng, cosLat * expected.lng, 1e-6); +} + +TEST(SphericalUtil, interpolate) { + LatLng up(90, 0); + LatLng down(-90, 0); + LatLng front(0, 0); + LatLng right(0, 90); + LatLng back(0, -180); + LatLng left(0, -90); + + EXPECT_NEAR_LatLan(up, SphericalUtil::interpolate(up, up, 1 / 2.0)); + EXPECT_NEAR_LatLan(down, SphericalUtil::interpolate(down, down, 1 / 2.0)); + EXPECT_NEAR_LatLan(left, SphericalUtil::interpolate(left, left, 1 / 2.0)); + + // Between front and up + EXPECT_NEAR_LatLan(LatLng(1, 0), SphericalUtil::interpolate(front, up, 1 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(1, 0), SphericalUtil::interpolate(up, front, 89 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(89, 0), SphericalUtil::interpolate(front, up, 89 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(89, 0), SphericalUtil::interpolate(up, front, 1 / 90.0)); + + // Between front and down + EXPECT_NEAR_LatLan(LatLng(-1, 0), SphericalUtil::interpolate(front, down, 1 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(-1, 0), SphericalUtil::interpolate(down, front, 89 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(-89, 0), SphericalUtil::interpolate(front, down, 89 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(-89, 0), SphericalUtil::interpolate(down, front, 1 / 90.0)); + + // Between left and back + EXPECT_NEAR_LatLan(LatLng(0, -91), SphericalUtil::interpolate(left, back, 1 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(0, -91), SphericalUtil::interpolate(back, left, 89 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(0, -179), SphericalUtil::interpolate(left, back, 89 / 90.0)); + EXPECT_NEAR_LatLan(LatLng(0, -179), SphericalUtil::interpolate(back, left, 1 / 90.0)); + + // geodesic crosses pole + EXPECT_NEAR_LatLan(up, SphericalUtil::interpolate(LatLng(45, 0), LatLng(45, 180), 1 / 2.0)); + EXPECT_NEAR_LatLan(down, SphericalUtil::interpolate(LatLng(-45, 0), LatLng(-45, 180), 1 / 2.0)); + + // boundary values for fraction, between left and back + EXPECT_NEAR_LatLan(left, SphericalUtil::interpolate(left, back, 0.0)); + EXPECT_NEAR_LatLan(back, SphericalUtil::interpolate(left, back, 1.0)); + + // two nearby points, separated by ~4m, for which the Slerp algorithm is not stable and we + // have to fall back to linear interpolation. + LatLng interpolateResult = SphericalUtil::interpolate(LatLng(-37.756891, 175.325262), LatLng(-37.756853, 175.325242), 0.5); + LatLng goldenResult(-37.756872, 175.325252); + + EXPECT_NEAR(interpolateResult.lat, goldenResult.lat, 2e-5); +} diff --git a/tests/packages.config b/tests/packages.config new file mode 100644 index 0000000..0acd30a --- /dev/null +++ b/tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/tests.vcxproj b/tests/tests.vcxproj new file mode 100644 index 0000000..7454a3a --- /dev/null +++ b/tests/tests.vcxproj @@ -0,0 +1,139 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {96b63797-1621-492e-88c0-72751561874d} + Win32Proj + 10.0.17763.0 + Application + v141 + Unicode + + + + + + + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);../geometry-library/ + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);../geometry-library/ + + + + + + + + + + + + + + + {6ff667f1-262a-4779-81cf-fd346fe2af62} + + + + + + + + + + + + + NotUsing + pch.h + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level3 + $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);$(SolutionDir)/include/ + + + true + Console + + + + + NotUsing + pch.h + Disabled + X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level3 + $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);$(SolutionDir)/include/ + + + true + Console + + + + + NotUsing + pch.h + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);$(SolutionDir)/include/ + + + true + Console + true + true + + + + + NotUsing + pch.h + X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);$(SolutionDir)/include/ + + + true + Console + true + true + + + + + Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их. Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}. + + + + \ No newline at end of file diff --git a/tests/tests.vcxproj.filters b/tests/tests.vcxproj.filters new file mode 100644 index 0000000..a221b1f --- /dev/null +++ b/tests/tests.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {4fbd4f21-7e3a-4fd2-9bfa-29dc154dc6d7} + + + + + SphericalUtil + + + SphericalUtil + + + SphericalUtil + + + SphericalUtil + + + SphericalUtil + + + SphericalUtil + + + SphericalUtil + + + SphericalUtil + + + SphericalUtil + + + + + + \ No newline at end of file From f40e05dd4c932a4a4be791f6ba442ea9276c309c Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Feb 2020 00:03:49 +0700 Subject: [PATCH 2/5] Added tests for functions in SphericalUtil class --- .gitignore | 3 ++ Makefile | 10 +++++ ...gleBetween.cpp => computeAngleBetween.hpp} | 0 .../{computeArea.cpp => computeArea.hpp} | 0 ...Between.cpp => computeDistanceBetween.hpp} | 0 ...{computeHeading.cpp => computeHeading.hpp} | 0 .../{computeLength.cpp => computeLength.hpp} | 0 .../{computeOffset.cpp => computeOffset.hpp} | 5 +-- ...fsetOrigin.cpp => computeOffsetOrigin.hpp} | 9 ++-- ...teSignedArea.cpp => computeSignedArea.hpp} | 0 .../{interpolate.cpp => interpolate.hpp} | 16 +++---- tests/Tests.cpp | 16 +++++++ tests/tests.vcxproj | 35 +++++++++------ tests/tests.vcxproj.filters | 45 ++++++++++--------- 14 files changed, 88 insertions(+), 51 deletions(-) create mode 100644 Makefile rename tests/SphericalUtil/{computeAngleBetween.cpp => computeAngleBetween.hpp} (100%) rename tests/SphericalUtil/{computeArea.cpp => computeArea.hpp} (100%) rename tests/SphericalUtil/{computeDistanceBetween.cpp => computeDistanceBetween.hpp} (100%) rename tests/SphericalUtil/{computeHeading.cpp => computeHeading.hpp} (100%) rename tests/SphericalUtil/{computeLength.cpp => computeLength.hpp} (100%) rename tests/SphericalUtil/{computeOffset.cpp => computeOffset.hpp} (94%) rename tests/SphericalUtil/{computeOffsetOrigin.cpp => computeOffsetOrigin.hpp} (82%) rename tests/SphericalUtil/{computeSignedArea.cpp => computeSignedArea.hpp} (100%) rename tests/SphericalUtil/{interpolate.cpp => interpolate.hpp} (90%) create mode 100644 tests/Tests.cpp diff --git a/.gitignore b/.gitignore index ae5b9fb..f2c1510 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +Gtests +Sample + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6987363 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +sample : + g++ samples/Samples.cpp \ + -std=c++14 -Iinclude/ \ + -o Sample + +gtests : + g++ tests/Tests.cpp \ + -std=c++14 -Iinclude/ \ + -lgtest -pthread \ + -o GTests diff --git a/tests/SphericalUtil/computeAngleBetween.cpp b/tests/SphericalUtil/computeAngleBetween.hpp similarity index 100% rename from tests/SphericalUtil/computeAngleBetween.cpp rename to tests/SphericalUtil/computeAngleBetween.hpp diff --git a/tests/SphericalUtil/computeArea.cpp b/tests/SphericalUtil/computeArea.hpp similarity index 100% rename from tests/SphericalUtil/computeArea.cpp rename to tests/SphericalUtil/computeArea.hpp diff --git a/tests/SphericalUtil/computeDistanceBetween.cpp b/tests/SphericalUtil/computeDistanceBetween.hpp similarity index 100% rename from tests/SphericalUtil/computeDistanceBetween.cpp rename to tests/SphericalUtil/computeDistanceBetween.hpp diff --git a/tests/SphericalUtil/computeHeading.cpp b/tests/SphericalUtil/computeHeading.hpp similarity index 100% rename from tests/SphericalUtil/computeHeading.cpp rename to tests/SphericalUtil/computeHeading.hpp diff --git a/tests/SphericalUtil/computeLength.cpp b/tests/SphericalUtil/computeLength.hpp similarity index 100% rename from tests/SphericalUtil/computeLength.cpp rename to tests/SphericalUtil/computeLength.hpp diff --git a/tests/SphericalUtil/computeOffset.cpp b/tests/SphericalUtil/computeOffset.hpp similarity index 94% rename from tests/SphericalUtil/computeOffset.cpp rename to tests/SphericalUtil/computeOffset.hpp index 1fb91b8..aa16f4c 100644 --- a/tests/SphericalUtil/computeOffset.cpp +++ b/tests/SphericalUtil/computeOffset.hpp @@ -2,13 +2,12 @@ #include "SphericalUtil.hpp" -inline void EXPECT_NEAR_LatLan(LatLng actual, LatLng expected) { - EXPECT_NEAR(actual.lat, expected.lat, 1e-6); +#define EXPECT_NEAR_LatLan(actual, expected) \ + EXPECT_NEAR(actual.lat, expected.lat, 1e-6); // Issue #2 // Account for the convergence of longitude lines at the poles // double cosLat = cos(deg2rad(actual.lat)); // EXPECT_NEAR(cosLat * actual.lng, cosLat * expected.lng, 1e-6); -} TEST(SphericalUtil, computeOffset) { LatLng up = { 90.0, 0.0 }; diff --git a/tests/SphericalUtil/computeOffsetOrigin.cpp b/tests/SphericalUtil/computeOffsetOrigin.hpp similarity index 82% rename from tests/SphericalUtil/computeOffsetOrigin.cpp rename to tests/SphericalUtil/computeOffsetOrigin.hpp index 381dad1..29d17fa 100644 --- a/tests/SphericalUtil/computeOffsetOrigin.cpp +++ b/tests/SphericalUtil/computeOffsetOrigin.hpp @@ -3,13 +3,12 @@ #include "SphericalUtil.hpp" -inline void EXPECT_NEAR_LatLan(LatLng actual, LatLng expected) { - EXPECT_NEAR(actual.lat, expected.lat, 1e-6); +#define EXPECT_NEAR_LatLan(actual, expected) \ + EXPECT_NEAR(actual.lat, expected.lat, 1e-6); // Issue #2 - // Account for the convergence of longitude lines at the poles + // Account for the convergence of longitude lines at the poles // double cosLat = cos(deg2rad(actual.lat)); - // EXPECT_NEAR(cosLat * actual.lng, cosLat * expected.lng, 1e-6); -} + // EXPECT_NEAR(cosLat * actual.lng, cosLat * expected.lng, 1e-6); TEST(SphericalUtil, computeOffsetOrigin) { LatLng front = { 0.0, 0.0 }; diff --git a/tests/SphericalUtil/computeSignedArea.cpp b/tests/SphericalUtil/computeSignedArea.hpp similarity index 100% rename from tests/SphericalUtil/computeSignedArea.cpp rename to tests/SphericalUtil/computeSignedArea.hpp diff --git a/tests/SphericalUtil/interpolate.cpp b/tests/SphericalUtil/interpolate.hpp similarity index 90% rename from tests/SphericalUtil/interpolate.cpp rename to tests/SphericalUtil/interpolate.hpp index b5baf1b..2b00888 100644 --- a/tests/SphericalUtil/interpolate.cpp +++ b/tests/SphericalUtil/interpolate.hpp @@ -3,21 +3,21 @@ #include "SphericalUtil.hpp" -inline void EXPECT_NEAR_LatLan(LatLng actual, LatLng expected) { +#define EXPECT_NEAR_LatLan(actual, expected) \ EXPECT_NEAR(actual.lat, expected.lat, 1e-6); // Issue #2 // Account for the convergence of longitude lines at the poles // double cosLat = cos(deg2rad(actual.lat)); // EXPECT_NEAR(cosLat * actual.lng, cosLat * expected.lng, 1e-6); -} + TEST(SphericalUtil, interpolate) { - LatLng up(90, 0); - LatLng down(-90, 0); - LatLng front(0, 0); - LatLng right(0, 90); - LatLng back(0, -180); - LatLng left(0, -90); + LatLng up = { 90.0, 0.0 }; + LatLng down = {-90.0, 0.0 }; + LatLng front = { 0.0, 0.0 }; + LatLng right = { 0.0, 90.0 }; + LatLng back = { 0.0, -180.0 }; + LatLng left = { 0.0, -90.0 }; EXPECT_NEAR_LatLan(up, SphericalUtil::interpolate(up, up, 1 / 2.0)); EXPECT_NEAR_LatLan(down, SphericalUtil::interpolate(down, down, 1 / 2.0)); diff --git a/tests/Tests.cpp b/tests/Tests.cpp new file mode 100644 index 0000000..1ad234b --- /dev/null +++ b/tests/Tests.cpp @@ -0,0 +1,16 @@ +/** Including all tests */ +#include "SphericalUtil/interpolate.hpp" +#include "SphericalUtil/computeAngleBetween.hpp" +#include "SphericalUtil/computeSignedArea.hpp" +#include "SphericalUtil/computeArea.hpp" +#include "SphericalUtil/computeLength.hpp" +#include "SphericalUtil/computeOffset.hpp" +#include "SphericalUtil/computeHeading.hpp" +#include "SphericalUtil/computeOffsetOrigin.hpp" +#include "SphericalUtil/computeDistanceBetween.hpp" + + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/tests.vcxproj b/tests/tests.vcxproj index 7454a3a..885fba9 100644 --- a/tests/tests.vcxproj +++ b/tests/tests.vcxproj @@ -33,24 +33,27 @@ - $(VC_IncludePath);$(WindowsSDK_IncludePath);../geometry-library/ + $(VC_IncludePath);$(WindowsSDK_IncludePath);../include/ + true - $(VC_IncludePath);$(WindowsSDK_IncludePath);../geometry-library/ + $(VC_IncludePath);$(WindowsSDK_IncludePath);../include/ + true - - - - - - - - - + + + + + + + + + + - + {6ff667f1-262a-4779-81cf-fd346fe2af62} @@ -82,7 +85,8 @@ NotUsing - pch.h + + Disabled X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true @@ -90,6 +94,7 @@ MultiThreadedDebugDLL Level3 $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);$(SolutionDir)/include/ + true @@ -116,12 +121,14 @@ NotUsing - pch.h + + X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDLL Level3 ProgramDatabase $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);$(SolutionDir)/include/ + true diff --git a/tests/tests.vcxproj.filters b/tests/tests.vcxproj.filters index a221b1f..eebe7d1 100644 --- a/tests/tests.vcxproj.filters +++ b/tests/tests.vcxproj.filters @@ -6,35 +6,38 @@ - + + + + + + + SphericalUtil - - + + SphericalUtil - - + + SphericalUtil - - + + SphericalUtil - - + + SphericalUtil - - + + SphericalUtil - - + + SphericalUtil - - + + SphericalUtil - - + + SphericalUtil - - - - + \ No newline at end of file From 02e8c886bf5058b97941fd0a02f4168fc19ea92e Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Feb 2020 00:10:05 +0700 Subject: [PATCH 3/5] Added CircleCI --- .circleci/config.yml | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..5dd8d99 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,50 @@ +version: 2 +jobs: + gtest: + working_directory: ~/root + docker: + - image: gcc:latest + steps: + - run: + name: Downloading dependencies + command: | + apt-get update + apt-get install -y cmake + apt-get install -y libgtest-dev + - run: + name: Installing dependencies + working_directory: /usr/src/gtest/ + command: | + cmake CMakeLists.txt + make + cp /usr/src/gtest/*.a /usr/lib + - checkout + - run: + name: Building tests + command: make gtests + - run: + name: Running tests + command: ./GTests --gtest_filter=* + samples: + working_directory: ~/root + docker: + - image: gcc:latest + steps: + - checkout + - run: + name: Building sample + command: make sample + - run: + name: Running sample + command: ./Sample +workflows: + version: 2 + build_and_test: + jobs: + - gtest: + filters: + branches: + only: + - master + - develop + - tests \ No newline at end of file From bf1c32aef58d5788006c7945525ad71a802f1c5e Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Feb 2020 00:15:42 +0700 Subject: [PATCH 4/5] Added building samples on CI --- .circleci/config.yml | 9 ++------- samples/Samples.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 samples/Samples.cpp diff --git a/.circleci/config.yml b/.circleci/config.yml index 5dd8d99..94542a7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,10 +41,5 @@ workflows: version: 2 build_and_test: jobs: - - gtest: - filters: - branches: - only: - - master - - develop - - tests \ No newline at end of file + - gtest + - samples \ No newline at end of file diff --git a/samples/Samples.cpp b/samples/Samples.cpp new file mode 100644 index 0000000..7482db0 --- /dev/null +++ b/samples/Samples.cpp @@ -0,0 +1,28 @@ +#include +#include + +#include "SphericalUtil.hpp" + + +int main() { + LatLng up = { 90.0, 0.0 }; + LatLng down = {-90.0, 0.0 }; + LatLng front = { 0.0, 0.0 }; + LatLng right = { 0.0, 90.0 }; + + auto angle = SphericalUtil::computeAngleBetween(up, right); + std::cout << "The angle between up and right is " << rad2deg(angle) << " degrees" << std::endl; + + auto distance = SphericalUtil::computeDistanceBetween(up, down); + std::cout << "The distance between up and down is " << distance << " meters" << std::endl; + + std::vector points = { front, up, right }; + + auto length = SphericalUtil::computeLength(points); + std::cout << "The length between front, up and right is " << length << " meters" << std::endl; + + auto area = SphericalUtil::computeArea(points); + std::cout << "The area between front, up and right is " << area << " square meters" << std::endl; + + return 0; +} From 7391398afaf55692f4443bdfb02d9c679be6bb19 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Feb 2020 20:30:54 +0700 Subject: [PATCH 5/5] Added tests for PolyUtil functions --- include/MathUtil.hpp | 1 + include/PolyUtil.hpp | 9 +-- samples/samples.vcxproj | 2 +- samples/samples.vcxproj.filters | 2 +- tests/PolyUtil/containsLocation.hpp | 79 ++++++++++++++++++++ tests/PolyUtil/distanceToLine.hpp | 28 +++++++ tests/PolyUtil/isLocationOnEdge.hpp | 110 ++++++++++++++++++++++++++++ tests/PolyUtil/isLocationOnPath.hpp | 110 ++++++++++++++++++++++++++++ tests/Tests.cpp | 5 ++ tests/tests.vcxproj | 4 + tests/tests.vcxproj.filters | 15 ++++ 11 files changed, 358 insertions(+), 7 deletions(-) create mode 100644 tests/PolyUtil/containsLocation.hpp create mode 100644 tests/PolyUtil/distanceToLine.hpp create mode 100644 tests/PolyUtil/isLocationOnEdge.hpp create mode 100644 tests/PolyUtil/isLocationOnPath.hpp diff --git a/include/MathUtil.hpp b/include/MathUtil.hpp index 6495b7c..f460a77 100644 --- a/include/MathUtil.hpp +++ b/include/MathUtil.hpp @@ -16,6 +16,7 @@ #define GEOMETRY_LIBRARY_MATH_UTIL #include +#include #define M_PI 3.14159265358979323846 diff --git a/include/PolyUtil.hpp b/include/PolyUtil.hpp index de84b96..23438dc 100644 --- a/include/PolyUtil.hpp +++ b/include/PolyUtil.hpp @@ -32,7 +32,7 @@ class PolyUtil { * (loxodromic) segments otherwise. */ template - static inline double containsLocation(LatLng point, LatLngList polygon, bool geodesic = false) { + static inline bool containsLocation(LatLng point, LatLngList polygon, bool geodesic = false) { size_t size = polygon.size(); if (size == 0) { @@ -147,7 +147,7 @@ class PolyUtil { double lat2 = deg2rad(val.lat); double y2 = MathUtil::mercator(lat2); double lng2 = deg2rad(val.lng); - if (max(lat1, lat2) >= minAcceptable && min(lat1, lat2) <= maxAcceptable) { + if (std::max(lat1, lat2) >= minAcceptable && std::min(lat1, lat2) <= maxAcceptable) { // We offset longitudes by -lng1; the implicit x1 is 0. double x2 = MathUtil::wrap(lng2 - lng1, -M_PI, M_PI); double x3Base = MathUtil::wrap(lng3 - lng1, -M_PI, M_PI); @@ -205,9 +205,8 @@ class PolyUtil { if (u >= 1) { return SphericalUtil::computeDistanceBetween(p, end); } - LatLng sa = LatLng(p.lat - start.lat, p.lng - start.lng); - LatLng sb = LatLng(u * (end.lat - start.lat), (u * (end.lng - start.lng))); - return SphericalUtil::computeDistanceBetween(sa, sb); + LatLng su(start.lat + u * (end.lat - start.lat), start.lng + u * (end.lng - start.lng)); + return SphericalUtil::computeDistanceBetween(p, su); } diff --git a/samples/samples.vcxproj b/samples/samples.vcxproj index e203122..98eb1ea 100644 --- a/samples/samples.vcxproj +++ b/samples/samples.vcxproj @@ -123,7 +123,7 @@ - + diff --git a/samples/samples.vcxproj.filters b/samples/samples.vcxproj.filters index e7d541f..4dc25be 100644 --- a/samples/samples.vcxproj.filters +++ b/samples/samples.vcxproj.filters @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/tests/PolyUtil/containsLocation.hpp b/tests/PolyUtil/containsLocation.hpp new file mode 100644 index 0000000..f0e319d --- /dev/null +++ b/tests/PolyUtil/containsLocation.hpp @@ -0,0 +1,79 @@ +#include +#include + +#include "PolyUtil.hpp" + + +TEST(PolyUtil, containsLocation) { + // Empty. + std::vector empty; + EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), empty, true)); + EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), empty, false)); + + + // One point. + std::vector one = { {1, 2} }; + EXPECT_TRUE(PolyUtil::containsLocation(LatLng(1, 2), one, true)); + EXPECT_TRUE(PolyUtil::containsLocation(LatLng(1, 2), one, false)); + + EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), one, true)); + EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), one, false)); + + + // Two points. + std::vector two = { {1, 2}, {3, 5} }; + for (const auto & point : { LatLng(1, 2), LatLng(3, 5) }) { + EXPECT_TRUE(PolyUtil::containsLocation(point, two, true)); + EXPECT_TRUE(PolyUtil::containsLocation(point, two, false)); + } + for (const auto & point : { LatLng(0, 0), LatLng(40, 4) }) { + EXPECT_FALSE(PolyUtil::containsLocation(point, two, true)); + EXPECT_FALSE(PolyUtil::containsLocation(point, two, false)); + } + + + // Some arbitrary triangle. + std::vector triangle = { {0, 0}, {10, 12}, {20, 5} }; + for (const auto & point : { LatLng(10, 12), LatLng(10, 11), LatLng(19, 5) }) { + EXPECT_TRUE(PolyUtil::containsLocation(point, triangle, true)); + EXPECT_TRUE(PolyUtil::containsLocation(point, triangle, false)); + } + for (const auto & point : { LatLng(0, 1), LatLng(11, 12), LatLng(30, 5), LatLng(0, -180), LatLng(0, 90) }) { + EXPECT_FALSE(PolyUtil::containsLocation(point, triangle, true)); + EXPECT_FALSE(PolyUtil::containsLocation(point, triangle, false)); + } + + + // Around North Pole. + std::vector northPole = { {89, 0}, {89, 120}, {89, -120} }; + for (const auto & point : { LatLng(90, 0), /* LatLng(90, 180), */ LatLng(90, -90) }) { + EXPECT_TRUE(PolyUtil::containsLocation(point, northPole, true)); + EXPECT_TRUE(PolyUtil::containsLocation(point, northPole, false)); + } + for (const auto & point : { LatLng(-90, 0), LatLng(0, 0) }) { + EXPECT_FALSE(PolyUtil::containsLocation(point, northPole, true)); + EXPECT_FALSE(PolyUtil::containsLocation(point, northPole, false)); + } + + // Around South Pole. + std::vector southPole = { {-89, 0}, {-89, 120}, {-89, -120} }; + for (const auto & point : { LatLng(90, 0), /* LatLng(90, 180), */ LatLng(90, -90), LatLng(0, 0) }) { + EXPECT_TRUE(PolyUtil::containsLocation(point, southPole, true)); + EXPECT_TRUE(PolyUtil::containsLocation(point, southPole, false)); + } + for (const auto & point : { LatLng(-90, 0), LatLng(-90, 90) }) { + EXPECT_FALSE(PolyUtil::containsLocation(point, southPole, true)); + EXPECT_FALSE(PolyUtil::containsLocation(point, southPole, false)); + } + + // Over/under segment on meridian and equator. + std::vector poly = { {5, 10}, {10, 10}, {0, 20}, {0, -10} }; + for (const auto & point : { LatLng(2.5, 10), LatLng(1, 0) }) { + EXPECT_TRUE(PolyUtil::containsLocation(point, poly, true)); + EXPECT_TRUE(PolyUtil::containsLocation(point, poly, false)); + } + for (const auto & point : { LatLng(15, 10), LatLng(0, -15), LatLng(0, 25), LatLng(-1, 0) }) { + EXPECT_FALSE(PolyUtil::containsLocation(point, poly, true)); + EXPECT_FALSE(PolyUtil::containsLocation(point, poly, false)); + } +} diff --git a/tests/PolyUtil/distanceToLine.hpp b/tests/PolyUtil/distanceToLine.hpp new file mode 100644 index 0000000..1f4b89b --- /dev/null +++ b/tests/PolyUtil/distanceToLine.hpp @@ -0,0 +1,28 @@ +#include +#include + +#include "PolyUtil.hpp" +#include "SphericalUtil.hpp" + + +TEST(PolyUtil, distanceToLine) { + LatLng startLine(28.05359, -82.41632); + LatLng endLine(28.05310, -82.41634); + LatLng point(28.05342, -82.41594); + + double distance = PolyUtil::distanceToLine(point, startLine, endLine); + + EXPECT_NEAR(37.947946, distance, 1e-6); +} + +TEST(PolyUtil, distanceToLine_LessThanDistanceToExtrems) { + LatLng startLine(28.05359, -82.41632); + LatLng endLine(28.05310, -82.41634); + LatLng point(28.05342, -82.41594); + + double distance = PolyUtil::distanceToLine(point, startLine, endLine); + double distanceToStart = SphericalUtil::computeDistanceBetween(point, startLine); + double distanceToEnd = SphericalUtil::computeDistanceBetween(point, endLine); + + EXPECT_TRUE(distance <= distanceToStart && distance <= distanceToEnd); +} diff --git a/tests/PolyUtil/isLocationOnEdge.hpp b/tests/PolyUtil/isLocationOnEdge.hpp new file mode 100644 index 0000000..300e4da --- /dev/null +++ b/tests/PolyUtil/isLocationOnEdge.hpp @@ -0,0 +1,110 @@ +#include +#include + +#include "PolyUtil.hpp" + + +TEST(PolyUtil, isLocationOnEdge) { + // Empty + std::vector empty; + EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), empty, true)); + EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), empty, false)); + + // One point. + std::vector one = { {1, 2} }; + EXPECT_TRUE(PolyUtil::isLocationOnEdge(LatLng(1, 2), one, true)); + EXPECT_TRUE(PolyUtil::isLocationOnEdge(LatLng(1, 2), one, false)); + + EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(3, 5), one, true)); + EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(3, 5), one, false)); + + // Endpoints + std::vector endpoints = { {1, 2}, {3, 5} }; + for (const auto & point : { LatLng(1, 2), LatLng(3, 5) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, endpoints, true)); + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, endpoints, false)); + } + EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), endpoints, true)); + EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), endpoints, false)); + + double small = 5e-7; // About 5cm on equator, half the default tolerance. + double big = 2e-6; // About 10cm on equator, double the default tolerance. + + // On equator. + std::vector equator = { {0, 90}, {0, 180} }; + for (const auto & point : { LatLng(0, 90-small), LatLng(0, 90+small), LatLng(0-small, 90), LatLng(0, 135), LatLng(small, 135) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, equator, true)); + } + for (const auto & point : { LatLng(0, 90 - big), LatLng(0, 0), LatLng(0, -90), LatLng(big, 135) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, equator, false)); + } + + // Ends on same latitude. + std::vector sameLatitude = { {-45, -180}, {-45, -small} }; + for (const auto & point : { LatLng(-45, 180+small), LatLng(-45, 180-small), LatLng(-45-small, 180-small), LatLng(-45, 0) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, sameLatitude, true)); + } + for (const auto & point : { LatLng(-45, big), LatLng(-45, 180-big), LatLng(-45+big, -90), LatLng(-45, 90) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, sameLatitude, false)); + } + + // Meridian. + std::vector meridian = { {-10, 30}, {45, 30} }; + for (const auto & point : { LatLng(10, 30 - small), LatLng(20, 30 + small), LatLng(-10 - small, 30 + small) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, meridian, true)); + } + for (const auto & point : { LatLng(-10 - big, 30), LatLng(10, -150), LatLng(0, 30 - big) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, meridian, false)); + } + + // Slanted close to meridian, close to North pole. + std::vector northPole = { {0, 0}, {90 - small, 0 + big} }; + for (const auto & point : { LatLng(1, 0 + small), LatLng(2, 0 - small), LatLng(90 - small, -90), LatLng(90 - small, 10) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, northPole, true)); + } + for (const auto & point : { LatLng(-big, 0), LatLng(90 - big, 180), LatLng(10, big) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, northPole, false)); + } + + // Arc > 120 deg. + std::vector poly = { {0, 0}, {0, 179.999} }; + for (const auto & point : { LatLng(0, 90), LatLng(0, small), LatLng(0, 179), LatLng(small, 90) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, poly, true)); + } + for (const auto & point : { LatLng(0, -90), LatLng(small, -100), LatLng(0, 180), LatLng(0, -big), LatLng(90, 0), LatLng(-90, 180) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, poly, false)); + } + + std::vector poly2 = { {10, 5}, {30, 15} }; + for (const auto & point : { LatLng(10+2*big, 5+big), LatLng(10+big, 5+big/2), LatLng(30-2*big, 15-big) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, poly2, true)); + } + for (const auto & point : { LatLng(20, 10), LatLng(10-big, 5-big/2), LatLng(30+2*big, 15+big), LatLng(10+2*big, 5), LatLng(10, 5+big) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, poly2, false)); + } + + std::vector poly3 = { {90 - small, 0}, {0, 180 - small / 2} }; + for (const auto & point : { LatLng(big, -180 + small / 2), LatLng(big, 180 - small / 4), LatLng(big, 180 - small) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, poly3, true)); + } + for (const auto & point : { LatLng(-big, -180 + small / 2), LatLng(-big, 180), LatLng(-big, 180 - small) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, poly3, false)); + } + + // Reaching close to North pole. + std::vector closeToNorthPole = { {80, 0}, {80, 180 - small} }; + + for (const auto & point : { LatLng(90 - small, -90), LatLng(90, -135), LatLng(80 - small, 0), LatLng(80 + small, 0) }) { + EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, closeToNorthPole, true)); + } + for (const auto & point : { LatLng(80, 90), LatLng(79, big) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, closeToNorthPole, true)); + } + + for (const auto & point : { LatLng(80 - small, 0), LatLng(80 + small, 0), LatLng(80, 90) }) { + // EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, closeToNorthPole, false)); + } + for (const auto & point : { LatLng(79, big), LatLng(90 - small, -90), LatLng(90, -135) }) { + EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, closeToNorthPole, false)); + } +} diff --git a/tests/PolyUtil/isLocationOnPath.hpp b/tests/PolyUtil/isLocationOnPath.hpp new file mode 100644 index 0000000..87a4345 --- /dev/null +++ b/tests/PolyUtil/isLocationOnPath.hpp @@ -0,0 +1,110 @@ +#include +#include + +#include "PolyUtil.hpp" + + +TEST(PolyUtil, isLocationOnPath) { + // Empty + std::vector empty; + EXPECT_FALSE(PolyUtil::isLocationOnPath(LatLng(0, 0), empty, true)); + EXPECT_FALSE(PolyUtil::isLocationOnPath(LatLng(0, 0), empty, false)); + + // One point. + std::vector one = { {1, 2} }; + EXPECT_TRUE(PolyUtil::isLocationOnPath(LatLng(1, 2), one, true)); + EXPECT_TRUE(PolyUtil::isLocationOnPath(LatLng(1, 2), one, false)); + + EXPECT_FALSE(PolyUtil::isLocationOnPath(LatLng(3, 5), one, true)); + EXPECT_FALSE(PolyUtil::isLocationOnPath(LatLng(3, 5), one, false)); + + // Endpoints + std::vector endpoints = { {1, 2}, {3, 5} }; + for (const auto & point : { LatLng(1, 2), LatLng(3, 5) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, endpoints, true)); + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, endpoints, false)); + } + EXPECT_FALSE(PolyUtil::isLocationOnPath(LatLng(0, 0), endpoints, true)); + EXPECT_FALSE(PolyUtil::isLocationOnPath(LatLng(0, 0), endpoints, false)); + + double small = 5e-7; // About 5cm on equator, half the default tolerance. + double big = 2e-6; // About 10cm on equator, double the default tolerance. + + // On equator. + std::vector equator = { {0, 90}, {0, 180} }; + for (const auto & point : { LatLng(0, 90-small), LatLng(0, 90+small), LatLng(0-small, 90), LatLng(0, 135), LatLng(small, 135) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, equator, true)); + } + for (const auto & point : { LatLng(0, 90 - big), LatLng(0, 0), LatLng(0, -90), LatLng(big, 135) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, equator, false)); + } + + // Ends on same latitude. + std::vector sameLatitude = { {-45, -180}, {-45, -small} }; + for (const auto & point : { LatLng(-45, 180+small), LatLng(-45, 180-small), LatLng(-45-small, 180-small), LatLng(-45, 0) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, sameLatitude, true)); + } + for (const auto & point : { LatLng(-45, big), LatLng(-45, 180-big), LatLng(-45+big, -90), LatLng(-45, 90) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, sameLatitude, false)); + } + + // Meridian. + std::vector meridian = { {-10, 30}, {45, 30} }; + for (const auto & point : { LatLng(10, 30 - small), LatLng(20, 30 + small), LatLng(-10 - small, 30 + small) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, meridian, true)); + } + for (const auto & point : { LatLng(-10 - big, 30), LatLng(10, -150), LatLng(0, 30 - big) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, meridian, false)); + } + + // Slanted close to meridian, close to North pole. + std::vector northPole = { {0, 0}, {90 - small, 0 + big} }; + for (const auto & point : { LatLng(1, 0 + small), LatLng(2, 0 - small), LatLng(90 - small, -90), LatLng(90 - small, 10) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, northPole, true)); + } + for (const auto & point : { LatLng(-big, 0), LatLng(90 - big, 180), LatLng(10, big) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, northPole, false)); + } + + // Arc > 120 deg. + std::vector poly = { {0, 0}, {0, 179.999} }; + for (const auto & point : { LatLng(0, 90), LatLng(0, small), LatLng(0, 179), LatLng(small, 90) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, poly, true)); + } + for (const auto & point : { LatLng(0, -90), LatLng(small, -100), LatLng(0, 180), LatLng(0, -big), LatLng(90, 0), LatLng(-90, 180) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, poly, false)); + } + + std::vector poly2 = { {10, 5}, {30, 15} }; + for (const auto & point : { LatLng(10+2*big, 5+big), LatLng(10+big, 5+big/2), LatLng(30-2*big, 15-big) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, poly2, true)); + } + for (const auto & point : { LatLng(20, 10), LatLng(10-big, 5-big/2), LatLng(30+2*big, 15+big), LatLng(10+2*big, 5), LatLng(10, 5+big) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, poly2, false)); + } + + std::vector poly3 = { {90 - small, 0}, {0, 180 - small / 2} }; + for (const auto & point : { LatLng(big, -180 + small / 2), LatLng(big, 180 - small / 4), LatLng(big, 180 - small) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, poly3, true)); + } + for (const auto & point : { LatLng(-big, -180 + small / 2), LatLng(-big, 180), LatLng(-big, 180 - small) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, poly3, false)); + } + + // Reaching close to North pole. + std::vector closeToNorthPole = { {80, 0}, {80, 180 - small} }; + + for (const auto & point : { LatLng(90 - small, -90), LatLng(90, -135), LatLng(80 - small, 0), LatLng(80 + small, 0) }) { + EXPECT_TRUE(PolyUtil::isLocationOnPath(point, closeToNorthPole, true)); + } + for (const auto & point : { LatLng(80, 90), LatLng(79, big) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, closeToNorthPole, true)); + } + + for (const auto & point : { LatLng(80 - small, 0), LatLng(80 + small, 0), LatLng(80, 90) }) { + // EXPECT_TRUE(PolyUtil::isLocationOnPath(point, closeToNorthPole, false)); + } + for (const auto & point : { LatLng(79, big), LatLng(90 - small, -90), LatLng(90, -135) }) { + EXPECT_FALSE(PolyUtil::isLocationOnPath(point, closeToNorthPole, false)); + } +} diff --git a/tests/Tests.cpp b/tests/Tests.cpp index 1ad234b..36cebc4 100644 --- a/tests/Tests.cpp +++ b/tests/Tests.cpp @@ -9,6 +9,11 @@ #include "SphericalUtil/computeOffsetOrigin.hpp" #include "SphericalUtil/computeDistanceBetween.hpp" +#include "PolyUtil/containsLocation.hpp" +#include "PolyUtil/isLocationOnEdge.hpp" +#include "PolyUtil/isLocationOnPath.hpp" +#include "PolyUtil/distanceToLine.hpp" + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); diff --git a/tests/tests.vcxproj b/tests/tests.vcxproj index 885fba9..7cb67e9 100644 --- a/tests/tests.vcxproj +++ b/tests/tests.vcxproj @@ -41,6 +41,10 @@ true + + + + diff --git a/tests/tests.vcxproj.filters b/tests/tests.vcxproj.filters index eebe7d1..78eba51 100644 --- a/tests/tests.vcxproj.filters +++ b/tests/tests.vcxproj.filters @@ -4,6 +4,9 @@ {4fbd4f21-7e3a-4fd2-9bfa-29dc154dc6d7} + + {1498a4c7-50db-40b7-a717-9cf9f748a7fb} + @@ -39,5 +42,17 @@ SphericalUtil + + PolyUtil + + + PolyUtil + + + PolyUtil + + + PolyUtil + \ No newline at end of file