Skip to content

Commit 388126d

Browse files
authored
Merge pull request #4 from gistrec/tests
Added tests and CI
2 parents 33c6e17 + 7391398 commit 388126d

25 files changed

+861
-31
lines changed

Diff for: .circleci/config.yml

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
version: 2
2+
jobs:
3+
gtest:
4+
working_directory: ~/root
5+
docker:
6+
- image: gcc:latest
7+
steps:
8+
- run:
9+
name: Downloading dependencies
10+
command: |
11+
apt-get update
12+
apt-get install -y cmake
13+
apt-get install -y libgtest-dev
14+
- run:
15+
name: Installing dependencies
16+
working_directory: /usr/src/gtest/
17+
command: |
18+
cmake CMakeLists.txt
19+
make
20+
cp /usr/src/gtest/*.a /usr/lib
21+
- checkout
22+
- run:
23+
name: Building tests
24+
command: make gtests
25+
- run:
26+
name: Running tests
27+
command: ./GTests --gtest_filter=*
28+
samples:
29+
working_directory: ~/root
30+
docker:
31+
- image: gcc:latest
32+
steps:
33+
- checkout
34+
- run:
35+
name: Building sample
36+
command: make sample
37+
- run:
38+
name: Running sample
39+
command: ./Sample
40+
workflows:
41+
version: 2
42+
build_and_test:
43+
jobs:
44+
- gtest
45+
- samples

Diff for: .gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
Gtests
2+
Sample
3+
14
## Ignore Visual Studio temporary files, build results, and
25
## files generated by popular Visual Studio add-ons.
36

Diff for: Makefile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
sample :
2+
g++ samples/Samples.cpp \
3+
-std=c++14 -Iinclude/ \
4+
-o Sample
5+
6+
gtests :
7+
g++ tests/Tests.cpp \
8+
-std=c++14 -Iinclude/ \
9+
-lgtest -pthread \
10+
-o GTests

Diff for: include/MathUtil.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define GEOMETRY_LIBRARY_MATH_UTIL
1717

1818
#include <cmath>
19+
#include <algorithm>
1920

2021
#define M_PI 3.14159265358979323846
2122

Diff for: include/PolyUtil.hpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class PolyUtil {
3232
* (loxodromic) segments otherwise.
3333
*/
3434
template <typename LatLngList>
35-
static inline double containsLocation(LatLng point, LatLngList polygon, bool geodesic = false) {
35+
static inline bool containsLocation(LatLng point, LatLngList polygon, bool geodesic = false) {
3636
size_t size = polygon.size();
3737

3838
if (size == 0) {
@@ -147,7 +147,7 @@ class PolyUtil {
147147
double lat2 = deg2rad(val.lat);
148148
double y2 = MathUtil::mercator(lat2);
149149
double lng2 = deg2rad(val.lng);
150-
if (max(lat1, lat2) >= minAcceptable && min(lat1, lat2) <= maxAcceptable) {
150+
if (std::max(lat1, lat2) >= minAcceptable && std::min(lat1, lat2) <= maxAcceptable) {
151151
// We offset longitudes by -lng1; the implicit x1 is 0.
152152
double x2 = MathUtil::wrap(lng2 - lng1, -M_PI, M_PI);
153153
double x3Base = MathUtil::wrap(lng3 - lng1, -M_PI, M_PI);
@@ -205,9 +205,8 @@ class PolyUtil {
205205
if (u >= 1) {
206206
return SphericalUtil::computeDistanceBetween(p, end);
207207
}
208-
LatLng sa = LatLng(p.lat - start.lat, p.lng - start.lng);
209-
LatLng sb = LatLng(u * (end.lat - start.lat), (u * (end.lng - start.lng)));
210-
return SphericalUtil::computeDistanceBetween(sa, sb);
208+
LatLng su(start.lat + u * (end.lat - start.lat), start.lng + u * (end.lng - start.lng));
209+
return SphericalUtil::computeDistanceBetween(p, su);
211210
}
212211

213212

Diff for: samples/Samples.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <iostream>
2+
#include <vector>
3+
4+
#include "SphericalUtil.hpp"
5+
6+
7+
int main() {
8+
LatLng up = { 90.0, 0.0 };
9+
LatLng down = {-90.0, 0.0 };
10+
LatLng front = { 0.0, 0.0 };
11+
LatLng right = { 0.0, 90.0 };
12+
13+
auto angle = SphericalUtil::computeAngleBetween(up, right);
14+
std::cout << "The angle between up and right is " << rad2deg(angle) << " degrees" << std::endl;
15+
16+
auto distance = SphericalUtil::computeDistanceBetween(up, down);
17+
std::cout << "The distance between up and down is " << distance << " meters" << std::endl;
18+
19+
std::vector<LatLng> points = { front, up, right };
20+
21+
auto length = SphericalUtil::computeLength(points);
22+
std::cout << "The length between front, up and right is " << length << " meters" << std::endl;
23+
24+
auto area = SphericalUtil::computeArea(points);
25+
std::cout << "The area between front, up and right is " << area << " square meters" << std::endl;
26+
27+
return 0;
28+
}

Diff for: samples/samples.vcxproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
</Link>
124124
</ItemDefinitionGroup>
125125
<ItemGroup>
126-
<ClCompile Include="samples.cpp" />
126+
<ClCompile Include="Samples.cpp" />
127127
</ItemGroup>
128128
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
129129
<ImportGroup Label="ExtensionTargets">

Diff for: samples/samples.vcxproj.filters

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<ItemGroup>
4-
<ClCompile Include="samples.cpp" />
4+
<ClCompile Include="Samples.cpp" />
55
</ItemGroup>
66
</Project>

Diff for: tests/PolyUtil/containsLocation.hpp

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include <gtest/gtest.h>
2+
#include <vector>
3+
4+
#include "PolyUtil.hpp"
5+
6+
7+
TEST(PolyUtil, containsLocation) {
8+
// Empty.
9+
std::vector<LatLng> empty;
10+
EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), empty, true));
11+
EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), empty, false));
12+
13+
14+
// One point.
15+
std::vector<LatLng> one = { {1, 2} };
16+
EXPECT_TRUE(PolyUtil::containsLocation(LatLng(1, 2), one, true));
17+
EXPECT_TRUE(PolyUtil::containsLocation(LatLng(1, 2), one, false));
18+
19+
EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), one, true));
20+
EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), one, false));
21+
22+
23+
// Two points.
24+
std::vector<LatLng> two = { {1, 2}, {3, 5} };
25+
for (const auto & point : { LatLng(1, 2), LatLng(3, 5) }) {
26+
EXPECT_TRUE(PolyUtil::containsLocation(point, two, true));
27+
EXPECT_TRUE(PolyUtil::containsLocation(point, two, false));
28+
}
29+
for (const auto & point : { LatLng(0, 0), LatLng(40, 4) }) {
30+
EXPECT_FALSE(PolyUtil::containsLocation(point, two, true));
31+
EXPECT_FALSE(PolyUtil::containsLocation(point, two, false));
32+
}
33+
34+
35+
// Some arbitrary triangle.
36+
std::vector<LatLng> triangle = { {0, 0}, {10, 12}, {20, 5} };
37+
for (const auto & point : { LatLng(10, 12), LatLng(10, 11), LatLng(19, 5) }) {
38+
EXPECT_TRUE(PolyUtil::containsLocation(point, triangle, true));
39+
EXPECT_TRUE(PolyUtil::containsLocation(point, triangle, false));
40+
}
41+
for (const auto & point : { LatLng(0, 1), LatLng(11, 12), LatLng(30, 5), LatLng(0, -180), LatLng(0, 90) }) {
42+
EXPECT_FALSE(PolyUtil::containsLocation(point, triangle, true));
43+
EXPECT_FALSE(PolyUtil::containsLocation(point, triangle, false));
44+
}
45+
46+
47+
// Around North Pole.
48+
std::vector<LatLng> northPole = { {89, 0}, {89, 120}, {89, -120} };
49+
for (const auto & point : { LatLng(90, 0), /* LatLng(90, 180), */ LatLng(90, -90) }) {
50+
EXPECT_TRUE(PolyUtil::containsLocation(point, northPole, true));
51+
EXPECT_TRUE(PolyUtil::containsLocation(point, northPole, false));
52+
}
53+
for (const auto & point : { LatLng(-90, 0), LatLng(0, 0) }) {
54+
EXPECT_FALSE(PolyUtil::containsLocation(point, northPole, true));
55+
EXPECT_FALSE(PolyUtil::containsLocation(point, northPole, false));
56+
}
57+
58+
// Around South Pole.
59+
std::vector<LatLng> southPole = { {-89, 0}, {-89, 120}, {-89, -120} };
60+
for (const auto & point : { LatLng(90, 0), /* LatLng(90, 180), */ LatLng(90, -90), LatLng(0, 0) }) {
61+
EXPECT_TRUE(PolyUtil::containsLocation(point, southPole, true));
62+
EXPECT_TRUE(PolyUtil::containsLocation(point, southPole, false));
63+
}
64+
for (const auto & point : { LatLng(-90, 0), LatLng(-90, 90) }) {
65+
EXPECT_FALSE(PolyUtil::containsLocation(point, southPole, true));
66+
EXPECT_FALSE(PolyUtil::containsLocation(point, southPole, false));
67+
}
68+
69+
// Over/under segment on meridian and equator.
70+
std::vector<LatLng> poly = { {5, 10}, {10, 10}, {0, 20}, {0, -10} };
71+
for (const auto & point : { LatLng(2.5, 10), LatLng(1, 0) }) {
72+
EXPECT_TRUE(PolyUtil::containsLocation(point, poly, true));
73+
EXPECT_TRUE(PolyUtil::containsLocation(point, poly, false));
74+
}
75+
for (const auto & point : { LatLng(15, 10), LatLng(0, -15), LatLng(0, 25), LatLng(-1, 0) }) {
76+
EXPECT_FALSE(PolyUtil::containsLocation(point, poly, true));
77+
EXPECT_FALSE(PolyUtil::containsLocation(point, poly, false));
78+
}
79+
}

