Skip to content

Added tests and CI #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 9, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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
- samples
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Gtests
Sample

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions include/MathUtil.hpp
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
#define GEOMETRY_LIBRARY_MATH_UTIL

#include <cmath>
#include <algorithm>

#define M_PI 3.14159265358979323846

9 changes: 4 additions & 5 deletions include/PolyUtil.hpp
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ class PolyUtil {
* (loxodromic) segments otherwise.
*/
template <typename LatLngList>
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);
}


28 changes: 28 additions & 0 deletions samples/Samples.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <iostream>
#include <vector>

#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<LatLng> 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;
}
2 changes: 1 addition & 1 deletion samples/samples.vcxproj
Original file line number Diff line number Diff line change
@@ -123,7 +123,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="samples.cpp" />
<ClCompile Include="Samples.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
2 changes: 1 addition & 1 deletion samples/samples.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="samples.cpp" />
<ClCompile Include="Samples.cpp" />
</ItemGroup>
</Project>
79 changes: 79 additions & 0 deletions tests/PolyUtil/containsLocation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include <gtest/gtest.h>
#include <vector>

#include "PolyUtil.hpp"


TEST(PolyUtil, containsLocation) {
// Empty.
std::vector<LatLng> empty;
EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), empty, true));
EXPECT_FALSE(PolyUtil::containsLocation(LatLng(0, 0), empty, false));


// One point.
std::vector<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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));
}
}
28 changes: 28 additions & 0 deletions tests/PolyUtil/distanceToLine.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <gtest/gtest.h>
#include <vector>

#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);
}
110 changes: 110 additions & 0 deletions tests/PolyUtil/isLocationOnEdge.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include <gtest/gtest.h>
#include <vector>

#include "PolyUtil.hpp"


TEST(PolyUtil, isLocationOnEdge) {
// Empty
std::vector<LatLng> empty;
EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), empty, true));
EXPECT_FALSE(PolyUtil::isLocationOnEdge(LatLng(0, 0), empty, false));

// One point.
std::vector<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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<LatLng> 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));
}
}
Loading