Use faster method for calculating distances.
fix cmakelist
This commit is contained in:
parent
6843eb1479
commit
a6cf2eee7e
@ -424,6 +424,12 @@ include_directories(SYSTEM ${RAPIDJSON_INCLUDE_DIR})
|
|||||||
|
|
||||||
set(MICROTAR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src")
|
set(MICROTAR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src")
|
||||||
include_directories(SYSTEM ${MICROTAR_INCLUDE_DIR})
|
include_directories(SYSTEM ${MICROTAR_INCLUDE_DIR})
|
||||||
|
|
||||||
|
set(MBXGEOM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/geometry.hpp-0.9.2/include")
|
||||||
|
include_directories(SYSTEM ${MBXGEOM_INCLUDE_DIR})
|
||||||
|
set(CHEAPRULER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/cheap-ruler-cpp-2.5.4/include")
|
||||||
|
include_directories(SYSTEM ${CHEAPRULER_INCLUDE_DIR})
|
||||||
|
|
||||||
add_library(MICROTAR OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src/microtar.c")
|
add_library(MICROTAR OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src/microtar.c")
|
||||||
set_property(TARGET MICROTAR PROPERTY POSITION_INDEPENDENT_CODE ON)
|
set_property(TARGET MICROTAR PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
@ -415,7 +415,7 @@ template <typename FacadeT> EdgeDistance computeEdgeDistance(const FacadeT &faca
|
|||||||
auto geometry_range = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
auto geometry_range = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
||||||
for (auto current = geometry_range.begin(); current < geometry_range.end() - 1; ++current)
|
for (auto current = geometry_range.begin(); current < geometry_range.end() - 1; ++current)
|
||||||
{
|
{
|
||||||
total_distance += util::coordinate_calculation::haversineDistance(
|
total_distance += util::coordinate_calculation::fccApproximateDistance(
|
||||||
facade.GetCoordinateOfNode(*current), facade.GetCoordinateOfNode(*std::next(current)));
|
facade.GetCoordinateOfNode(*current), facade.GetCoordinateOfNode(*std::next(current)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,9 @@ inline double radToDeg(const double radian)
|
|||||||
//! Takes the squared euclidean distance of the input coordinates. Does not return meters!
|
//! Takes the squared euclidean distance of the input coordinates. Does not return meters!
|
||||||
std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rhs);
|
std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rhs);
|
||||||
|
|
||||||
|
double fccApproximateDistance(const Coordinate first_coordinate,
|
||||||
|
const Coordinate second_coordinate);
|
||||||
|
|
||||||
double haversineDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
|
double haversineDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
|
||||||
|
|
||||||
double greatCircleDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
|
double greatCircleDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
#include <mapbox/cheap_ruler.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@ -18,6 +20,30 @@ namespace util
|
|||||||
namespace coordinate_calculation
|
namespace coordinate_calculation
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
mapbox::cheap_ruler::CheapRuler cheap_ruler_cache[] = {
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-90, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-80, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-70, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-60, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-50, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-40, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-30, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-20, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(-10, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(0, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(10, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(20, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(30, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(40, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(50, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(60, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(70, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(80, mapbox::cheap_ruler::CheapRuler::Meters),
|
||||||
|
mapbox::cheap_ruler::CheapRuler(90, mapbox::cheap_ruler::CheapRuler::Meters)};
|
||||||
|
}
|
||||||
|
|
||||||
// Does not project the coordinates!
|
// Does not project the coordinates!
|
||||||
std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rhs)
|
std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rhs)
|
||||||
{
|
{
|
||||||
@ -32,6 +58,19 @@ std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rh
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uses method described here:
|
||||||
|
// https://www.gpo.gov/fdsys/pkg/CFR-2005-title47-vol4/pdf/CFR-2005-title47-vol4-sec73-208.pdf
|
||||||
|
// should be within 0.1% or so of Vincenty method (assuming 19 buckets are enough)
|
||||||
|
// Should be more faster and more precise than Haversine
|
||||||
|
double fccApproximateDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
|
||||||
|
{
|
||||||
|
const auto lon1 = static_cast<double>(util::toFloating(coordinate_1.lon));
|
||||||
|
const auto lat1 = static_cast<double>(util::toFloating(coordinate_1.lat));
|
||||||
|
const auto lon2 = static_cast<double>(util::toFloating(coordinate_2.lon));
|
||||||
|
const auto lat2 = static_cast<double>(util::toFloating(coordinate_2.lat));
|
||||||
|
return cheap_ruler_cache[std::lround(lat1 / 10) + 9].distance({lon1, lat1}, {lon2, lat2});
|
||||||
|
}
|
||||||
|
|
||||||
double haversineDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
|
double haversineDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
|
||||||
{
|
{
|
||||||
auto lon1 = static_cast<int>(coordinate_1.lon);
|
auto lon1 = static_cast<int>(coordinate_1.lon);
|
||||||
|
18
third_party/cheap-ruler-cpp-2.5.4/.clang-format
vendored
Normal file
18
third_party/cheap-ruler-cpp-2.5.4/.clang-format
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Standard: Cpp11
|
||||||
|
IndentWidth: 4
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
UseTab: Never
|
||||||
|
BinPackParameters: false
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
NamespaceIndentation: None
|
||||||
|
PointerBindsToType: true
|
||||||
|
SpacesInParentheses: false
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
ColumnLimit: 100
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
2
third_party/cheap-ruler-cpp-2.5.4/.gitignore
vendored
Normal file
2
third_party/cheap-ruler-cpp-2.5.4/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build/
|
||||||
|
mason_packages/
|
25
third_party/cheap-ruler-cpp-2.5.4/.travis.yml
vendored
Normal file
25
third_party/cheap-ruler-cpp-2.5.4/.travis.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
language: generic
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
env: CXX=g++-4.9
|
||||||
|
sudo: required
|
||||||
|
dist: trusty
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
|
packages: [ 'g++-4.9', 'cmake', 'cmake-data' ]
|
||||||
|
- os: linux
|
||||||
|
env: CXX=g++-5
|
||||||
|
sudo: required
|
||||||
|
dist: trusty
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
|
packages: [ 'g++-5', 'cmake', 'cmake-data' ]
|
||||||
|
|
||||||
|
cache: apt
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cmake . && make && ./cheap_ruler
|
27
third_party/cheap-ruler-cpp-2.5.4/CMakeLists.txt
vendored
Normal file
27
third_party/cheap-ruler-cpp-2.5.4/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
|
||||||
|
project(cheap_ruler LANGUAGES CXX C)
|
||||||
|
|
||||||
|
include(cmake/build.cmake)
|
||||||
|
include(cmake/mason.cmake)
|
||||||
|
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.10)
|
||||||
|
set(CMAKE_CONFIGURATION_TYPES Debug Release)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Wextra -Wpedantic -Wshadow")
|
||||||
|
|
||||||
|
mason_use(geometry VERSION 0.9.2 HEADER_ONLY)
|
||||||
|
mason_use(gtest VERSION 1.8.0)
|
||||||
|
mason_use(variant VERSION 1.1.4 HEADER_ONLY)
|
||||||
|
|
||||||
|
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
|
||||||
|
|
||||||
|
add_executable(cheap_ruler
|
||||||
|
${PROJECT_SOURCE_DIR}/test/cheap_ruler.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(cheap_ruler
|
||||||
|
PUBLIC ${PROJECT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_add_mason_package(cheap_ruler PRIVATE geometry)
|
||||||
|
target_add_mason_package(cheap_ruler PRIVATE gtest)
|
||||||
|
target_add_mason_package(cheap_ruler PRIVATE variant)
|
15
third_party/cheap-ruler-cpp-2.5.4/LICENSE
vendored
Normal file
15
third_party/cheap-ruler-cpp-2.5.4/LICENSE
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2017, Mapbox
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||||
|
with or without fee is hereby granted, provided that the above copyright notice
|
||||||
|
and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||||
|
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||||
|
THIS SOFTWARE.
|
199
third_party/cheap-ruler-cpp-2.5.4/README.md
vendored
Normal file
199
third_party/cheap-ruler-cpp-2.5.4/README.md
vendored
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
# cheap-ruler-cpp
|
||||||
|
|
||||||
|
Port to C++ of [Cheap Ruler](https://github.com/mapbox/cheap-ruler), a collection of very fast approximations to common geodesic measurements.
|
||||||
|
|
||||||
|
[](https://travis-ci.org/mapbox/cheap-ruler-cpp)
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <mapbox/cheap_ruler.hpp>
|
||||||
|
|
||||||
|
namespace cr = mapbox::cheap_ruler;
|
||||||
|
```
|
||||||
|
|
||||||
|
All `point`, `line_string`, `polygon`, and `box` references are [mapbox::geometry](https://github.com/mapbox/geometry.hpp) data structures.
|
||||||
|
|
||||||
|
## Create a ruler object
|
||||||
|
|
||||||
|
#### `CheapRuler(double latitude, Unit unit)`
|
||||||
|
|
||||||
|
Creates a ruler object that will approximate measurements around the given latitude with an optional distance unit. Once created, the ruler object has access to the [methods](#methods) below.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto ruler = cr::CheapRuler(32.8351);
|
||||||
|
auto milesRuler = cr::CheapRuler(32.8351, cr::CheapRuler::Miles);
|
||||||
|
```
|
||||||
|
|
||||||
|
Possible units:
|
||||||
|
|
||||||
|
* `cheap_ruler::CheapRuler::Unit`
|
||||||
|
* `cheap_ruler::CheapRuler::Kilometers`
|
||||||
|
* `cheap_ruler::CheapRuler::Miles`
|
||||||
|
* `cheap_ruler::CheapRuler::NauticalMiles`
|
||||||
|
* `cheap_ruler::CheapRuler::Meters`
|
||||||
|
* `cheap_ruler::CheapRuler::Yards`
|
||||||
|
* `cheap_ruler::CheapRuler::Feet`
|
||||||
|
* `cheap_ruler::CheapRuler::Inches`
|
||||||
|
|
||||||
|
#### `CheapRuler::fromTile(uint32_t y, uint32_t z)`
|
||||||
|
|
||||||
|
Creates a ruler object from tile coordinates (`y` and `z` integers). Convenient in tile-reduce scripts.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto ruler = cr::CheapRuler::fromTile(11041, 15);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
#### `distance(point a, point b)`
|
||||||
|
|
||||||
|
Given two points of the form [x = longitude, y = latitude], returns the distance (`double`).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::point point_a{-96.9148, 32.8351};
|
||||||
|
cr::point point_b{-96.9146, 32.8386};
|
||||||
|
auto distance = ruler.distance(point_a, point_b);
|
||||||
|
std::clog << distance; // 0.388595
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `bearing(point a, point b)`
|
||||||
|
|
||||||
|
Returns the bearing (`double`) between two points in angles.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::point point_a{-96.9148, 32.8351};
|
||||||
|
cr::point point_b{-96.9146, 32.8386};
|
||||||
|
auto bearing = ruler.bearing(point_a, point_b);
|
||||||
|
std::clog << bearing; // 2.76206
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `destination(point origin, double distance, double bearing)`
|
||||||
|
|
||||||
|
Returns a new point (`point`) given distance and bearing from the starting point.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::point point_a{-96.9148, 32.8351};
|
||||||
|
auto dest = ruler.destination(point_a, 1.0, -175);
|
||||||
|
std::clog << dest.x << ", " << dest.y; // -96.9148, 32.8261
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `offset(point origin, double dx, double dy)`
|
||||||
|
|
||||||
|
Returns a new point (`point`) given easting and northing offsets from the starting point.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::point point_a{-96.9148, 32.8351};
|
||||||
|
auto os = ruler.offset(point_a, 10.0, -5.0);
|
||||||
|
std::clog << os.x << ", " << os.y; // -96.808, 32.79
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `lineDistance(const line_string& points)`
|
||||||
|
|
||||||
|
Given a line (an array of points), returns the total line distance (`double`).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::line_string line_a{{ -96.9, 32.8 }, { -96.8, 32.8 }, { -96.2, 32.3 }};
|
||||||
|
auto line_distance = ruler.lineDistance(line_a);
|
||||||
|
std::clog << line_distance; // 88.2962
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `area(polygon poly)`
|
||||||
|
|
||||||
|
Given a polygon (an array of rings, where each ring is an array of points), returns the area (`double`).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::linear_ring ring{{ -96.9, 32.8 }, { -96.8, 32.8 }, { -96.2, 32.3 }, { -96.9, 32.8 }};
|
||||||
|
auto area = ruler.area(cr::polygon{ ring });
|
||||||
|
std::clog << area; //
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `along(const line_string& line, double distance)`
|
||||||
|
|
||||||
|
Returns the point (`point`) at a specified distance along the line.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::linear_ring ring{{ -96.9, 32.8 }, { -96.8, 32.8 }, { -96.2, 32.3 }, { -96.9, 32.8 }};
|
||||||
|
auto area = ruler.area(cr::polygon{ ring });
|
||||||
|
std::clog << area; // 259.581
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `pointOnLine(const line_string& line, point p)`
|
||||||
|
|
||||||
|
Returns a tuple of the form `std::pair<point, unsigned>` where point is closest point on the line from the given point, index is the start index of the segment with the closest point, and t is a parameter from 0 to 1 that indicates where the closest point is on that segment.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::line_string line{{ -96.9, 32.8 }, { -96.8, 32.8 }, { -96.2, 32.3 }};
|
||||||
|
cr::point point{-96.9, 32.79};
|
||||||
|
auto pol = ruler.pointOnLine(line, point);
|
||||||
|
auto point = std::get<0>(pol);
|
||||||
|
std::clog << point.x << ", " << point.y; // -96.9, 32.8 (point)
|
||||||
|
std::clog << std::get<1>(pol); // 0 (index)
|
||||||
|
std::clog << std::get<2>(pol); // 0. (t)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `lineSlice(point start, point stop, const line_string& line)`
|
||||||
|
|
||||||
|
Returns a part of the given line (`line_string`) between the start and the stop points (or their closest points on the line).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::line_string line{{ -96.9, 32.8 }, { -96.8, 32.8 }, { -96.2, 32.3 }};
|
||||||
|
cr::point start_point{-96.9, 32.8};
|
||||||
|
cr::point stop_point{-96.8, 32.8};
|
||||||
|
auto slice = ruler.lineSlice(start_point, stop_point, line);
|
||||||
|
std::clog << slice[0].x << ", " << slice[0].y; // -96.9, 32.8
|
||||||
|
std::clog << slice[1].x << ", " << slice[1].y; // -96.8, 32.8
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `lineSliceAlong(double start, double stop, const line_string& line)`
|
||||||
|
|
||||||
|
Returns a part of the given line (`line_string`) between the start and the stop points indicated by distance along the line.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::line_string line{{ -96.9, 32.8 }, { -96.8, 32.8 }, { -96.2, 32.3 }};
|
||||||
|
auto slice = ruler.lineSliceAlong(0.1, 1.2, line);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `bufferPoint(point p, double buffer)`
|
||||||
|
|
||||||
|
Given a point, returns a bounding box object ([w, s, e, n]) created from the given point buffered by a given distance.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::point point{-96.9, 32.8};
|
||||||
|
auto box = ruler.bufferPoint(point, 0.1);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `bufferBBox(box bbox, double buffer)`
|
||||||
|
|
||||||
|
Given a bounding box, returns the box buffered by a given distance.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::box bbox({ 30, 38 }, { 40, 39 });
|
||||||
|
auto bbox2 = ruler.bufferBBox(bbox, 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `insideBBox(point p, box bbox)`
|
||||||
|
|
||||||
|
Returns true (`bool`) if the given point is inside in the given bounding box, otherwise false.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cr::box bbox({ 30, 38 }, { 40, 39 });
|
||||||
|
auto inside = ruler.insideBBox({ 35, 38.5 }, bbox);
|
||||||
|
std::clog << inside; // true
|
||||||
|
```
|
||||||
|
|
||||||
|
# Develop
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# create targets
|
||||||
|
cmake .
|
||||||
|
|
||||||
|
# build
|
||||||
|
make
|
||||||
|
|
||||||
|
# test
|
||||||
|
./cheap_ruler
|
||||||
|
|
||||||
|
# or just do it all in one!
|
||||||
|
cmake . && make && ./cheap_ruler
|
||||||
|
```
|
11
third_party/cheap-ruler-cpp-2.5.4/cmake/build.cmake
vendored
Normal file
11
third_party/cheap-ruler-cpp-2.5.4/cmake/build.cmake
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Generate source groups so the files are properly sorted in IDEs like Xcode.
|
||||||
|
function(create_source_groups target)
|
||||||
|
get_target_property(sources ${target} SOURCES)
|
||||||
|
foreach(file ${sources})
|
||||||
|
get_filename_component(file "${file}" ABSOLUTE)
|
||||||
|
string(REGEX REPLACE "^${CMAKE_SOURCE_DIR}/" "" group "${file}")
|
||||||
|
get_filename_component(group "${group}" DIRECTORY)
|
||||||
|
string(REPLACE "/" "\\" group "${group}")
|
||||||
|
source_group("${group}" FILES "${file}")
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
235
third_party/cheap-ruler-cpp-2.5.4/cmake/mason.cmake
vendored
Normal file
235
third_party/cheap-ruler-cpp-2.5.4/cmake/mason.cmake
vendored
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
# Mason CMake
|
||||||
|
|
||||||
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
|
function(mason_detect_platform)
|
||||||
|
# Determine platform
|
||||||
|
if(NOT MASON_PLATFORM)
|
||||||
|
# we call uname -s manually here since
|
||||||
|
# CMAKE_HOST_SYSTEM_NAME will not be defined before the project() call
|
||||||
|
execute_process(
|
||||||
|
COMMAND uname -s
|
||||||
|
OUTPUT_VARIABLE UNAME
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
if (UNAME STREQUAL "Darwin")
|
||||||
|
set(MASON_PLATFORM "osx" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(MASON_PLATFORM "linux" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Determine platform version string
|
||||||
|
if(NOT MASON_PLATFORM_VERSION)
|
||||||
|
# Android Studio only passes ANDROID_ABI, but we need to adjust that to the Mason
|
||||||
|
if(MASON_PLATFORM STREQUAL "android" AND NOT MASON_PLATFORM_VERSION)
|
||||||
|
if (ANDROID_ABI STREQUAL "armeabi")
|
||||||
|
set(MASON_PLATFORM_VERSION "arm-v5-9" PARENT_SCOPE)
|
||||||
|
elseif (ANDROID_ABI STREQUAL "armeabi-v7a")
|
||||||
|
set(MASON_PLATFORM_VERSION "arm-v7-9" PARENT_SCOPE)
|
||||||
|
elseif (ANDROID_ABI STREQUAL "arm64-v8a")
|
||||||
|
set(MASON_PLATFORM_VERSION "arm-v8-21" PARENT_SCOPE)
|
||||||
|
elseif (ANDROID_ABI STREQUAL "x86")
|
||||||
|
set(MASON_PLATFORM_VERSION "x86-9" PARENT_SCOPE)
|
||||||
|
elseif (ANDROID_ABI STREQUAL "x86_64")
|
||||||
|
set(MASON_PLATFORM_VERSION "x86-64-21" PARENT_SCOPE)
|
||||||
|
elseif (ANDROID_ABI STREQUAL "mips")
|
||||||
|
set(MASON_PLATFORM_VERSION "mips-9" PARENT_SCOPE)
|
||||||
|
elseif (ANDROID_ABI STREQUAL "mips64")
|
||||||
|
set(MASON_PLATFORM_VERSION "mips-64-9" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unknown ANDROID_ABI '${ANDROID_ABI}'.")
|
||||||
|
endif()
|
||||||
|
elseif(MASON_PLATFORM STREQUAL "ios")
|
||||||
|
set(MASON_PLATFORM_VERSION "8.0" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
execute_process(
|
||||||
|
COMMAND uname -m
|
||||||
|
OUTPUT_VARIABLE MASON_PLATFORM_VERSION
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
set(MASON_PLATFORM_VERSION "${MASON_PLATFORM_VERSION}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(mason_use _PACKAGE)
|
||||||
|
if(NOT _PACKAGE)
|
||||||
|
message(FATAL_ERROR "[Mason] No package name given")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
cmake_parse_arguments("" "HEADER_ONLY" "VERSION" "" ${ARGN})
|
||||||
|
|
||||||
|
if(_UNPARSED_ARGUMENTS)
|
||||||
|
message(FATAL_ERROR "[Mason] mason_use() called with unrecognized arguments: ${_UNPARSED_ARGUMENTS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT _VERSION)
|
||||||
|
message(FATAL_ERROR "[Mason] Specifying a version is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MASON_PACKAGE_${_PACKAGE}_INVOCATION STREQUAL "${MASON_INVOCATION}")
|
||||||
|
# Check that the previous invocation of mason_use didn't select another version of this package
|
||||||
|
if(NOT MASON_PACKAGE_${_PACKAGE}_VERSION STREQUAL ${_VERSION})
|
||||||
|
message(FATAL_ERROR "[Mason] Already using ${_PACKAGE} ${MASON_PACKAGE_${_PACKAGE}_VERSION}. Cannot select version ${_VERSION}.")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
if(_HEADER_ONLY)
|
||||||
|
set(_PLATFORM_ID "headers")
|
||||||
|
else()
|
||||||
|
set(_PLATFORM_ID "${MASON_PLATFORM}-${MASON_PLATFORM_VERSION}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_SLUG "${_PLATFORM_ID}/${_PACKAGE}/${_VERSION}")
|
||||||
|
set(_INSTALL_PATH "${MASON_PACKAGE_DIR}/${_SLUG}")
|
||||||
|
file(RELATIVE_PATH _INSTALL_PATH_RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${_INSTALL_PATH}")
|
||||||
|
|
||||||
|
if(NOT EXISTS "${_INSTALL_PATH}")
|
||||||
|
set(_CACHE_PATH "${MASON_PACKAGE_DIR}/.binaries/${_SLUG}.tar.gz")
|
||||||
|
if (NOT EXISTS "${_CACHE_PATH}")
|
||||||
|
# Download the package
|
||||||
|
set(_URL "${MASON_REPOSITORY}/${_SLUG}.tar.gz")
|
||||||
|
message("[Mason] Downloading package ${_URL}...")
|
||||||
|
|
||||||
|
set(_FAILED)
|
||||||
|
set(_ERROR)
|
||||||
|
# Note: some CMake versions are compiled without SSL support
|
||||||
|
get_filename_component(_CACHE_DIR "${_CACHE_PATH}" DIRECTORY)
|
||||||
|
file(MAKE_DIRECTORY "${_CACHE_DIR}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND curl --retry 3 -s -f -S -L "${_URL}" -o "${_CACHE_PATH}.tmp"
|
||||||
|
RESULT_VARIABLE _FAILED
|
||||||
|
ERROR_VARIABLE _ERROR)
|
||||||
|
if(_FAILED)
|
||||||
|
message(FATAL_ERROR "[Mason] Failed to download ${_URL}: ${_ERROR}")
|
||||||
|
else()
|
||||||
|
# We downloaded to a temporary file to prevent half-finished downloads
|
||||||
|
file(RENAME "${_CACHE_PATH}.tmp" "${_CACHE_PATH}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Unpack the package
|
||||||
|
message("[Mason] Unpacking package to ${_INSTALL_PATH_RELATIVE}...")
|
||||||
|
file(MAKE_DIRECTORY "${_INSTALL_PATH}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E tar xzf "${_CACHE_PATH}"
|
||||||
|
WORKING_DIRECTORY "${_INSTALL_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Error out if there is no config file.
|
||||||
|
if(NOT EXISTS "${_INSTALL_PATH}/mason.ini")
|
||||||
|
message(FATAL_ERROR "[Mason] Could not find mason.ini for package ${_PACKAGE} ${_VERSION}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(MASON_PACKAGE_${_PACKAGE}_PREFIX "${_INSTALL_PATH}" CACHE STRING "${_PACKAGE} ${_INSTALL_PATH}" FORCE)
|
||||||
|
mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_PREFIX)
|
||||||
|
|
||||||
|
# Load the configuration from the ini file
|
||||||
|
file(STRINGS "${_INSTALL_PATH}/mason.ini" _CONFIG_FILE)
|
||||||
|
foreach(_LINE IN LISTS _CONFIG_FILE)
|
||||||
|
string(REGEX MATCH "^([a-z_]+) *= *" _KEY "${_LINE}")
|
||||||
|
if (_KEY)
|
||||||
|
string(LENGTH "${_KEY}" _KEY_LENGTH)
|
||||||
|
string(SUBSTRING "${_LINE}" ${_KEY_LENGTH} -1 _VALUE)
|
||||||
|
string(REGEX REPLACE ";.*$" "" _VALUE "${_VALUE}") # Trim trailing commas
|
||||||
|
string(REPLACE "{prefix}" "${_INSTALL_PATH}" _VALUE "${_VALUE}")
|
||||||
|
string(STRIP "${_VALUE}" _VALUE)
|
||||||
|
string(REPLACE "=" "" _KEY "${_KEY}")
|
||||||
|
string(STRIP "${_KEY}" _KEY)
|
||||||
|
string(TOUPPER "${_KEY}" _KEY)
|
||||||
|
if(_KEY STREQUAL "INCLUDE_DIRS" OR _KEY STREQUAL "STATIC_LIBS" )
|
||||||
|
separate_arguments(_VALUE)
|
||||||
|
endif()
|
||||||
|
set(MASON_PACKAGE_${_PACKAGE}_${_KEY} "${_VALUE}" CACHE STRING "${_PACKAGE} ${_KEY}" FORCE)
|
||||||
|
mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_${_KEY})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Compare version in the package to catch errors early on
|
||||||
|
if(NOT _VERSION STREQUAL MASON_PACKAGE_${_PACKAGE}_VERSION)
|
||||||
|
message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has version '${MASON_PACKAGE_${_PACKAGE}_VERSION}', but required '${_VERSION}'")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT _PACKAGE STREQUAL MASON_PACKAGE_${_PACKAGE}_NAME)
|
||||||
|
message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has name '${MASON_PACKAGE_${_PACKAGE}_NAME}', but required '${_NAME}'")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT _HEADER_ONLY)
|
||||||
|
if(NOT MASON_PLATFORM STREQUAL MASON_PACKAGE_${_PACKAGE}_PLATFORM)
|
||||||
|
message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has platform '${MASON_PACKAGE_${_PACKAGE}_PLATFORM}', but required '${MASON_PLATFORM}'")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT MASON_PLATFORM_VERSION STREQUAL MASON_PACKAGE_${_PACKAGE}_PLATFORM_VERSION)
|
||||||
|
message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has platform version '${MASON_PACKAGE_${_PACKAGE}_PLATFORM_VERSION}', but required '${MASON_PLATFORM_VERSION}'")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Concatenate the static libs and libraries
|
||||||
|
set(_LIBRARIES)
|
||||||
|
list(APPEND _LIBRARIES ${MASON_PACKAGE_${_PACKAGE}_STATIC_LIBS} ${MASON_PACKAGE_${_PACKAGE}_LDFLAGS})
|
||||||
|
set(MASON_PACKAGE_${_PACKAGE}_LIBRARIES "${_LIBRARIES}" CACHE STRING "${_PACKAGE} _LIBRARIES" FORCE)
|
||||||
|
mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_LIBRARIES)
|
||||||
|
|
||||||
|
if(NOT _HEADER_ONLY)
|
||||||
|
string(REGEX MATCHALL "(^| +)-L *([^ ]+)" MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LDFLAGS}")
|
||||||
|
string(REGEX REPLACE "(^| +)-L *" "\\1" MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}")
|
||||||
|
set(MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}" CACHE STRING "${_PACKAGE} ${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}" FORCE)
|
||||||
|
mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Store invocation ID to prevent different versions of the same package in one invocation
|
||||||
|
set(MASON_PACKAGE_${_PACKAGE}_INVOCATION "${MASON_INVOCATION}" CACHE INTERNAL "${_PACKAGE} invocation ID" FORCE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
macro(target_add_mason_package _TARGET _VISIBILITY _PACKAGE)
|
||||||
|
if (NOT MASON_PACKAGE_${_PACKAGE}_INVOCATION)
|
||||||
|
message(FATAL_ERROR "[Mason] Package ${_PACKAGE} has not been initialized yet")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_INCLUDE_DIRS}")
|
||||||
|
target_compile_definitions(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_DEFINITIONS}")
|
||||||
|
target_compile_options(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_OPTIONS}")
|
||||||
|
target_link_libraries(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_LIBRARIES}")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
|
||||||
|
string(RANDOM LENGTH 16 MASON_INVOCATION)
|
||||||
|
|
||||||
|
# Read environment variables if CMake is run in command mode
|
||||||
|
if (CMAKE_ARGC)
|
||||||
|
set(MASON_PLATFORM "$ENV{MASON_PLATFORM}")
|
||||||
|
set(MASON_PLATFORM_VERSION "$ENV{MASON_PLATFORM_VERSION}")
|
||||||
|
set(MASON_PACKAGE_DIR "$ENV{MASON_PACKAGE_DIR}")
|
||||||
|
set(MASON_REPOSITORY "$ENV{MASON_REPOSITORY}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Directory where Mason packages are located; typically ends with mason_packages
|
||||||
|
if (NOT MASON_PACKAGE_DIR)
|
||||||
|
set(MASON_PACKAGE_DIR "${CMAKE_SOURCE_DIR}/mason_packages")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# URL prefix of where packages are located.
|
||||||
|
if (NOT MASON_REPOSITORY)
|
||||||
|
set(MASON_REPOSITORY "https://mason-binaries.s3.amazonaws.com")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mason_detect_platform()
|
||||||
|
|
||||||
|
# Execute commands if CMake is run in command mode
|
||||||
|
if (CMAKE_ARGC)
|
||||||
|
# Collect remaining arguments for passing to mason_use
|
||||||
|
set(_MASON_ARGS)
|
||||||
|
foreach(I RANGE 4 ${CMAKE_ARGC})
|
||||||
|
list(APPEND _MASON_ARGS "${CMAKE_ARGV${I}}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Install the package
|
||||||
|
mason_use(${_MASON_ARGS})
|
||||||
|
|
||||||
|
# Optionally print variables
|
||||||
|
if(DEFINED MASON_PACKAGE_${CMAKE_ARGV4}_${CMAKE_ARGV3})
|
||||||
|
# CMake can't write to stdout with message()
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${MASON_PACKAGE_${CMAKE_ARGV4}_${CMAKE_ARGV3}}")
|
||||||
|
endif()
|
||||||
|
endif()
|
354
third_party/cheap-ruler-cpp-2.5.4/include/mapbox/cheap_ruler.hpp
vendored
Normal file
354
third_party/cheap-ruler-cpp-2.5.4/include/mapbox/cheap_ruler.hpp
vendored
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mapbox/geometry.hpp>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace cheap_ruler {
|
||||||
|
|
||||||
|
using box = geometry::box<double>;
|
||||||
|
using line_string = geometry::line_string<double>;
|
||||||
|
using linear_ring = geometry::linear_ring<double>;
|
||||||
|
using multi_line_string = geometry::multi_line_string<double>;
|
||||||
|
using point = geometry::point<double>;
|
||||||
|
using polygon = geometry::polygon<double>;
|
||||||
|
|
||||||
|
class CheapRuler {
|
||||||
|
public:
|
||||||
|
enum Unit {
|
||||||
|
Kilometers,
|
||||||
|
Miles,
|
||||||
|
NauticalMiles,
|
||||||
|
Meters,
|
||||||
|
Metres = Meters,
|
||||||
|
Yards,
|
||||||
|
Feet,
|
||||||
|
Inches
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// A collection of very fast approximations to common geodesic measurements. Useful
|
||||||
|
// for performance-sensitive code that measures things on a city scale. Point coordinates
|
||||||
|
// are in the [x = longitude, y = latitude] form.
|
||||||
|
//
|
||||||
|
explicit CheapRuler(double latitude, Unit unit = Kilometers) {
|
||||||
|
double m = 0.;
|
||||||
|
|
||||||
|
switch (unit) {
|
||||||
|
case Kilometers:
|
||||||
|
m = 1.;
|
||||||
|
break;
|
||||||
|
case Miles:
|
||||||
|
m = 1000. / 1609.344;
|
||||||
|
break;
|
||||||
|
case NauticalMiles:
|
||||||
|
m = 1000. / 1852.;
|
||||||
|
break;
|
||||||
|
case Meters:
|
||||||
|
m = 1000.;
|
||||||
|
break;
|
||||||
|
case Yards:
|
||||||
|
m = 1000. / 0.9144;
|
||||||
|
break;
|
||||||
|
case Feet:
|
||||||
|
m = 1000. / 0.3048;
|
||||||
|
break;
|
||||||
|
case Inches:
|
||||||
|
m = 1000. / 0.0254;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cos = std::cos(latitude * M_PI / 180.);
|
||||||
|
auto cos2 = 2. * cos * cos - 1.;
|
||||||
|
auto cos3 = 2. * cos * cos2 - cos;
|
||||||
|
auto cos4 = 2. * cos * cos3 - cos2;
|
||||||
|
auto cos5 = 2. * cos * cos4 - cos3;
|
||||||
|
|
||||||
|
// multipliers for converting longitude and latitude
|
||||||
|
// degrees into distance (http://1.usa.gov/1Wb1bv7)
|
||||||
|
kx = m * (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5);
|
||||||
|
ky = m * (111.13209 - 0.56605 * cos2 + 0.0012 * cos4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CheapRuler fromTile(uint32_t y, uint32_t z) {
|
||||||
|
double n = M_PI * (1. - 2. * (y + 0.5) / std::pow(2., z));
|
||||||
|
double latitude = std::atan(0.5 * (std::exp(n) - std::exp(-n))) * 180. / M_PI;
|
||||||
|
|
||||||
|
return CheapRuler(latitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Given two points of the form [x = longitude, y = latitude], returns the distance.
|
||||||
|
//
|
||||||
|
double distance(point a, point b) {
|
||||||
|
auto dx = (a.x - b.x) * kx;
|
||||||
|
auto dy = (a.y - b.y) * ky;
|
||||||
|
|
||||||
|
return std::sqrt(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Returns the bearing between two points in angles.
|
||||||
|
//
|
||||||
|
double bearing(point a, point b) {
|
||||||
|
auto dx = (b.x - a.x) * kx;
|
||||||
|
auto dy = (b.y - a.y) * ky;
|
||||||
|
|
||||||
|
if (!dx && !dy) {
|
||||||
|
return 0.;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value = std::atan2(dx, dy) * 180. / M_PI;
|
||||||
|
|
||||||
|
if (value > 180.) {
|
||||||
|
value -= 360.;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Returns a new point given distance and bearing from the starting point.
|
||||||
|
//
|
||||||
|
point destination(point origin, double dist, double bearing_) {
|
||||||
|
auto a = (90. - bearing_) * M_PI / 180.;
|
||||||
|
|
||||||
|
return offset(origin, std::cos(a) * dist, std::sin(a) * dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Returns a new point given easting and northing offsets from the starting point.
|
||||||
|
//
|
||||||
|
point offset(point origin, double dx, double dy) {
|
||||||
|
return point(origin.x + dx / kx, origin.y + dy / ky);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Given a line (an array of points), returns the total line distance.
|
||||||
|
//
|
||||||
|
double lineDistance(const line_string& points) {
|
||||||
|
double total = 0.;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < points.size() - 1; ++i) {
|
||||||
|
total += distance(points[i], points[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Given a polygon (an array of rings, where each ring is an array of points),
|
||||||
|
// returns the area.
|
||||||
|
//
|
||||||
|
double area(polygon poly) {
|
||||||
|
double sum = 0.;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < poly.size(); ++i) {
|
||||||
|
auto& ring = poly[i];
|
||||||
|
|
||||||
|
for (unsigned j = 0, len = ring.size(), k = len - 1; j < len; k = j++) {
|
||||||
|
sum += (ring[j].x - ring[k].x) * (ring[j].y + ring[k].y) * (i ? -1. : 1.);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (std::abs(sum) / 2.) * kx * ky;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Returns the point at a specified distance along the line.
|
||||||
|
//
|
||||||
|
point along(const line_string& line, double dist) {
|
||||||
|
double sum = 0.;
|
||||||
|
|
||||||
|
if (dist <= 0.) {
|
||||||
|
return line[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < line.size() - 1; ++i) {
|
||||||
|
auto p0 = line[i];
|
||||||
|
auto p1 = line[i + 1];
|
||||||
|
auto d = distance(p0, p1);
|
||||||
|
|
||||||
|
sum += d;
|
||||||
|
|
||||||
|
if (sum > dist) {
|
||||||
|
return interpolate(p0, p1, (dist - (sum - d)) / d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return line[line.size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Returns a tuple of the form <point, index, t> where point is closest point on the line
|
||||||
|
// from the given point, index is the start index of the segment with the closest point,
|
||||||
|
// and t is a parameter from 0 to 1 that indicates where the closest point is on that segment.
|
||||||
|
//
|
||||||
|
std::tuple<point, unsigned, double> pointOnLine(const line_string& line, point p) {
|
||||||
|
double minDist = std::numeric_limits<double>::infinity();
|
||||||
|
double minX = 0., minY = 0., minI = 0., minT = 0.;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < line.size() - 1; ++i) {
|
||||||
|
auto t = 0.;
|
||||||
|
auto x = line[i].x;
|
||||||
|
auto y = line[i].y;
|
||||||
|
auto dx = (line[i + 1].x - x) * kx;
|
||||||
|
auto dy = (line[i + 1].y - y) * ky;
|
||||||
|
|
||||||
|
if (dx != 0. || dy != 0.) {
|
||||||
|
t = ((p.x - x) * kx * dx + (p.y - y) * ky * dy) / (dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (t > 1) {
|
||||||
|
x = line[i + 1].x;
|
||||||
|
y = line[i + 1].y;
|
||||||
|
|
||||||
|
} else if (t > 0) {
|
||||||
|
x += (dx / kx) * t;
|
||||||
|
y += (dy / ky) * t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = (p.x - x) * kx;
|
||||||
|
dy = (p.y - y) * ky;
|
||||||
|
|
||||||
|
auto sqDist = dx * dx + dy * dy;
|
||||||
|
|
||||||
|
if (sqDist < minDist) {
|
||||||
|
minDist = sqDist;
|
||||||
|
minX = x;
|
||||||
|
minY = y;
|
||||||
|
minI = i;
|
||||||
|
minT = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_tuple(
|
||||||
|
point(minX, minY), minI, ::fmax(0., ::fmin(1., minT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Returns a part of the given line between the start and the stop points (or their closest
|
||||||
|
// points on the line).
|
||||||
|
//
|
||||||
|
line_string lineSlice(point start, point stop, const line_string& line) {
|
||||||
|
auto getPoint = [](auto tuple) { return std::get<0>(tuple); };
|
||||||
|
auto getIndex = [](auto tuple) { return std::get<1>(tuple); };
|
||||||
|
auto getT = [](auto tuple) { return std::get<2>(tuple); };
|
||||||
|
|
||||||
|
auto p1 = pointOnLine(line, start);
|
||||||
|
auto p2 = pointOnLine(line, stop);
|
||||||
|
|
||||||
|
if (getIndex(p1) > getIndex(p2) || (getIndex(p1) == getIndex(p2) && getT(p1) > getT(p2))) {
|
||||||
|
auto tmp = p1;
|
||||||
|
p1 = p2;
|
||||||
|
p2 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_string slice = { getPoint(p1) };
|
||||||
|
|
||||||
|
auto l = getIndex(p1) + 1;
|
||||||
|
auto r = getIndex(p2);
|
||||||
|
|
||||||
|
if (line[l] != slice[0] && l <= r) {
|
||||||
|
slice.push_back(line[l]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = l + 1; i <= r; ++i) {
|
||||||
|
slice.push_back(line[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line[r] != getPoint(p2)) {
|
||||||
|
slice.push_back(getPoint(p2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Returns a part of the given line between the start and the stop points
|
||||||
|
// indicated by distance along the line.
|
||||||
|
//
|
||||||
|
line_string lineSliceAlong(double start, double stop, const line_string& line) {
|
||||||
|
double sum = 0.;
|
||||||
|
line_string slice;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < line.size() - 1; ++i) {
|
||||||
|
auto p0 = line[i];
|
||||||
|
auto p1 = line[i + 1];
|
||||||
|
auto d = distance(p0, p1);
|
||||||
|
|
||||||
|
sum += d;
|
||||||
|
|
||||||
|
if (sum > start && slice.size() == 0) {
|
||||||
|
slice.push_back(interpolate(p0, p1, (start - (sum - d)) / d));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sum >= stop) {
|
||||||
|
slice.push_back(interpolate(p0, p1, (stop - (sum - d)) / d));
|
||||||
|
return slice;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sum > start) {
|
||||||
|
slice.push_back(p1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Given a point, returns a bounding box object ([w, s, e, n])
|
||||||
|
// created from the given point buffered by a given distance.
|
||||||
|
//
|
||||||
|
box bufferPoint(point p, double buffer) {
|
||||||
|
auto v = buffer / ky;
|
||||||
|
auto h = buffer / kx;
|
||||||
|
|
||||||
|
return box(
|
||||||
|
point(p.x - h, p.y - v),
|
||||||
|
point(p.x + h, p.y + v)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Given a bounding box, returns the box buffered by a given distance.
|
||||||
|
//
|
||||||
|
box bufferBBox(box bbox, double buffer) {
|
||||||
|
auto v = buffer / ky;
|
||||||
|
auto h = buffer / kx;
|
||||||
|
|
||||||
|
return box(
|
||||||
|
point(bbox.min.x - h, bbox.min.y - v),
|
||||||
|
point(bbox.max.x + h, bbox.max.y + v)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Returns true if the given point is inside in the given bounding box, otherwise false.
|
||||||
|
//
|
||||||
|
bool insideBBox(point p, box bbox) {
|
||||||
|
return p.x >= bbox.min.x &&
|
||||||
|
p.x <= bbox.max.x &&
|
||||||
|
p.y >= bbox.min.y &&
|
||||||
|
p.y <= bbox.max.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static point interpolate(point a, point b, double t) {
|
||||||
|
double dx = b.x - a.x;
|
||||||
|
double dy = b.y - a.y;
|
||||||
|
|
||||||
|
return point(a.x + dx * t, a.y + dy * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
double ky;
|
||||||
|
double kx;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cheap_ruler
|
||||||
|
} // namespace mapbox
|
200
third_party/cheap-ruler-cpp-2.5.4/test/cheap_ruler.cpp
vendored
Normal file
200
third_party/cheap-ruler-cpp-2.5.4/test/cheap_ruler.cpp
vendored
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#include <mapbox/cheap_ruler.hpp>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "fixtures/lines.hpp"
|
||||||
|
#include "fixtures/turf.hpp"
|
||||||
|
|
||||||
|
namespace cr = mapbox::cheap_ruler;
|
||||||
|
|
||||||
|
class CheapRulerTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
cr::CheapRuler ruler = cr::CheapRuler(32.8351);
|
||||||
|
cr::CheapRuler milesRuler = cr::CheapRuler(32.8351, cr::CheapRuler::Miles);
|
||||||
|
};
|
||||||
|
|
||||||
|
void assertErr(double expected, double actual, double maxError) {
|
||||||
|
// Add a negligible fraction to make sure we
|
||||||
|
// don't divide by zero.
|
||||||
|
double error = std::abs((actual - expected) /
|
||||||
|
(expected == 0. ? expected + 0.000001 : expected));
|
||||||
|
|
||||||
|
if (error > maxError) {
|
||||||
|
FAIL() << "expected is " << expected << " but got " << actual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, distance) {
|
||||||
|
for (unsigned i = 0; i < points.size() - 1; ++i) {
|
||||||
|
auto expected = turf_distance[i];
|
||||||
|
auto actual = ruler.distance(points[i], points[i + 1]);
|
||||||
|
|
||||||
|
assertErr(expected, actual, .003);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, distanceInMiles) {
|
||||||
|
auto d = ruler.distance({ 30.5, 32.8351 }, { 30.51, 32.8451 });
|
||||||
|
auto d2 = milesRuler.distance({ 30.5, 32.8351 }, { 30.51, 32.8451 });
|
||||||
|
|
||||||
|
assertErr(d / d2, 1.609344, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, bearing) {
|
||||||
|
for (unsigned i = 0; i < points.size() - 1; ++i) {
|
||||||
|
auto expected = turf_bearing[i];
|
||||||
|
auto actual = ruler.bearing(points[i], points[i + 1]);
|
||||||
|
|
||||||
|
assertErr(expected, actual, .005);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, destination) {
|
||||||
|
for (unsigned i = 0; i < points.size(); ++i) {
|
||||||
|
auto bearing = (i % 360) - 180.;
|
||||||
|
auto expected = turf_destination[i];
|
||||||
|
auto actual = ruler.destination(points[i], 1.0, bearing);
|
||||||
|
|
||||||
|
assertErr(expected.x, actual.x, 1e-6); // longitude
|
||||||
|
assertErr(expected.y, actual.y, 1e-6); // latitude
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, lineDistance) {
|
||||||
|
for (unsigned i = 0; i < lines.size(); ++i) {
|
||||||
|
auto expected = turf_lineDistance[i];
|
||||||
|
auto actual = ruler.lineDistance(lines[i]);
|
||||||
|
|
||||||
|
assertErr(expected, actual, 0.003);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, area) {
|
||||||
|
for (unsigned i = 0, j = 0; i < lines.size(); ++i) {
|
||||||
|
if (lines[i].size() < 3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cr::linear_ring ring;
|
||||||
|
for (auto point : lines[i]) {
|
||||||
|
ring.push_back(point);
|
||||||
|
}
|
||||||
|
ring.push_back(lines[i][0]);
|
||||||
|
|
||||||
|
auto expected = turf_area[j++];
|
||||||
|
auto actual = ruler.area(cr::polygon{ ring });
|
||||||
|
|
||||||
|
assertErr(expected, actual, 0.003);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, along) {
|
||||||
|
for (unsigned i = 0; i < lines.size(); ++i) {
|
||||||
|
auto expected = turf_along[i];
|
||||||
|
auto actual = ruler.along(lines[i], turf_along_dist[i]);
|
||||||
|
|
||||||
|
assertErr(expected.x, actual.x, 1e-6); // along longitude
|
||||||
|
assertErr(expected.y, actual.y, 1e-6); // along latitude
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, alongWithDist) {
|
||||||
|
ASSERT_EQ(ruler.along(lines[0], -5), lines[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, alongWithDistGreaterThanLength) {
|
||||||
|
ASSERT_EQ(ruler.along(lines[0], 1000), lines[0][lines[0].size() - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, pointOnLine) {
|
||||||
|
// not Turf comparison because pointOnLine is bugged https://github.com/Turfjs/turf/issues/344
|
||||||
|
cr::line_string line = {{ -77.031669, 38.878605 }, { -77.029609, 38.881946 }};
|
||||||
|
auto result = ruler.pointOnLine(line, { -77.034076, 38.882017 });
|
||||||
|
|
||||||
|
ASSERT_EQ(std::get<0>(result), cr::point(-77.03052697027461, 38.880457194811896)); // point
|
||||||
|
ASSERT_EQ(std::get<1>(result), 0u); // index
|
||||||
|
ASSERT_EQ(std::get<2>(result), 0.5543833618360235); // t
|
||||||
|
|
||||||
|
ASSERT_EQ(std::get<2>(ruler.pointOnLine(line, { -80., 38. })), 0.) << "t is not less than 0";
|
||||||
|
ASSERT_EQ(std::get<2>(ruler.pointOnLine(line, { -75., 38. })), 1.) << "t is not bigger than 1";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, lineSlice) {
|
||||||
|
for (unsigned i = 0; i < lines.size(); ++i) {
|
||||||
|
auto line = lines[i];
|
||||||
|
auto dist = ruler.lineDistance(line);
|
||||||
|
auto start = ruler.along(line, dist * 0.3);
|
||||||
|
auto stop = ruler.along(line, dist * 0.7);
|
||||||
|
auto expected = turf_lineSlice[i];
|
||||||
|
auto actual = ruler.lineDistance(ruler.lineSlice(start, stop, line));
|
||||||
|
|
||||||
|
assertErr(expected, actual, 1e-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, lineSliceAlong) {
|
||||||
|
for (unsigned i = 0; i < lines.size(); ++i) {
|
||||||
|
if (i == 46) {
|
||||||
|
// skip due to Turf bug https://github.com/Turfjs/turf/issues/351
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto line = lines[i];
|
||||||
|
auto dist = ruler.lineDistance(line);
|
||||||
|
auto expected = turf_lineSlice[i];
|
||||||
|
auto actual = ruler.lineDistance(ruler.lineSliceAlong(dist * 0.3, dist * 0.7, line));
|
||||||
|
|
||||||
|
assertErr(expected, actual, 1e-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, lineSliceReverse) {
|
||||||
|
auto line = lines[0];
|
||||||
|
auto dist = ruler.lineDistance(line);
|
||||||
|
auto start = ruler.along(line, dist * 0.7);
|
||||||
|
auto stop = ruler.along(line, dist * 0.3);
|
||||||
|
auto actual = ruler.lineDistance(ruler.lineSlice(start, stop, line));
|
||||||
|
|
||||||
|
ASSERT_EQ(actual, 0.018676802802910702);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, bufferPoint) {
|
||||||
|
for (unsigned i = 0; i < points.size(); ++i) {
|
||||||
|
auto expected = turf_bufferPoint[i];
|
||||||
|
auto actual = milesRuler.bufferPoint(points[i], 0.1);
|
||||||
|
|
||||||
|
assertErr(expected.min.x, actual.min.x, 2e-7);
|
||||||
|
assertErr(expected.min.x, actual.min.x, 2e-7);
|
||||||
|
assertErr(expected.max.y, actual.max.y, 2e-7);
|
||||||
|
assertErr(expected.max.y, actual.max.y, 2e-7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, bufferBBox) {
|
||||||
|
cr::box bbox({ 30, 38 }, { 40, 39 });
|
||||||
|
cr::box bbox2 = ruler.bufferBBox(bbox, 1);
|
||||||
|
|
||||||
|
ASSERT_EQ(bbox2, cr::box({ 29.989319515875376, 37.99098271225711 }, { 40.01068048412462, 39.00901728774289 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, insideBBox) {
|
||||||
|
cr::box bbox({ 30, 38 }, { 40, 39 });
|
||||||
|
|
||||||
|
ASSERT_TRUE(ruler.insideBBox({ 35, 38.5 }, bbox));
|
||||||
|
ASSERT_FALSE(ruler.insideBBox({ 45, 45 }, bbox));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CheapRulerTest, fromTile) {
|
||||||
|
auto ruler1 = cr::CheapRuler(50.5);
|
||||||
|
auto ruler2 = cr::CheapRuler::fromTile(11041, 15);
|
||||||
|
|
||||||
|
cr::point p1(30.5, 50.5);
|
||||||
|
cr::point p2(30.51, 50.51);
|
||||||
|
|
||||||
|
assertErr(ruler1.distance(p1, p2), ruler2.distance(p1, p2), 2e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
8
third_party/cheap-ruler-cpp-2.5.4/test/fixtures/lines.hpp
vendored
Normal file
8
third_party/cheap-ruler-cpp-2.5.4/test/fixtures/lines.hpp
vendored
Normal file
File diff suppressed because one or more lines are too long
1894
third_party/cheap-ruler-cpp-2.5.4/test/fixtures/turf.hpp
vendored
Normal file
1894
third_party/cheap-ruler-cpp-2.5.4/test/fixtures/turf.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
third_party/geometry.hpp-0.9.2/.gitignore
vendored
Normal file
2
third_party/geometry.hpp-0.9.2/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mason_packages
|
||||||
|
test
|
3
third_party/geometry.hpp-0.9.2/.gitmodules
vendored
Normal file
3
third_party/geometry.hpp-0.9.2/.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule ".mason"]
|
||||||
|
path = .mason
|
||||||
|
url = https://github.com/mapbox/mason.git
|
50
third_party/geometry.hpp-0.9.2/.travis.yml
vendored
Normal file
50
third_party/geometry.hpp-0.9.2/.travis.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
language: generic
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
env: CXX=g++-4.9
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
|
packages: [ 'g++-4.9' ]
|
||||||
|
- os: linux
|
||||||
|
env: CXX=g++-5
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
|
packages: [ 'g++-5' ]
|
||||||
|
- os: linux
|
||||||
|
env: CXX=g++-6
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
|
packages: [ 'g++-6' ]
|
||||||
|
- os: linux
|
||||||
|
env: CXX=clang++-3.8
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
|
packages: [ 'libstdc++-4.9-dev' ]
|
||||||
|
before_script:
|
||||||
|
- git submodule update --init
|
||||||
|
- .mason/mason install clang++ 3.8.1
|
||||||
|
- export PATH=$(.mason/mason prefix clang++ 3.8.1)/bin:$PATH
|
||||||
|
- os: linux
|
||||||
|
env: CXX=clang++-3.9
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||||
|
packages: [ 'libstdc++-4.9-dev' ]
|
||||||
|
before_script:
|
||||||
|
- git submodule update --init
|
||||||
|
- .mason/mason install clang++ 3.9.1
|
||||||
|
- export PATH=$(.mason/mason prefix clang++ 3.9.1)/bin:$PATH
|
||||||
|
- os: osx
|
||||||
|
osx_image: xcode7.3
|
||||||
|
|
||||||
|
cache: apt
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make test
|
13
third_party/geometry.hpp-0.9.2/LICENSE
vendored
Normal file
13
third_party/geometry.hpp-0.9.2/LICENSE
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Copyright (c) 2016, Mapbox
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
19
third_party/geometry.hpp-0.9.2/Makefile
vendored
Normal file
19
third_party/geometry.hpp-0.9.2/Makefile
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
CXXFLAGS += -I include -std=c++14 -DDEBUG -O0 -Wall -Wextra -Werror
|
||||||
|
MASON ?= .mason/mason
|
||||||
|
|
||||||
|
VARIANT = 1.1.4
|
||||||
|
|
||||||
|
default: test
|
||||||
|
|
||||||
|
$(MASON):
|
||||||
|
git submodule update --init
|
||||||
|
|
||||||
|
mason_packages/headers/variant/$(VARIANT):
|
||||||
|
$(MASON) install variant $(VARIANT)
|
||||||
|
|
||||||
|
test: tests/* include/mapbox/geometry/* mason_packages/headers/variant/$(VARIANT) Makefile
|
||||||
|
$(CXX) tests/*.cpp $(CXXFLAGS) `$(MASON) cflags variant $(VARIANT)` -o test
|
||||||
|
./test
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f test
|
83
third_party/geometry.hpp-0.9.2/README.md
vendored
Normal file
83
third_party/geometry.hpp-0.9.2/README.md
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# geometry.hpp
|
||||||
|
|
||||||
|
Provides header-only, generic C++ interfaces for geometry types, geometry collections, and features.
|
||||||
|
|
||||||
|
- `mapbox::geometry::point`
|
||||||
|
- `mapbox::geometry::multi_point`
|
||||||
|
- `mapbox::geometry::line_string`
|
||||||
|
- `mapbox::geometry::multi_line_string`
|
||||||
|
- `mapbox::geometry::polygon`
|
||||||
|
- `mapbox::geometry::multi_polygon`
|
||||||
|
- `mapbox::geometry::geometry_collection`
|
||||||
|
- `mapbox::geometry::feature` (experimental)
|
||||||
|
|
||||||
|
### Design
|
||||||
|
|
||||||
|
These types are designed to be easy to parse and serialize to [GeoJSON](http://geojson.org/).
|
||||||
|
|
||||||
|
They should also be a robust and high performance container for data processing and conversion.
|
||||||
|
|
||||||
|
|
||||||
|
### Goals
|
||||||
|
|
||||||
|
- Header-only
|
||||||
|
- Fast compile
|
||||||
|
- c++11/c++14 compatibility
|
||||||
|
- No external dependencies for usage of core types (point, line_string, etc)
|
||||||
|
- Minimal dependencies for usage of enclosing `geometry` type (`mapbox::variant`)
|
||||||
|
- Easily [adaptable to `boost::geometry`](http://www.boost.org/doc/libs/1_56_0/libs/geometry/doc/html/geometry/examples/example__adapting_a_legacy_geometry_object_model.html)
|
||||||
|
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Using a single type directly (requires no external dependencies):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <mapbox/geometry/point.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using mapbox::geometry::point;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
point<double> pt(1.0,0.0);
|
||||||
|
std::clog << "x: " << pt.x << " y: " << pt.y << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Creating a geometry collection (depends on https://github.com/mapbox/variant):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <mapbox/geometry/geometry.hpp>
|
||||||
|
#include <mapbox/variant.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using mapbox::geometry::geometry_collection;
|
||||||
|
using mapbox::geometry::geometry;
|
||||||
|
using mapbox::geometry::point;
|
||||||
|
|
||||||
|
using point_type = point<double>;
|
||||||
|
|
||||||
|
struct printer
|
||||||
|
{
|
||||||
|
printer() {}
|
||||||
|
|
||||||
|
void operator()(point_type const& pt) const
|
||||||
|
{
|
||||||
|
std::clog << "x: " << pt.x << " y: " << pt.y << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void operator()(T const& g) const
|
||||||
|
{
|
||||||
|
std::clog << "encountered non-point geometry\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
geometry_collection<double> gc;
|
||||||
|
gc.emplace_back(point_type(1.0,0.0));
|
||||||
|
geometry<double> const& geom = gc.at(0);
|
||||||
|
printer visitor;
|
||||||
|
mapbox::util::apply_visitor(visitor,geom);
|
||||||
|
}
|
||||||
|
```
|
13
third_party/geometry.hpp-0.9.2/include/mapbox/geometry.hpp
vendored
Normal file
13
third_party/geometry.hpp-0.9.2/include/mapbox/geometry.hpp
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mapbox/geometry/point.hpp>
|
||||||
|
#include <mapbox/geometry/line_string.hpp>
|
||||||
|
#include <mapbox/geometry/polygon.hpp>
|
||||||
|
#include <mapbox/geometry/multi_point.hpp>
|
||||||
|
#include <mapbox/geometry/multi_line_string.hpp>
|
||||||
|
#include <mapbox/geometry/multi_polygon.hpp>
|
||||||
|
#include <mapbox/geometry/geometry.hpp>
|
||||||
|
#include <mapbox/geometry/feature.hpp>
|
||||||
|
#include <mapbox/geometry/point_arithmetic.hpp>
|
||||||
|
#include <mapbox/geometry/for_each_point.hpp>
|
||||||
|
#include <mapbox/geometry/envelope.hpp>
|
34
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/box.hpp
vendored
Normal file
34
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/box.hpp
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mapbox/geometry/point.hpp>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct box
|
||||||
|
{
|
||||||
|
using point_type = point<T>;
|
||||||
|
|
||||||
|
constexpr box(point_type const& min_, point_type const& max_)
|
||||||
|
: min(min_), max(max_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
point_type min;
|
||||||
|
point_type max;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool operator==(box<T> const& lhs, box<T> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.min == rhs.min && lhs.max == rhs.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool operator!=(box<T> const& lhs, box<T> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.min != rhs.min || lhs.max != rhs.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
33
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/envelope.hpp
vendored
Normal file
33
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/envelope.hpp
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mapbox/geometry/box.hpp>
|
||||||
|
#include <mapbox/geometry/for_each_point.hpp>
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename G, typename T = typename G::coordinate_type>
|
||||||
|
box<T> envelope(G const& geometry)
|
||||||
|
{
|
||||||
|
using limits = std::numeric_limits<T>;
|
||||||
|
|
||||||
|
T min_t = limits::has_infinity ? -limits::infinity() : limits::min();
|
||||||
|
T max_t = limits::has_infinity ? limits::infinity() : limits::max();
|
||||||
|
|
||||||
|
point<T> min(max_t, max_t);
|
||||||
|
point<T> max(min_t, min_t);
|
||||||
|
|
||||||
|
for_each_point(geometry, [&] (point<T> const& point) {
|
||||||
|
if (min.x > point.x) min.x = point.x;
|
||||||
|
if (min.y > point.y) min.y = point.y;
|
||||||
|
if (max.x < point.x) max.x = point.x;
|
||||||
|
if (max.y < point.y) max.y = point.y;
|
||||||
|
});
|
||||||
|
|
||||||
|
return box<T>(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
91
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/feature.hpp
vendored
Normal file
91
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/feature.hpp
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mapbox/geometry/geometry.hpp>
|
||||||
|
|
||||||
|
#include <mapbox/variant.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <experimental/optional>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
struct value;
|
||||||
|
|
||||||
|
struct null_value_t
|
||||||
|
{
|
||||||
|
constexpr null_value_t() {}
|
||||||
|
constexpr null_value_t(std::nullptr_t) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr bool operator==(const null_value_t&, const null_value_t&) { return true; }
|
||||||
|
constexpr bool operator!=(const null_value_t&, const null_value_t&) { return false; }
|
||||||
|
constexpr bool operator<(const null_value_t&, const null_value_t&) { return false; }
|
||||||
|
|
||||||
|
constexpr null_value_t null_value = null_value_t();
|
||||||
|
|
||||||
|
// Multiple numeric types (uint64_t, int64_t, double) are present in order to support
|
||||||
|
// the widest possible range of JSON numbers, which do not have a maximum range.
|
||||||
|
// Implementations that produce `value`s should use that order for type preference,
|
||||||
|
// using uint64_t for positive integers, int64_t for negative integers, and double
|
||||||
|
// for non-integers and integers outside the range of 64 bits.
|
||||||
|
using value_base = mapbox::util::variant<null_value_t, bool, uint64_t, int64_t, double, std::string,
|
||||||
|
mapbox::util::recursive_wrapper<std::vector<value>>,
|
||||||
|
mapbox::util::recursive_wrapper<std::unordered_map<std::string, value>>>;
|
||||||
|
|
||||||
|
struct value : value_base
|
||||||
|
{
|
||||||
|
using value_base::value_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
using property_map = std::unordered_map<std::string, value>;
|
||||||
|
|
||||||
|
// The same considerations and requirement for numeric types apply as for `value_base`.
|
||||||
|
using identifier = mapbox::util::variant<uint64_t, int64_t, double, std::string>;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct feature
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using geometry_type = mapbox::geometry::geometry<T>; // Fully qualified to avoid GCC -fpermissive error.
|
||||||
|
|
||||||
|
geometry_type geometry;
|
||||||
|
property_map properties {};
|
||||||
|
std::experimental::optional<identifier> id {};
|
||||||
|
|
||||||
|
// GCC 4.9 does not support C++14 aggregates with non-static data member
|
||||||
|
// initializers.
|
||||||
|
feature(geometry_type geometry_,
|
||||||
|
property_map properties_ = property_map {},
|
||||||
|
std::experimental::optional<identifier> id_ = std::experimental::optional<identifier> {})
|
||||||
|
: geometry(std::move(geometry_)),
|
||||||
|
properties(std::move(properties_)),
|
||||||
|
id(std::move(id_)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
constexpr bool operator==(feature<T> const& lhs, feature<T> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.id == rhs.id && lhs.geometry == rhs.geometry && lhs.properties == rhs.properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
constexpr bool operator!=(feature<T> const& lhs, feature<T> const& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, template <typename...> class Cont = std::vector>
|
||||||
|
struct feature_collection : Cont<feature<T>>
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using feature_type = feature<T>;
|
||||||
|
using container_type = Cont<feature_type>;
|
||||||
|
using container_type::container_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
45
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/for_each_point.hpp
vendored
Normal file
45
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/for_each_point.hpp
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mapbox/geometry/geometry.hpp>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename Point, typename F>
|
||||||
|
auto for_each_point(Point&& point, F&& f)
|
||||||
|
-> decltype(point.x, point.y, void())
|
||||||
|
{
|
||||||
|
f(std::forward<Point>(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container, typename F>
|
||||||
|
auto for_each_point(Container&& container, F&& f)
|
||||||
|
-> decltype(container.begin(), container.end(), void());
|
||||||
|
|
||||||
|
template <typename...Types, typename F>
|
||||||
|
void for_each_point(mapbox::util::variant<Types...> const& geom, F&& f)
|
||||||
|
{
|
||||||
|
mapbox::util::variant<Types...>::visit(geom, [&] (auto const& g) {
|
||||||
|
for_each_point(g, f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename...Types, typename F>
|
||||||
|
void for_each_point(mapbox::util::variant<Types...> & geom, F&& f)
|
||||||
|
{
|
||||||
|
mapbox::util::variant<Types...>::visit(geom, [&] (auto & g) {
|
||||||
|
for_each_point(g, f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container, typename F>
|
||||||
|
auto for_each_point(Container&& container, F&& f)
|
||||||
|
-> decltype(container.begin(), container.end(), void())
|
||||||
|
{
|
||||||
|
for (auto& e: container) {
|
||||||
|
for_each_point(e, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
58
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/geometry.hpp
vendored
Normal file
58
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/geometry.hpp
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mapbox/geometry/point.hpp>
|
||||||
|
#include <mapbox/geometry/line_string.hpp>
|
||||||
|
#include <mapbox/geometry/polygon.hpp>
|
||||||
|
#include <mapbox/geometry/multi_point.hpp>
|
||||||
|
#include <mapbox/geometry/multi_line_string.hpp>
|
||||||
|
#include <mapbox/geometry/multi_polygon.hpp>
|
||||||
|
|
||||||
|
#include <mapbox/variant.hpp>
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Cont = std::vector>
|
||||||
|
struct geometry_collection;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using geometry_base = mapbox::util::variant<point<T>,
|
||||||
|
line_string<T>,
|
||||||
|
polygon<T>,
|
||||||
|
multi_point<T>,
|
||||||
|
multi_line_string<T>,
|
||||||
|
multi_polygon<T>,
|
||||||
|
geometry_collection<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct geometry : geometry_base<T>
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using geometry_base<T>::geometry_base;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The default constructor would create a point geometry with default-constructed coordinates;
|
||||||
|
* i.e. (0, 0). Since this is not particularly useful, and could hide bugs, it is disabled.
|
||||||
|
*/
|
||||||
|
geometry() = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Cont>
|
||||||
|
struct geometry_collection : Cont<geometry<T>>
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using geometry_type = geometry<T>;
|
||||||
|
using container_type = Cont<geometry_type>;
|
||||||
|
|
||||||
|
geometry_collection() = default;
|
||||||
|
geometry_collection(geometry_collection const&) = default;
|
||||||
|
geometry_collection(geometry_collection &&) = default;
|
||||||
|
geometry_collection(std::initializer_list<geometry_type> && args)
|
||||||
|
: container_type(std::forward<std::initializer_list<geometry_type>>(args)) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
21
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/line_string.hpp
vendored
Normal file
21
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/line_string.hpp
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// mapbox
|
||||||
|
#include <mapbox/geometry/point.hpp>
|
||||||
|
// stl
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Cont = std::vector>
|
||||||
|
struct line_string : Cont<point<T> >
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using point_type = point<T>;
|
||||||
|
using container_type = Cont<point_type>;
|
||||||
|
using container_type::container_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
21
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/multi_line_string.hpp
vendored
Normal file
21
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/multi_line_string.hpp
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// mapbox
|
||||||
|
#include <mapbox/geometry/line_string.hpp>
|
||||||
|
// stl
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Cont = std::vector>
|
||||||
|
struct multi_line_string : Cont<line_string<T>>
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using line_string_type = line_string<T>;
|
||||||
|
using container_type = Cont<line_string_type>;
|
||||||
|
using container_type::container_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
21
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/multi_point.hpp
vendored
Normal file
21
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/multi_point.hpp
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// mapbox
|
||||||
|
#include <mapbox/geometry/point.hpp>
|
||||||
|
// stl
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Cont = std::vector>
|
||||||
|
struct multi_point : Cont<point<T>>
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using point_type = point<T>;
|
||||||
|
using container_type = Cont<point_type>;
|
||||||
|
using container_type::container_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
21
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/multi_polygon.hpp
vendored
Normal file
21
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/multi_polygon.hpp
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// mapbox
|
||||||
|
#include <mapbox/geometry/polygon.hpp>
|
||||||
|
// stl
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Cont = std::vector>
|
||||||
|
struct multi_polygon : Cont<polygon<T>>
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using polygon_type = polygon<T>;
|
||||||
|
using container_type = Cont<polygon_type>;
|
||||||
|
using container_type::container_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
35
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/point.hpp
vendored
Normal file
35
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/point.hpp
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct point
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
|
||||||
|
constexpr point()
|
||||||
|
: x(), y()
|
||||||
|
{}
|
||||||
|
constexpr point(T x_, T y_)
|
||||||
|
: x(x_), y(y_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
T x;
|
||||||
|
T y;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool operator==(point<T> const& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.x == rhs.x && lhs.y == rhs.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool operator!=(point<T> const& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
119
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/point_arithmetic.hpp
vendored
Normal file
119
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/point_arithmetic.hpp
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T> operator+(point<T> const& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
return point<T>(lhs.x + rhs.x, lhs.y + rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T> operator+(point<T> const& lhs, T const& rhs)
|
||||||
|
{
|
||||||
|
return point<T>(lhs.x + rhs, lhs.y + rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T> operator-(point<T> const& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
return point<T>(lhs.x - rhs.x, lhs.y - rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T> operator-(point<T> const& lhs, T const& rhs)
|
||||||
|
{
|
||||||
|
return point<T>(lhs.x - rhs, lhs.y - rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T> operator*(point<T> const& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
return point<T>(lhs.x * rhs.x, lhs.y * rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T> operator*(point<T> const& lhs, T const& rhs)
|
||||||
|
{
|
||||||
|
return point<T>(lhs.x * rhs, lhs.y * rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T> operator/(point<T> const& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
return point<T>(lhs.x / rhs.x, lhs.y / rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T> operator/(point<T> const& lhs, T const& rhs)
|
||||||
|
{
|
||||||
|
return point<T>(lhs.x / rhs, lhs.y / rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T>& operator+=(point<T>& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
lhs.x += rhs.x;
|
||||||
|
lhs.y += rhs.y;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T>& operator+=(point<T>& lhs, T const& rhs)
|
||||||
|
{
|
||||||
|
lhs.x += rhs;
|
||||||
|
lhs.y += rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T>& operator-=(point<T>& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
lhs.x -= rhs.x;
|
||||||
|
lhs.y -= rhs.y;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T>& operator-=(point<T>& lhs, T const& rhs)
|
||||||
|
{
|
||||||
|
lhs.x -= rhs;
|
||||||
|
lhs.y -= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T>& operator*=(point<T>& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
lhs.x *= rhs.x;
|
||||||
|
lhs.y *= rhs.y;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T>& operator*=(point<T>& lhs, T const& rhs)
|
||||||
|
{
|
||||||
|
lhs.x *= rhs;
|
||||||
|
lhs.y *= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T>& operator/=(point<T>& lhs, point<T> const& rhs)
|
||||||
|
{
|
||||||
|
lhs.x /= rhs.x;
|
||||||
|
lhs.y /= rhs.y;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
point<T>& operator/=(point<T>& lhs, T const& rhs)
|
||||||
|
{
|
||||||
|
lhs.x /= rhs;
|
||||||
|
lhs.y /= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
31
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/polygon.hpp
vendored
Normal file
31
third_party/geometry.hpp-0.9.2/include/mapbox/geometry/polygon.hpp
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// mapbox
|
||||||
|
#include <mapbox/geometry/point.hpp>
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace mapbox {
|
||||||
|
namespace geometry {
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Cont = std::vector>
|
||||||
|
struct linear_ring : Cont<point<T>>
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using point_type = point<T>;
|
||||||
|
using container_type = Cont<point_type>;
|
||||||
|
using container_type::container_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Cont = std::vector>
|
||||||
|
struct polygon : Cont<linear_ring<T>>
|
||||||
|
{
|
||||||
|
using coordinate_type = T;
|
||||||
|
using linear_ring_type = linear_ring<T>;
|
||||||
|
using container_type = Cont<linear_ring_type>;
|
||||||
|
using container_type::container_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geometry
|
||||||
|
} // namespace mapbox
|
5
third_party/geometry.hpp-0.9.2/tests/collection.cpp
vendored
Normal file
5
third_party/geometry.hpp-0.9.2/tests/collection.cpp
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include <mapbox/geometry.hpp>
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
mapbox::geometry::geometry_collection<double> gc;
|
||||||
|
}
|
260
third_party/geometry.hpp-0.9.2/tests/test.cpp
vendored
Normal file
260
third_party/geometry.hpp-0.9.2/tests/test.cpp
vendored
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
#include <mapbox/geometry.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
using namespace mapbox::geometry;
|
||||||
|
|
||||||
|
static void testPoint() {
|
||||||
|
point<double> p1;
|
||||||
|
assert(int(p1.x) == 0);
|
||||||
|
assert(int(p1.y) == 0);
|
||||||
|
|
||||||
|
point<uint32_t> p2(2, 3);
|
||||||
|
point<uint32_t> p3(4, 6);
|
||||||
|
|
||||||
|
assert((p2 + p3) == point<uint32_t>(6, 9));
|
||||||
|
assert((p2 + 1u) == point<uint32_t>(3, 4));
|
||||||
|
assert((p3 - p2) == point<uint32_t>(2, 3));
|
||||||
|
assert((p3 - 1u) == point<uint32_t>(3, 5));
|
||||||
|
assert((p3 * p2) == point<uint32_t>(8, 18));
|
||||||
|
assert((p2 * 2u) == point<uint32_t>(4, 6));
|
||||||
|
assert((p3 / p2) == point<uint32_t>(2, 2));
|
||||||
|
assert((p3 / 2u) == point<uint32_t>(2, 3));
|
||||||
|
|
||||||
|
{ point<uint32_t> p(2, 3); assert((p += p3) == point<uint32_t>(6, 9)); }
|
||||||
|
{ point<uint32_t> p(2, 3); assert((p += 1u) == point<uint32_t>(3, 4)); }
|
||||||
|
{ point<uint32_t> p(4, 6); assert((p -= p2) == point<uint32_t>(2, 3)); }
|
||||||
|
{ point<uint32_t> p(4, 6); assert((p -= 1u) == point<uint32_t>(3, 5)); }
|
||||||
|
{ point<uint32_t> p(4, 6); assert((p *= p2) == point<uint32_t>(8, 18)); }
|
||||||
|
{ point<uint32_t> p(2, 3); assert((p *= 2u) == point<uint32_t>(4, 6)); }
|
||||||
|
{ point<uint32_t> p(4, 6); assert((p /= p2) == point<uint32_t>(2, 2)); }
|
||||||
|
{ point<uint32_t> p(4, 6); assert((p /= 2u) == point<uint32_t>(2, 3)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testMultiPoint() {
|
||||||
|
multi_point<double> mp1;
|
||||||
|
assert(mp1.size() == 0);
|
||||||
|
|
||||||
|
multi_point<double> mp2(10);
|
||||||
|
assert(mp2.size() == 10);
|
||||||
|
|
||||||
|
assert(mp1 == mp1);
|
||||||
|
assert(!(mp1 != mp1));
|
||||||
|
assert(mp1 != mp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testLineString() {
|
||||||
|
line_string<double> ls1;
|
||||||
|
assert(ls1.size() == 0);
|
||||||
|
|
||||||
|
line_string<double> ls2(10);
|
||||||
|
assert(ls2.size() == 10);
|
||||||
|
|
||||||
|
assert(ls1 == ls1);
|
||||||
|
assert(!(ls1 != ls1));
|
||||||
|
assert(ls1 != ls2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testMultiLineString() {
|
||||||
|
multi_line_string<double> mls1;
|
||||||
|
assert(mls1.size() == 0);
|
||||||
|
|
||||||
|
multi_line_string<double> mls2(10);
|
||||||
|
assert(mls2.size() == 10);
|
||||||
|
|
||||||
|
assert(mls1 == mls1);
|
||||||
|
assert(!(mls1 != mls1));
|
||||||
|
assert(mls1 != mls2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testPolygon() {
|
||||||
|
polygon<double> pg1;
|
||||||
|
assert(pg1.size() == 0);
|
||||||
|
|
||||||
|
polygon<double> pg2({{{0, 1}}});
|
||||||
|
assert(pg2.size() == 1);
|
||||||
|
assert(pg2[0].size() == 1);
|
||||||
|
assert(pg2[0][0] == point<double>(0, 1));
|
||||||
|
|
||||||
|
assert(pg1 == pg1);
|
||||||
|
assert(!(pg1 != pg1));
|
||||||
|
assert(pg1 != pg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testMultiPolygon() {
|
||||||
|
multi_polygon<double> mpg1;
|
||||||
|
assert(mpg1.size() == 0);
|
||||||
|
|
||||||
|
multi_polygon<double> mpg2(10);
|
||||||
|
assert(mpg2.size() == 10);
|
||||||
|
|
||||||
|
assert(mpg1 == mpg1);
|
||||||
|
assert(!(mpg1 != mpg1));
|
||||||
|
assert(mpg1 != mpg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testGeometry() {
|
||||||
|
geometry<double> pg { point<double>() };
|
||||||
|
assert(pg.is<point<double>>());
|
||||||
|
|
||||||
|
geometry<double> lsg { line_string<double>() };
|
||||||
|
assert(lsg.is<line_string<double>>());
|
||||||
|
|
||||||
|
geometry<double> pgg { polygon<double>() };
|
||||||
|
assert(pgg.is<polygon<double>>());
|
||||||
|
|
||||||
|
geometry<double> mpg { multi_point<double>() };
|
||||||
|
assert(mpg.is<multi_point<double>>());
|
||||||
|
|
||||||
|
geometry<double> mlsg { multi_line_string<double>() };
|
||||||
|
assert(mlsg.is<multi_line_string<double>>());
|
||||||
|
|
||||||
|
geometry<double> mpgg { multi_polygon<double>() };
|
||||||
|
assert(mpgg.is<multi_polygon<double>>());
|
||||||
|
|
||||||
|
geometry<double> gcg { geometry_collection<double>() };
|
||||||
|
assert(gcg.is<geometry_collection<double>>());
|
||||||
|
|
||||||
|
assert(pg == pg);
|
||||||
|
assert(!(pg != pg));
|
||||||
|
assert(pg != lsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testGeometryCollection() {
|
||||||
|
geometry_collection<double> gc1;
|
||||||
|
assert(gc1.size() == 0);
|
||||||
|
|
||||||
|
assert(gc1 == gc1);
|
||||||
|
assert(!(gc1 != gc1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testFeature() {
|
||||||
|
feature<double> pf { point<double>() };
|
||||||
|
assert(pf.geometry.is<point<double>>());
|
||||||
|
assert(pf.properties.size() == 0);
|
||||||
|
|
||||||
|
auto &p = pf.properties;
|
||||||
|
|
||||||
|
p["bool"] = true;
|
||||||
|
p["string"] = std::string("foo");
|
||||||
|
p["double"] = 2.5;
|
||||||
|
p["uint"] = uint64_t(10);
|
||||||
|
p["int"] = int64_t(-10);
|
||||||
|
p["null"] = null_value;
|
||||||
|
|
||||||
|
assert(p["bool"].is<bool>());
|
||||||
|
assert(p["bool"] == true);
|
||||||
|
assert(p["string"].is<std::string>());
|
||||||
|
assert(p["string"] == std::string("foo"));
|
||||||
|
assert(p["double"].is<double>());
|
||||||
|
assert(p["double"] == 2.5);
|
||||||
|
assert(p["uint"].is<uint64_t>());
|
||||||
|
assert(p["uint"] == uint64_t(10));
|
||||||
|
assert(p["int"].is<int64_t>());
|
||||||
|
assert(p["int"] == int64_t(-10));
|
||||||
|
assert(p["null"].is<null_value_t>());
|
||||||
|
assert(p["null"] == null_value);
|
||||||
|
|
||||||
|
p["null"] = null_value_t{};
|
||||||
|
assert(p["null"].is<null_value_t>());
|
||||||
|
assert(p["null"] == null_value);
|
||||||
|
|
||||||
|
assert(p == p);
|
||||||
|
assert(!(p != p));
|
||||||
|
|
||||||
|
assert(pf == pf);
|
||||||
|
assert(!(pf != pf));
|
||||||
|
|
||||||
|
assert(p.size() == 6);
|
||||||
|
|
||||||
|
feature<double> id1 { point<double>() };
|
||||||
|
id1.id = { uint64_t(1) };
|
||||||
|
|
||||||
|
feature<double> id2 { point<double>() };
|
||||||
|
id1.id = { uint64_t(2) };
|
||||||
|
|
||||||
|
assert(id1 == id1);
|
||||||
|
assert(id1 != id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testFeatureCollection() {
|
||||||
|
feature_collection<double> fc1;
|
||||||
|
assert(fc1.size() == 0);
|
||||||
|
|
||||||
|
assert(fc1 == fc1);
|
||||||
|
assert(!(fc1 != fc1));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct point_counter {
|
||||||
|
std::size_t count = 0;
|
||||||
|
template <class Point>
|
||||||
|
void operator()(Point const&) { count++; };
|
||||||
|
};
|
||||||
|
|
||||||
|
static void testForEachPoint() {
|
||||||
|
auto count_points = [] (auto const& g) {
|
||||||
|
point_counter counter;
|
||||||
|
for_each_point(g, counter);
|
||||||
|
return counter.count;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(count_points(point<double>()) == 1);
|
||||||
|
assert(count_points(line_string<double>({{0, 1}, {2, 3}})) == 2);
|
||||||
|
assert(count_points(geometry<double>(polygon<double>({{{0, 1}, {2, 3}}}))) == 2);
|
||||||
|
|
||||||
|
auto point_negator = [] (point<double>& p) { p *= -1.0; };
|
||||||
|
|
||||||
|
point<double> p(1, 2);
|
||||||
|
for_each_point(p, point_negator);
|
||||||
|
assert(p == point<double>(-1, -2));
|
||||||
|
|
||||||
|
line_string<double> ls({{0, 1}, {2, 3}});
|
||||||
|
for_each_point(ls, point_negator);
|
||||||
|
assert(ls == line_string<double>({{0, -1}, {-2, -3}}));
|
||||||
|
|
||||||
|
geometry<double> g(polygon<double>({{{0, 1}, {2, 3}}}));
|
||||||
|
for_each_point(g, point_negator);
|
||||||
|
assert(g == geometry<double>(polygon<double>({{{0, -1}, {-2, -3}}})));
|
||||||
|
|
||||||
|
// Custom geometry type
|
||||||
|
using my_geometry = mapbox::util::variant<point<double>>;
|
||||||
|
assert(count_points(my_geometry(point<double>())) == 1);
|
||||||
|
|
||||||
|
// Custom point type
|
||||||
|
struct my_point {
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
};
|
||||||
|
assert(count_points(std::vector<my_point>({my_point{0, 1}})) == 1);
|
||||||
|
assert(count_points(mapbox::util::variant<my_point>(my_point{0, 1})) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testEnvelope() {
|
||||||
|
assert(envelope(point<double>(0, 0)) == box<double>({0, 0}, {0, 0}));
|
||||||
|
assert(envelope(line_string<double>({{0, 1}, {2, 3}})) == box<double>({0, 1}, {2, 3}));
|
||||||
|
assert(envelope(polygon<double>({{{0, 1}, {2, 3}}})) == box<double>({0, 1}, {2, 3}));
|
||||||
|
|
||||||
|
assert(envelope(multi_point<double>({{0, 0}})) == box<double>({0, 0}, {0, 0}));
|
||||||
|
assert(envelope(multi_line_string<double>({{{0, 1}, {2, 3}}})) == box<double>({0, 1}, {2, 3}));
|
||||||
|
assert(envelope(multi_polygon<double>({{{{0, 1}, {2, 3}}}})) == box<double>({0, 1}, {2, 3}));
|
||||||
|
|
||||||
|
assert(envelope(geometry<int>(point<int>(0, 0))) == box<int>({0, 0}, {0, 0}));
|
||||||
|
assert(envelope(geometry_collection<int>({point<int>(0, 0)})) == box<int>({0, 0}, {0, 0}));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
testPoint();
|
||||||
|
testMultiPoint();
|
||||||
|
testLineString();
|
||||||
|
testMultiLineString();
|
||||||
|
testPolygon();
|
||||||
|
testMultiPolygon();
|
||||||
|
testGeometry();
|
||||||
|
testGeometryCollection();
|
||||||
|
testFeature();
|
||||||
|
testFeatureCollection();
|
||||||
|
|
||||||
|
testForEachPoint();
|
||||||
|
testEnvelope();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user