Diff for: tests/PolyUtil/distanceToLine.hpp

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <gtest/gtest.h>
2+
#include <vector>
3+
4+
#include "PolyUtil.hpp"
5+
#include "SphericalUtil.hpp"
6+
7+
8+
TEST(PolyUtil, distanceToLine) {
9+
LatLng startLine(28.05359, -82.41632);
10+
LatLng endLine(28.05310, -82.41634);
11+
LatLng point(28.05342, -82.41594);
12+
13+
double distance = PolyUtil::distanceToLine(point, startLine, endLine);
14+
15+
EXPECT_NEAR(37.947946, distance, 1e-6);
16+
}
17+
18+
TEST(PolyUtil, distanceToLine_LessThanDistanceToExtrems) {
19+
LatLng startLine(28.05359, -82.41632);
20+
LatLng endLine(28.05310, -82.41634);
21+
LatLng point(28.05342, -82.41594);
22+
23+
double distance = PolyUtil::distanceToLine(point, startLine, endLine);
24+
double distanceToStart = SphericalUtil::computeDistanceBetween(point, startLine);
25+
double distanceToEnd = SphericalUtil::computeDistanceBetween(point, endLine);
26+
27+
EXPECT_TRUE(distance <= distanceToStart && distance <= distanceToEnd);
28+
}

