Refactor StaticRTree to remove application dependent code

StaticRTree now acts like a container, just returning the input data
(NodeBasedEdge) and not PhantomNodes.
This commit is contained in:
Patrick Niklaus
2015-12-03 20:04:23 +01:00
parent a8e8f04fa3
commit cdb1918973
29 changed files with 742 additions and 1606 deletions
+106 -227
View File
@@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "../../algorithms/coordinate_calculation.hpp"
#include "../../algorithms/geospatial_query.hpp"
#include "../../data_structures/static_rtree.hpp"
#include "../../data_structures/query_node.hpp"
#include "../../data_structures/edge_based_node.hpp"
@@ -55,11 +56,12 @@ constexpr uint32_t TEST_BRANCHING_FACTOR = 8;
constexpr uint32_t TEST_LEAF_NODE_SIZE = 64;
typedef EdgeBasedNode TestData;
typedef StaticRTree<TestData,
std::vector<FixedPointCoordinate>,
false,
TEST_BRANCHING_FACTOR,
TEST_LEAF_NODE_SIZE> TestStaticRTree;
using TestStaticRTree = StaticRTree<TestData,
std::vector<FixedPointCoordinate>,
false,
TEST_BRANCHING_FACTOR,
TEST_LEAF_NODE_SIZE>;
using MiniStaticRTree = StaticRTree<TestData, std::vector<FixedPointCoordinate>, false, 2, 3>;
// Choosen by a fair W20 dice roll (this value is completely arbitrary)
constexpr unsigned RANDOM_SEED = 42;
@@ -68,113 +70,35 @@ static const int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
static const int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
static const int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
class LinearSearchNN
template <typename DataT> class LinearSearchNN
{
public:
LinearSearchNN(const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords,
const std::vector<TestData> &edges)
const std::vector<DataT> &edges)
: coords(coords), edges(edges)
{
}
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result_coordinate)
std::vector<DataT> Nearest(const FixedPointCoordinate &input_coordinate,
const unsigned num_results)
{
float min_dist = std::numeric_limits<float>::max();
FixedPointCoordinate min_coord;
for (const TestData &e : edges)
{
const FixedPointCoordinate &start = coords->at(e.u);
const FixedPointCoordinate &end = coords->at(e.v);
float distance = coordinate_calculation::great_circle_distance(
input_coordinate.lat, input_coordinate.lon, start.lat, start.lon);
if (distance < min_dist)
std::vector<DataT> local_edges(edges);
std::nth_element(
local_edges.begin(), local_edges.begin() + num_results, local_edges.end(),
[this, &input_coordinate](const DataT &lhs, const DataT &rhs)
{
min_coord = start;
min_dist = distance;
}
float current_ratio = 0.;
FixedPointCoordinate nearest;
const float lhs_dist = coordinate_calculation::perpendicular_distance(
coords->at(lhs.u), coords->at(lhs.v), input_coordinate, nearest, current_ratio);
const float rhs_dist = coordinate_calculation::perpendicular_distance(
coords->at(rhs.u), coords->at(rhs.v), input_coordinate, nearest, current_ratio);
return lhs_dist < rhs_dist;
});
local_edges.resize(num_results);
distance = coordinate_calculation::great_circle_distance(
input_coordinate.lat, input_coordinate.lon, end.lat, end.lon);
if (distance < min_dist)
{
min_coord = end;
min_dist = distance;
}
}
result_coordinate = min_coord;
return result_coordinate.is_valid();
}
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &result_phantom_node,
const unsigned)
{
float min_dist = std::numeric_limits<float>::max();
TestData nearest_edge;
for (const TestData &e : edges)
{
if (e.component.is_tiny)
continue;
float current_ratio = 0.;
FixedPointCoordinate nearest;
const float current_perpendicular_distance =
coordinate_calculation::perpendicular_distance(
coords->at(e.u), coords->at(e.v), input_coordinate, nearest, current_ratio);
if ((current_perpendicular_distance < min_dist) &&
!osrm::epsilon_compare(current_perpendicular_distance, min_dist))
{ // found a new minimum
min_dist = current_perpendicular_distance;
result_phantom_node = {e.forward_edge_based_node_id,
e.reverse_edge_based_node_id,
e.name_id,
e.forward_weight,
e.reverse_weight,
e.forward_offset,
e.reverse_offset,
e.packed_geometry_id,
e.component.is_tiny,
e.component.id,
nearest,
e.fwd_segment_position,
e.forward_travel_mode,
e.backward_travel_mode};
nearest_edge = e;
}
}
if (result_phantom_node.location.is_valid())
{
// Hack to fix rounding errors and wandering via nodes.
if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
{
result_phantom_node.location.lon = input_coordinate.lon;
}
if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
{
result_phantom_node.location.lat = input_coordinate.lat;
}
const float distance_1 = coordinate_calculation::great_circle_distance(
coords->at(nearest_edge.u), result_phantom_node.location);
const float distance_2 = coordinate_calculation::great_circle_distance(
coords->at(nearest_edge.u), coords->at(nearest_edge.v));
const float ratio = std::min(1.f, distance_1 / distance_2);
if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
{
result_phantom_node.forward_weight *= ratio;
}
if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
{
result_phantom_node.reverse_weight *= (1. - ratio);
}
}
return result_phantom_node.location.is_valid();
return local_edges;
}
private:
@@ -295,23 +219,18 @@ void simple_verify_rtree(RTreeT &rtree,
BOOST_TEST_MESSAGE("Verify end points");
for (const auto &e : edges)
{
FixedPointCoordinate result_u, result_v;
const FixedPointCoordinate &pu = coords->at(e.u);
const FixedPointCoordinate &pv = coords->at(e.v);
bool found_u = rtree.LocateClosestEndPointForCoordinate(pu, result_u, 1);
bool found_v = rtree.LocateClosestEndPointForCoordinate(pv, result_v, 1);
BOOST_CHECK(found_u && found_v);
float dist_u =
coordinate_calculation::great_circle_distance(result_u.lat, result_u.lon, pu.lat, pu.lon);
BOOST_CHECK_LE(dist_u, std::numeric_limits<float>::epsilon());
float dist_v =
coordinate_calculation::great_circle_distance(result_v.lat, result_v.lon, pv.lat, pv.lon);
BOOST_CHECK_LE(dist_v, std::numeric_limits<float>::epsilon());
auto result_u = rtree.Nearest(pu, 1);
auto result_v = rtree.Nearest(pv, 1);
BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
BOOST_CHECK(result_u.front().u == e.u || result_u.front().v == e.u);
BOOST_CHECK(result_v.front().u == e.v || result_v.front().v == e.v);
}
}
template <typename RTreeT>
void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN &lsnn, unsigned num_samples)
void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN<TestData> &lsnn, const std::vector<FixedPointCoordinate>& coords, unsigned num_samples)
{
std::mt19937 g(RANDOM_SEED);
std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
@@ -325,17 +244,22 @@ void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN &lsnn, unsigned num_sam
BOOST_TEST_MESSAGE("Sampling queries");
for (const auto &q : queries)
{
FixedPointCoordinate result_rtree;
rtree.LocateClosestEndPointForCoordinate(q, result_rtree, 1);
FixedPointCoordinate result_ln;
lsnn.LocateClosestEndPointForCoordinate(q, result_ln);
BOOST_CHECK_EQUAL(result_ln, result_rtree);
auto result_rtree = rtree.Nearest(q, 1);
auto result_lsnn = lsnn.Nearest(q, 1);
BOOST_CHECK(result_rtree.size() == 1);
BOOST_CHECK(result_lsnn.size() == 1);
auto rtree_u = result_rtree.back().u;
auto rtree_v = result_rtree.back().v;
auto lsnn_u = result_lsnn.back().u;
auto lsnn_v = result_lsnn.back().v;
PhantomNode phantom_rtree;
rtree.FindPhantomNodeForCoordinate(q, phantom_rtree, 1);
PhantomNode phantom_ln;
lsnn.FindPhantomNodeForCoordinate(q, phantom_ln, 1);
BOOST_CHECK_EQUAL(phantom_rtree, phantom_ln);
float current_ratio = 0.;
FixedPointCoordinate nearest;
const float rtree_dist = coordinate_calculation::perpendicular_distance(
coords[rtree_u], coords[rtree_v], q, nearest, current_ratio);
const float lsnn_dist = coordinate_calculation::perpendicular_distance(
coords[lsnn_u], coords[lsnn_v], q, nearest, current_ratio);
BOOST_CHECK_LE(std::abs(rtree_dist - lsnn_dist), std::numeric_limits<float>::epsilon());
}
}
@@ -365,10 +289,10 @@ void construction_test(const std::string &prefix, FixtureT *fixture)
std::string nodes_path;
build_rtree<FixtureT, RTreeT>(prefix, fixture, leaves_path, nodes_path);
RTreeT rtree(nodes_path, leaves_path, fixture->coords);
LinearSearchNN lsnn(fixture->coords, fixture->edges);
LinearSearchNN<TestData> lsnn(fixture->coords, fixture->edges);
simple_verify_rtree(rtree, fixture->coords, fixture->edges);
sampling_verify_rtree(rtree, lsnn, 100);
sampling_verify_rtree(rtree, lsnn, *fixture->coords, 100);
}
BOOST_FIXTURE_TEST_CASE(construct_half_leaf_test, TestRandomGraphFixture_LeafHalfFull)
@@ -396,51 +320,43 @@ BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_M
construction_test("test_5", this);
}
/*
* Bug: If you querry a point that lies between two BBs that have a gap,
* one BB will be pruned, even if it could contain a nearer match.
*/
// Bug: If you querry a point that lies between two BBs that have a gap,
// one BB will be pruned, even if it could contain a nearer match.
BOOST_AUTO_TEST_CASE(regression_test)
{
typedef std::pair<float, float> Coord;
typedef std::pair<unsigned, unsigned> Edge;
using Coord = std::pair<float, float>;
using Edge = std::pair<unsigned, unsigned>;
GraphFixture fixture(
{
Coord(40.0, 0.0),
Coord(35.0, 5.0),
Coord(40.0, 0.0), Coord(35.0, 5.0),
Coord(5.0, 5.0),
Coord(0.0, 10.0),
Coord(5.0, 5.0), Coord(0.0, 10.0),
Coord(20.0, 10.0),
Coord(20.0, 5.0),
Coord(20.0, 10.0), Coord(20.0, 5.0),
Coord(40.0, 100.0),
Coord(35.0, 105.0),
Coord(40.0, 100.0), Coord(35.0, 105.0),
Coord(5.0, 105.0),
Coord(0.0, 110.0),
Coord(5.0, 105.0), Coord(0.0, 110.0),
},
{Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)});
typedef StaticRTree<TestData, std::vector<FixedPointCoordinate>, false, 2, 3> MiniStaticRTree;
std::string leaves_path;
std::string nodes_path;
build_rtree<GraphFixture, MiniStaticRTree>("test_regression", &fixture, leaves_path,
nodes_path);
MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
LinearSearchNN<TestData> lsnn(fixture.coords, fixture.edges);
// query a node just right of the center of the gap
FixedPointCoordinate input(20.0 * COORDINATE_PRECISION, 55.1 * COORDINATE_PRECISION);
FixedPointCoordinate result;
rtree.LocateClosestEndPointForCoordinate(input, result, 1);
FixedPointCoordinate result_ln;
LinearSearchNN lsnn(fixture.coords, fixture.edges);
lsnn.LocateClosestEndPointForCoordinate(input, result_ln);
auto result_rtree = rtree.Nearest(input, 1);
auto result_ls = lsnn.Nearest(input, 1);
// TODO: reactivate
// BOOST_CHECK_EQUAL(result_ln, result);
BOOST_CHECK(result_rtree.size() == 1);
BOOST_CHECK(result_ls.size() == 1);
BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u);
BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v);
}
void TestRectangle(double width, double height, double center_lat, double center_lon)
@@ -448,7 +364,7 @@ void TestRectangle(double width, double height, double center_lat, double center
FixedPointCoordinate center(center_lat * COORDINATE_PRECISION,
center_lon * COORDINATE_PRECISION);
TestStaticRTree::RectangleT rect;
TestStaticRTree::Rectangle rect;
rect.min_lat = center.lat - height / 2.0 * COORDINATE_PRECISION;
rect.max_lat = center.lat + height / 2.0 * COORDINATE_PRECISION;
rect.min_lon = center.lon - width / 2.0 * COORDINATE_PRECISION;
@@ -502,100 +418,63 @@ BOOST_AUTO_TEST_CASE(rectangle_test)
TestRectangle(10, 10, 0, 0);
}
/* Verify that the bearing-bounds checking function behaves as expected */
BOOST_AUTO_TEST_CASE(bearing_range_test)
{
// Simple, non-edge-case checks
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(45, 45, 10));
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(35, 45, 10));
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(55, 45, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(34, 45, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(56, 45, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(34, 45, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(56, 45, 10));
// When angle+limit goes > 360
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(359, 355, 10));
// When angle-limit goes < 0
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(359, 5, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(354, 5, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(16, 5, 10));
// Checking other cases of wraparound
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(359, -5, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(344, -5, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(6, -5, 10));
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(-1, 5, 10));
BOOST_CHECK_EQUAL(false, TestStaticRTree::IsBearingWithinBounds(-6, 5, 10));
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(-721, 5, 10));
BOOST_CHECK_EQUAL(true, TestStaticRTree::IsBearingWithinBounds(719, 5, 10));
}
BOOST_AUTO_TEST_CASE(bearing_tests)
{
typedef std::pair<float, float> Coord;
typedef std::pair<unsigned, unsigned> Edge;
using Coord = std::pair<float, float>;
using Edge = std::pair<unsigned, unsigned>;
GraphFixture fixture(
{
Coord(0.0, 0.0),
Coord(10.0, 10.0),
Coord(0.0, 0.0), Coord(10.0, 10.0),
},
{Edge(0, 1), Edge(1,0)});
typedef StaticRTree<TestData, std::vector<FixedPointCoordinate>, false, 2, 3> MiniStaticRTree;
{Edge(0, 1), Edge(1, 0)});
std::string leaves_path;
std::string nodes_path;
build_rtree<GraphFixture, MiniStaticRTree>("test_bearing", &fixture, leaves_path, nodes_path);
MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
GeospatialQuery<MiniStaticRTree> query(rtree, fixture.coords);
FixedPointCoordinate input(5.0 * COORDINATE_PRECISION, 5.1 * COORDINATE_PRECISION);
std::vector<PhantomNode> results;
rtree.IncrementalFindPhantomNodeForCoordinate( input, results, 5);
BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK_EQUAL(results.back().forward_node_id, 0);
BOOST_CHECK_EQUAL(results.back().reverse_node_id, 1);
{
auto results = query.NearestPhantomNodes(input, 5);
BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK_EQUAL(results.back().second.forward_node_id, 0);
BOOST_CHECK_EQUAL(results.back().second.reverse_node_id, 1);
}
results.clear();
rtree.IncrementalFindPhantomNodeForCoordinate( input, results, 5, 270, 10);
BOOST_CHECK_EQUAL(results.size(), 0);
{
auto results = query.NearestPhantomNodes(input, 5, 270, 10);
BOOST_CHECK_EQUAL(results.size(), 0);
}
results.clear();
rtree.IncrementalFindPhantomNodeForCoordinate( input, results, 5, 45, 10);
BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK_EQUAL(results[0].forward_node_id, 1);
BOOST_CHECK_EQUAL(results[0].reverse_node_id, SPECIAL_NODEID);
BOOST_CHECK_EQUAL(results[1].forward_node_id, SPECIAL_NODEID);
BOOST_CHECK_EQUAL(results[1].reverse_node_id, 1);
{
auto results = query.NearestPhantomNodes(input, 5, 45, 10);
BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK_EQUAL(results[0].second.forward_node_id, 1);
BOOST_CHECK_EQUAL(results[0].second.reverse_node_id, SPECIAL_NODEID);
BOOST_CHECK_EQUAL(results[1].second.forward_node_id, SPECIAL_NODEID);
BOOST_CHECK_EQUAL(results[1].second.reverse_node_id, 1);
}
{
auto results = query.NearestPhantomNodesInRange(input, 11000);
BOOST_CHECK_EQUAL(results.size(), 2);
}
std::vector<std::pair<PhantomNode, double>> distance_results;
rtree.IncrementalFindPhantomNodeForCoordinateWithDistance( input, distance_results, 11000 );
BOOST_CHECK_EQUAL(distance_results.size(), 2);
distance_results.clear();
rtree.IncrementalFindPhantomNodeForCoordinateWithDistance( input, distance_results, 11000, 270, 10 );
BOOST_CHECK_EQUAL(distance_results.size(), 0);
distance_results.clear();
rtree.IncrementalFindPhantomNodeForCoordinateWithDistance( input, distance_results, 11000, 45, 10 );
BOOST_CHECK_EQUAL(distance_results.size(), 2);
BOOST_CHECK_EQUAL(distance_results[0].first.forward_node_id, 1);
BOOST_CHECK_EQUAL(distance_results[0].first.reverse_node_id, SPECIAL_NODEID);
BOOST_CHECK_EQUAL(distance_results[1].first.forward_node_id, SPECIAL_NODEID);
BOOST_CHECK_EQUAL(distance_results[1].first.reverse_node_id, 1);
{
auto results = query.NearestPhantomNodesInRange(input, 11000, 270, 10);
BOOST_CHECK_EQUAL(results.size(), 0);
}
{
auto results = query.NearestPhantomNodesInRange(input, 11000, 45, 10);
BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK_EQUAL(results[0].second.forward_node_id, 1);
BOOST_CHECK_EQUAL(results[0].second.reverse_node_id, SPECIAL_NODEID);
BOOST_CHECK_EQUAL(results[1].second.forward_node_id, SPECIAL_NODEID);
BOOST_CHECK_EQUAL(results[1].second.reverse_node_id, 1);
}
}
BOOST_AUTO_TEST_SUITE_END()
+72
View File
@@ -0,0 +1,72 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "../../util/bearing.hpp"
#include "../../typedefs.h"
#include <boost/functional/hash.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
BOOST_AUTO_TEST_SUITE(bearing)
// Verify that the bearing-bounds checking function behaves as expected
BOOST_AUTO_TEST_CASE(bearing_range_test)
{
// Simple, non-edge-case checks
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(45, 45, 10));
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(35, 45, 10));
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(55, 45, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(34, 45, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(56, 45, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(34, 45, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(56, 45, 10));
// When angle+limit goes > 360
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(359, 355, 10));
// When angle-limit goes < 0
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(359, 5, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(354, 5, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(16, 5, 10));
// Checking other cases of wraparound
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(359, -5, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(344, -5, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(6, -5, 10));
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(-1, 5, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(-6, 5, 10));
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(-721, 5, 10));
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(719, 5, 10));
}
BOOST_AUTO_TEST_SUITE_END()
+34
View File
@@ -0,0 +1,34 @@
/*
Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define BOOST_TEST_MODULE util tests
#include <boost/test/unit_test.hpp>
/*
* This file will contain an automatically generated main function.
*/