Diff for: tests/PolyUtil/isLocationOnEdge.hpp

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#include <gtest/gtest.h>
2+
#include <vector>
3+
4+
#include "PolyUtil.hpp"
5+
6+
7+
TEST(PolyUtil, isLocationOnEdge) {
8+
// Empty
9+
std::vector<LatLng> empty;
10+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), empty, true));
11+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), empty, false));
12+
13+
// One point.
14+
std::vector<LatLng> one = { {1, 2} };
15+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(LatLng(1, 2), one, true));
16+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(LatLng(1, 2), one, false));
17+
18+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(3, 5), one, true));
19+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(3, 5), one, false));
20+
21+
// Endpoints
22+
std::vector<LatLng> endpoints = { {1, 2}, {3, 5} };
23+
for (const auto & point : { LatLng(1, 2), LatLng(3, 5) }) {
24+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, endpoints, true));
25+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, endpoints, false));
26+
}
27+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), endpoints, true));
28+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), endpoints, false));
29+
30+
double small = 5e-7; // About 5cm on equator, half the default tolerance.
31+
double big = 2e-6; // About 10cm on equator, double the default tolerance.
32+
33+
// On equator.
34+
std::vector<LatLng> equator = { {0, 90}, {0, 180} };
35+
for (const auto & point : { LatLng(0, 90-small), LatLng(0, 90+small), LatLng(0-small, 90), LatLng(0, 135), LatLng(small, 135) }) {
36+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, equator, true));
37+
}
38+
for (const auto & point : { LatLng(0, 90 - big), LatLng(0, 0), LatLng(0, -90), LatLng(big, 135) }) {
39+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, equator, false));
40+
}
41+
42+
// Ends on same latitude.
43+
std::vector<LatLng> sameLatitude = { {-45, -180}, {-45, -small} };
44+
for (const auto & point : { LatLng(-45, 180+small), LatLng(-45, 180-small), LatLng(-45-small, 180-small), LatLng(-45, 0) }) {
45+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, sameLatitude, true));
46+
}
47+
for (const auto & point : { LatLng(-45, big), LatLng(-45, 180-big), LatLng(-45+big, -90), LatLng(-45, 90) }) {
48+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, sameLatitude, false));
49+
}
50+
51+
// Meridian.
52+
std::vector<LatLng> meridian = { {-10, 30}, {45, 30} };
53+
for (const auto & point : { LatLng(10, 30 - small), LatLng(20, 30 + small), LatLng(-10 - small, 30 + small) }) {
54+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, meridian, true));
55+
}
56+
for (const auto & point : { LatLng(-10 - big, 30), LatLng(10, -150), LatLng(0, 30 - big) }) {
57+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, meridian, false));
58+
}
59+
60+
// Slanted close to meridian, close to North pole.
61+
std::vector<LatLng> northPole = { {0, 0}, {90 - small, 0 + big} };
62+
for (const auto & point : { LatLng(1, 0 + small), LatLng(2, 0 - small), LatLng(90 - small, -90), LatLng(90 - small, 10) }) {
63+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, northPole, true));
64+
}
65+
for (const auto & point : { LatLng(-big, 0), LatLng(90 - big, 180), LatLng(10, big) }) {
66+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, northPole, false));
67+
}
68+
69+
// Arc > 120 deg.
70+
std::vector<LatLng> poly = { {0, 0}, {0, 179.999} };
71+
for (const auto & point : { LatLng(0, 90), LatLng(0, small), LatLng(0, 179), LatLng(small, 90) }) {
72+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, poly, true));
73+
}
74+
for (const auto & point : { LatLng(0, -90), LatLng(small, -100), LatLng(0, 180), LatLng(0, -big), LatLng(90, 0), LatLng(-90, 180) }) {
75+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, poly, false));
76+
}
77+
78+
std::vector<LatLng> poly2 = { {10, 5}, {30, 15} };
79+
for (const auto & point : { LatLng(10+2*big, 5+big), LatLng(10+big, 5+big/2), LatLng(30-2*big, 15-big) }) {
80+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, poly2, true));
81+
}
82+
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) }) {
83+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, poly2, false));
84+
}
85+
86+
std::vector<LatLng> poly3 = { {90 - small, 0}, {0, 180 - small / 2} };
87+
for (const auto & point : { LatLng(big, -180 + small / 2), LatLng(big, 180 - small / 4), LatLng(big, 180 - small) }) {
88+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, poly3, true));
89+
}
90+
for (const auto & point : { LatLng(-big, -180 + small / 2), LatLng(-big, 180), LatLng(-big, 180 - small) }) {
91+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, poly3, false));
92+
}
93+
94+
// Reaching close to North pole.
95+
std::vector<LatLng> closeToNorthPole = { {80, 0}, {80, 180 - small} };
96+
97+
for (const auto & point : { LatLng(90 - small, -90), LatLng(90, -135), LatLng(80 - small, 0), LatLng(80 + small, 0) }) {
98+
EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, closeToNorthPole, true));
99+
}
100+
for (const auto & point : { LatLng(80, 90), LatLng(79, big) }) {
101+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, closeToNorthPole, true));
102+
}
103+
104+
for (const auto & point : { LatLng(80 - small, 0), LatLng(80 + small, 0), LatLng(80, 90) }) {
105+
// EXPECT_TRUE(PolyUtil::isLocationOnEdge(point, closeToNorthPole, false));
106+
}
107+
for (const auto & point : { LatLng(79, big), LatLng(90 - small, -90), LatLng(90, -135) }) {
108+
EXPECT_FALSE(PolyUtil::isLocationOnEdge(point, closeToNorthPole, false));
109+
}
110+
}

0 commit comments

Comments
 (0)