Compare commits

..

12 Commits

Author SHA1 Message Date
Patrick Niklaus 1869840f0e [publish binary] Test building node binaries with MLD 2017-03-22 00:51:07 +00:00
Patrick Niklaus 8532b5460b Disable doc builds because they are broken 2017-03-22 00:30:42 +00:00
Patrick Niklaus 1fdbaf4a39 Upgrade docbox 2017-03-22 00:04:46 +00:00
Patrick Niklaus 08527175b5 Fresh lock file 2017-03-21 23:44:08 +00:00
Patrick Niklaus d792572ece Install yarn on OSX by hand and update lock file 2017-03-21 23:26:32 +00:00
Patrick Niklaus 2a691ac5be Integrate documentation JS and make travis file slightly more readable 2017-03-21 22:50:08 +00:00
Patrick Niklaus 2221a34529 Switch to yarn 2017-03-21 22:37:16 +00:00
Patrick Niklaus a8fd4050a2 Integrate node-osrm docs 2017-03-21 22:29:00 +00:00
Patrick Niklaus 85ee03dfde Also copy osrm-partition and osrm-customize 2017-03-21 20:15:08 +00:00
Patrick Niklaus 694e3854d7 Test routing on CH, MLD, CoreCH via node bindings 2017-03-21 20:15:08 +00:00
Patrick Niklaus 90ed027711 Integrate MLD into node-bindings 2017-03-21 20:15:06 +00:00
Patrick Niklaus ac0c5c27e7 First steps towards integrating MLD in node bindings 2017-03-21 20:12:56 +00:00
35 changed files with 270 additions and 966 deletions
+1 -6
View File
@@ -16,8 +16,6 @@ notifications:
branches:
only:
- master
# enable building tags
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
cache:
yarn: true
@@ -28,8 +26,6 @@ cache:
env:
global:
- secure: "hk+32aXXF5t1ApaM2Wjqooz3dx1si907L87WRMkO47WlpJmUUU/Ye+MJk9sViH8MdhOcceocVAmdYl5/WFWOIbDWNlBya9QvXDZyIu2KIre/0QyOCTZbrsif8paBXKIO5O/R4OTvIZ8rvWZsadBdmAT9GSbDhih6FzqXAEgeIYQ="
- secure: "VE+cFkseFwW4jK6XwkP0yW3h4DixPJ8+Eb3yKcchGZ5iIJxlZ/8i1vKHYxadgPRwSYwPSB14tF70xj2OmiT2keGzZUfphmPXinBaLEhYk+Bde+GZZkoSl5ND109I/LcyNr0nG9dDgtV6pkvFchgchpyP9JnVOOS0+crEZlAz0RE="
- CCACHE_TEMPDIR=/tmp/.ccache-temp
- CCACHE_COMPRESS=1
- CASHER_TIME_OUT=599 # one second less than 10m to avoid 10m timeout error: https://github.com/Project-OSRM/osrm-backend/issues/2742
@@ -148,8 +144,6 @@ before_install:
sudo mdutil -i off /
npm install -g yarn
fi
- export PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
- export PUBLISH=$([[ "${TRAVIS_TAG:-}" == "v${PACKAGE_JSON_VERSION}" ]] && echo "On" || echo "Off")
- echo "Using ${JOBS} jobs"
- yarn install --ignore-scripts
# Bootstrap cmake to be able to run mason
@@ -234,5 +228,6 @@ after_success:
- |
if [ -n "${ENABLE_NODE_BINDINGS}" ]; then
source ./scripts/travis/build.sh
./scripts/travis/publish.sh
fi
-2
View File
@@ -1,5 +1,3 @@
- Track preprocessing flag in the map matching plugin.
# 5.7.0
- Changes from 5.6
- NodeJs Bindings
+6 -14
View File
@@ -41,27 +41,19 @@ The easiest and quickest way to setup your own routing engine backend is to use
### Using Docker
We base [our Docker images](https://hub.docker.com/r/osrm/osrm-backend/) on Alpine Linux and make sure they are as lightweight as possible.
We base the Docker images on Alpine Linux and make sure they are as lightweight as possible (around 10-15 MB).
In the following, replace `X.Y.Z` with the current stable release version.
```
wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf
docker run -t -v $(pwd):/data osrm/osrm-backend osrm-extract -p /opt/car.lua /data/berlin-latest.osm.pbf
docker run -t -v $(pwd):/data osrm/osrm-backend osrm-contract /data/berlin-latest.osrm
docker run -t -i -p 5000:5000 -v $(pwd):/data osrm/osrm-backend osrm-routed /data/berlin-latest.osrm
docker run -t -v $(pwd):/data osrm/osrm-backend:vX.Y.Z osrm-extract -p /opt/car.lua /data/berlin-latest.osm.pbf
docker run -t -v $(pwd):/data osrm/osrm-backend:vX.Y.Z osrm-contract /data/berlin-latest.osrm
docker run -t -i -p 5000:5000 -v $(pwd):/data osrm/osrm-backend:vX.Y.Z osrm-routed /data/berlin-latest.osrm
curl "http://127.0.0.1:5000/route/v1/driving/13.388860,52.517037;13.385983,52.496891?steps=true"
curl http://127.0.0.1:5000/route/v1/driving/13.388860,52.517037;13.385983,52.496891?steps=true
```
In case Docker complains about not being able to connect to the Docker daemon make sure you are in the `docker` group.
```
sudo usermod -aG docker $USER
```
After adding yourself to the `docker` group make sure to log out and back in again with your terminal.
### Building from Source
The following targets Ubuntu 16.04.
+3 -9
View File
@@ -141,21 +141,15 @@ SET test_osm=%test_region%.osm.pbf
IF NOT EXIST %test_osm% powershell Invoke-WebRequest https://s3.amazonaws.com/mapbox/osrm/testing/monaco.osm.pbf -OutFile %test_osm%
%Configuration%\osrm-extract.exe -p ../profiles/car.lua %test_osm%
MKDIR ch
XCOPY %test_region%.osrm.* ch\
XCOPY %test_region%.osrm ch\
XCOPY %test_region%.osrm %test_region%.osrm.* ch\
MKDIR corech
XCOPY %test_region%.osrm.* corech\
XCOPY %test_region%.osrm corech\
XCOPY %test_region%.osrm %test_region%.osrm.* corech\
MKDIR mld
XCOPY %test_region%.osrm.* mld\
XCOPY %test_region%.osrm mld\
XCOPY %test_region%.osrm %test_region%.osrm.* mld\
%Configuration%\osrm-contract.exe %test_region_ch%.osrm
%Configuration%\osrm-contract.exe --core 0.8 %test_region_corech%.osrm
%Configuration%\osrm-partition.exe %test_region_mld%.osrm
%Configuration%\osrm-customize.exe %test_region_mld%.osrm
XCOPY /Y ch\*.* ..\test\data\ch\
XCOPY /Y corech\*.* ..\test\data\corech\
XCOPY /Y mld\*.* ..\test\data\mld\
unit_tests\%Configuration%\library-tests.exe
IF NOT "%APPVEYOR_REPO_BRANCH%"=="master" GOTO DONE
-75
View File
@@ -1,75 +0,0 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "user for publishing to s3://mapbox-node-binary/osrm",
"Resources": {
"User": {
"Type": "AWS::IAM::User",
"Properties": {
"Policies": [
{
"PolicyName": "list",
"PolicyDocument": {
"Statement": [
{
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::mapbox-node-binary",
"Condition": {
"StringLike": {
"s3:prefix": [
"osrm/*"
]
}
}
}
]
}
},
{
"PolicyName": "publish",
"PolicyDocument": {
"Statement": [
{
"Action": [
"s3:DeleteObject",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:PutObject",
"s3:PutObjectAcl"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::mapbox-node-binary/osrm/*"
}
]
}
}
]
}
},
"AccessKey": {
"Type": "AWS::IAM::AccessKey",
"Properties": {
"UserName": {
"Ref": "User"
}
}
}
},
"Outputs": {
"AccessKeyId": {
"Value": {
"Ref": "AccessKey"
}
},
"SecretAccessKey": {
"Value": {
"Fn::GetAtt": [
"AccessKey",
"SecretAccessKey"
]
}
}
}
}
-59
View File
@@ -1,59 +0,0 @@
var cf = require('@mapbox/cloudfriend');
var package_json = require('../package.json')
module.exports = {
AWSTemplateFormatVersion: '2010-09-09',
Description: 'user for publishing to s3://mapbox-node-binary/' + package_json.name,
Resources: {
User: {
Type: 'AWS::IAM::User',
Properties: {
Policies: [
{
PolicyName: 'list',
PolicyDocument: {
Statement: [
{
Action: ['s3:ListBucket'],
Effect: 'Allow',
Resource: 'arn:aws:s3:::mapbox-node-binary',
Condition : {
StringLike : {
"s3:prefix": [ package_json.name + "/*"]
}
}
}
]
}
},
{
PolicyName: 'publish',
PolicyDocument: {
Statement: [
{
Action: ['s3:DeleteObject', 's3:GetObject', 's3:GetObjectAcl', 's3:PutObject', 's3:PutObjectAcl'],
Effect: 'Allow',
Resource: 'arn:aws:s3:::mapbox-node-binary/' + package_json.name + '/*'
}
]
}
}
]
}
},
AccessKey: {
Type: 'AWS::IAM::AccessKey',
Properties: {
UserName: cf.ref('User')
}
}
},
Outputs: {
AccessKeyId: {
Value: cf.ref('AccessKey')
},
SecretAccessKey: {
Value: cf.getAtt('AccessKey', 'SecretAccessKey')
}
}
};
+1
View File
@@ -1,6 +1,7 @@
coverage:
ignore:
- unit_tests/.*
- third_party/.*
comment: off
+3 -5
View File
@@ -279,8 +279,6 @@ In addition to the [general options](#general-options) the following options are
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
|timestamps |`{timestamp};{timestamp}[;{timestamp} ...]` |Timestamps for the input locations in seconds since UNIX epoch. Timestamps need to be monotonically increasing. |
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
|gaps |`split` (default), `ignore` |Allows the input track splitting based on huge timestamp gaps between points. |
|tidy |`true`, `false` (default) |Allows the input track modification to obtain better matching quality for noisy tracks. |
|Parameter |Values |
|------------|-----------------------------------|
@@ -316,7 +314,7 @@ All other properties might be undefined.
The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm) for 10 or more waypoints and uses brute force for less than 10 waypoints.
The returned path does not have to be the fastest path. As TSP is NP-hard it only returns an approximation.
Note that all input coordinates have to be connected for the trip service to work.
Note that all input coordinates have to be connected for the trip service to work.
```endpoint
GET /trip/v1/{profile}/{coordinates}?roundtrip={true|false}&source{any|first}&destination{any|last}&steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}'
@@ -336,7 +334,7 @@ In addition to the [general options](#general-options) the following options are
**Fixing Start and End Points**
It is possible to explicitely set the start or end coordinate of the trip.
It is possible to explicitely set the start or end coordinate of the trip.
When source is set to `first`, the first coordinate is used as start coordinate of the trip in the output. When destination is set to `last`, the last coordinate will be used as destination of the trip in the returned output. If you specify `any`, any of the coordinates can be used as the first or last coordinate in the output.
However, if `source=any&destination=any` the returned round-trip will still start at the first input coordinate by default.
@@ -346,7 +344,7 @@ Right now, the following combinations are possible:
| roundtrip | source | destination | supported |
| :-- | :-- | :-- | :-- |
| true | first | last | **yes** |
| true | first | last | **yes** |
| true | first | any | **yes** |
| true | any | last | **yes** |
| true | any | any | **yes** |
+3 -79
View File
@@ -25,18 +25,6 @@ As you scroll down the file you'll see local variables, and then local functions
`way_function` and `node_function` are the important functions which are called when extracting OpenStreetMap data with `osrm-extract`.
The following global properties can be set in your profile:
Attribute | Type | Notes
------------------------------|----------|----------------------------------------------------------------------------
weight_name | String | Name used in output for the routing weight property (default 'duration')
weight_precision | Unsigned | Decimal precision of edge weights (default 1)
left_hand_driving | Boolean | Are vehicles assumed to drive on the left? (used in guidance)
use_turn_restrictions | Boolean | Are turn instructions followed?
continue_straight_at_waypoint | Boolean | Must the route continue straight on at a via point, or are U-turns allowed?
max_speed_for_map_matching | Float | Maximum vehicle speed to be assumed in matching (in m/s)
max_turn_weight | Float | Maximum turn penalty weight
## way_function
Given an OpenStreetMap way, the way_function will either return nothing (meaning we are not going to route over this way at all), or it will set up a result hash to be returned. The most important thing it will do is set the value of `result.forward_speed` and `result.backward_speed` as a suitable integer value representing the speed for traversing the way.
@@ -45,79 +33,15 @@ All other calculations stem from that, including the returned timings in driving
Using the power of the scripting language you wouldn't typically see something as simple as a `result.forward_speed = 20` line within the way_function. Instead a way_function will examine the tagging (e.g. `way:get_value_by_key("highway")` and many others), process this information in various ways, calling other local functions, referencing the global variables and look-up hashes, before arriving at the result.
The following attributes can be set on the result in way_function:
Attribute | Type | Notes
----------------------------------------|----------|--------------------------------------------------------------------------
forward_speed | Float | Speed on this way in km/h
backward_speed | Float | " "
forward_rate | Float | Routing weight, expressed as meters/*weight* (e.g. for a fastest-route weighting, you would want this to be meters/second, so set it to forward_speed/3.6)
backward_rate | Float | " "
forward_mode | Enum | Mode of travel (e.g. car, ferry). Defined in include/extractor/travel_mode.hpp
backward_mode | Enum | " "
duration | Float | Alternative setter for duration of the whole way in both directions
weight | Float | Alternative setter for weight of the whole way in both directions
turn_lanes_forward | String | Directions for individual lanes (normalised OSM turn:lanes value)
turn_lanes_backward | String | " "
forward_restricted | Boolean | Is this a restricted access road? (e.g. private, or deliveries only; used to enable high turn penalty, so that way is only chosen for start/end of route)
backward_restricted | Boolean | " "
is_startpoint | Boolean | Can a journey start on this way? (e.g. ferry; if false, prevents snapping the start point to this way)
roundabout | Boolean | Is this part of a roundabout?
circular | Boolean | Is this part of a non-roundabout circular junction?
name | String | Name of the way
ref | String | Road number
pronunciation | String | Name pronunciation
road_classification.motorway_class | Boolean | Guidance: way is a motorway
road_classification.link_class | Boolean | Guidance: way is a slip/link road
road_classification.road_priority_class | Enum | Guidance: order in priority list. Defined in include/extractor/guidance/road_classification.hpp
road_classification.may_be_ignored | Boolean | Guidance: way is non-highway
road_classification.num_lanes | Unsigned | Guidance: total number of lanes in way
### Guidance
## Guidance
The guidance parameters in profiles are currently a work in progress. They can and will change.
Please be aware of this when using guidance configuration possibilities.
### Road Classification
Guidance uses road classes to decide on when/if to emit specific instructions and to discover which road is obvious when following a route.
Classification uses three flags and a priority-category.
The flags indicate whether a road is a motorway (required for on/off ramps), a link type (the ramps itself, if also a motorway) and whether a road may be omittted in considerations (is considered purely for connectivity).
The priority-category influences the decision which road is considered the obvious choice and which roads can be seen as fork.
Forks can be emitted between roads of similar priority category only. Obvious choices follow a major priority road, if the priority difference is large.
## node_function
The following attributes can be set on the result in node_function:
Attribute | Type | Notes
----------------|---------|-------------------------------------------------------
barrier | Boolean | Is it an impassable barrier?
traffic_lights | Boolean | Is it a traffic light (incurs delay in turn_function)?
## segment_function
The following attributes can be read and set on the result in segment_function:
Attribute | Read/write? | Type | Notes
-------------------|-------------|---------|------------------------------------------------------
source.lon | Read | Float | Co-ordinates of segment start
source.lat | Read | Float | " "
target.lon | Read | Float | Co-ordinates of segment end
target.lat | Read | Float | " "
target.distance | Read | Float | Length of segment
weight | Read/write | Float | Routing weight for this segment
duration | Read/write | Float | Duration for this segment
## turn_function
The following attributes can be read and set on the result in turn_function:
Attribute | Read/write? | Type | Notes
-------------------|-------------|---------|------------------------------------------------------
direction_modifier | Read | Enum | Geometry of turn. Defined in include/extractor/guidance/turn_instruction.hpp
turn_type | Read | Enum | Priority of turn. Defined in include/extractor/guidance/turn_instruction.hpp
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in way_function)
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in way_function)
angle | Read | Float | Angle of turn in degrees (0-360: 0=u-turn, 180=straight on)
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
-16
View File
@@ -79,19 +79,3 @@ Feature: Bike - Cycle tracks/lanes
| residential | lane | yes | x | x |
| footway | lane | yes | x | x |
| cycleway | lane | yes | x | x |
Scenario: Bike - Cycleway on oneways, modes
Then routability should be
| highway | cycleway | oneway | forw | backw |
| motorway | track | yes | cycling | |
| residential | track | yes | cycling | pushing bike |
| cycleway | track | yes | cycling | pushing bike |
| footway | track | yes | pushing bike | pushing bike |
Scenario: Bike - Cycleway on oneways, speeds
Then routability should be
| highway | cycleway | oneway | forw | backw |
| motorway | track | yes | 15 km/h | |
| residential | track | yes | 15 km/h | 6 km/h |
| cycleway | track | yes | 15 km/h | 6 km/h |
| footway | track | yes | 6 km/h +-1 | 6 km/h +-1 |
+3 -3
View File
@@ -10,11 +10,11 @@ Feature: osrm-partition command line options: help
And stdout should contain "--help"
And stdout should contain "Configuration:"
And stdout should contain "--threads"
And stdout should contain "--min-cell-size"
And stdout should contain "--balance"
And stdout should contain "--boundary"
And stdout should contain "--optimizing-cuts"
And stdout should contain "--small-component-size"
And stdout should contain "--max-cell-sizes"
And it should exit with an error
Scenario: osrm-partition - Help, short
@@ -26,11 +26,11 @@ Feature: osrm-partition command line options: help
And stdout should contain "--help"
And stdout should contain "Configuration:"
And stdout should contain "--threads"
And stdout should contain "--min-cell-size"
And stdout should contain "--balance"
And stdout should contain "--boundary"
And stdout should contain "--optimizing-cuts"
And stdout should contain "--small-component-size"
And stdout should contain "--max-cell-sizes"
And it should exit successfully
Scenario: osrm-partition - Help, long
@@ -42,9 +42,9 @@ Feature: osrm-partition command line options: help
And stdout should contain "--help"
And stdout should contain "Configuration:"
And stdout should contain "--threads"
And stdout should contain "--min-cell-size"
And stdout should contain "--balance"
And stdout should contain "--boundary"
And stdout should contain "--optimizing-cuts"
And stdout should contain "--small-component-size"
And stdout should contain "--max-cell-sizes"
And it should exit successfully
@@ -18,15 +18,3 @@ Feature: osrm-partition command line options: invalid options
And stderr should contain "option"
And stderr should contain "fly-me-to-the-moon"
And it should exit with an error
Scenario: osrm-partition - Check invalid values
When I try to run "osrm-partition --max-cell-sizes 4,6@4,16 fly-me-to-the-moon.osrm"
Then stdout should be empty
And stderr should contain "is invalid"
And it should exit with an error
Scenario: osrm-partition - Check non-descending order
When I try to run "osrm-partition --max-cell-sizes 4,64,16 fly-me-to-the-moon.osrm"
Then stdout should be empty
And stderr should contain "must be sorted in non-descending order"
And it should exit with an error
-78
View File
@@ -40,84 +40,6 @@ Feature: Basic Map Matching
| trace | timestamps | matchings |
| abcd | 0 1 62 63 | ab,cd |
Scenario: Testbot - Map matching with trace splitting suppression
Given the query options
| gaps | ignore |
Given the node map
"""
a b c d
e
"""
And the ways
| nodes | oneway |
| abcd | no |
When I match I should get
| trace | timestamps | matchings |
| abcd | 0 1 62 63 | abcd |
Scenario: Testbot - Map matching with trace tidying. Clean case.
Given a grid size of 100 meters
Given the query options
| tidy | true |
Given the node map
"""
a b c d
e
"""
And the ways
| nodes | oneway |
| abcd | no |
When I match I should get
| trace | timestamps | matchings |
| abcd | 0 10 20 30 | abcd |
Scenario: Testbot - Map matching with trace tidying. Dirty case by ts.
Given a grid size of 100 meters
Given the query options
| tidy | true |
Given the node map
"""
a b c d
e
"""
And the ways
| nodes | oneway |
| abcd | no |
When I match I should get
| trace | timestamps | matchings |
| abacd | 0 10 12 20 30 | abcd |
Scenario: Testbot - Map matching with trace tidying. Dirty case by dist.
Given a grid size of 8 meters
Given the query options
| tidy | true |
Given the node map
"""
a q b c d
e
"""
And the ways
| nodes | oneway |
| aqbcd | no |
When I match I should get
| trace | matchings |
| abcbd | abbd |
Scenario: Testbot - Map matching with core factor
Given the contract extra arguments "--core 0.8"
Given the node map
+5 -3
View File
@@ -3,7 +3,7 @@ Feature: Multi level routing
Background:
Given the profile "testbot"
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 4,16,64"
And the partition extra arguments "--min-cell-size 4 --small-component-size 1"
Scenario: Testbot - Multi level routing check partition
Given the node map
@@ -31,7 +31,7 @@ Feature: Multi level routing
| be | primary |
And the data has been extracted
When I run "osrm-partition --max-cell-sizes 4,16 --small-component-size 1 {processed_file}"
When I run "osrm-partition --min-cell-size 4 --small-component-size 1 {processed_file}"
Then it should exit successfully
And stdout should not contain "level 1 #cells 1 bit size 1"
@@ -57,6 +57,7 @@ Feature: Multi level routing
| cm | primary |
| hj | primary |
| kp | primary |
And the partition extra arguments "--min-cell-size 4 --small-component-size 1"
When I route I should get
| from | to | route | time |
@@ -87,6 +88,7 @@ Feature: Multi level routing
| dim | primary |
| glr | primary |
| ot | secondary |
And the partition extra arguments "--min-cell-size 4 --small-component-size 1"
When I route I should get
| from | to | route | time |
@@ -111,7 +113,6 @@ Feature: Multi level routing
lk
"""
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 4,16"
And the ways
| nodes | maxspeed |
| abcda | 5 |
@@ -123,6 +124,7 @@ Feature: Multi level routing
| fi | 15 |
| gi | 15 |
| hf | 100 |
And the partition extra arguments "--min-cell-size 4 --small-component-size 1"
When I route I should get
| from | to | route | time |
+3 -2
View File
@@ -39,9 +39,9 @@ class CellCustomizer
const EdgeWeight weight = heap.GetKey(node);
if (level == 1)
RelaxNode<true>(graph, cells, heap, level, node, weight);
RelaxNode<true>(graph, cells, heap, level, id, node, weight);
else
RelaxNode<false>(graph, cells, heap, level, node, weight);
RelaxNode<false>(graph, cells, heap, level, id, node, weight);
destinations_set.erase(node);
}
@@ -85,6 +85,7 @@ class CellCustomizer
const partition::CellStorage &cells,
Heap &heap,
LevelID level,
CellID id,
NodeID node,
EdgeWeight weight) const
{
+3 -14
View File
@@ -2,7 +2,6 @@
#define ENGINE_API_MATCH_HPP
#include "engine/api/match_parameters.hpp"
#include "engine/api/match_parameters_tidy.hpp"
#include "engine/api/route_api.hpp"
#include "engine/datafacade/datafacade_base.hpp"
@@ -22,10 +21,8 @@ namespace api
class MatchAPI final : public RouteAPI
{
public:
MatchAPI(const datafacade::BaseDataFacade &facade_,
const MatchParameters &parameters_,
const tidy::Result &tidy_result_)
: RouteAPI(facade_, parameters_), parameters(parameters_), tidy_result(tidy_result_)
MatchAPI(const datafacade::BaseDataFacade &facade_, const MatchParameters &parameters_)
: RouteAPI(facade_, parameters_), parameters(parameters_)
{
}
@@ -86,20 +83,13 @@ class MatchAPI final : public RouteAPI
for (auto point_index : util::irange(
0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
{
trace_idx_to_matching_idx[tidy_result
.tidied_to_original[sub_matchings[sub_matching_index]
.indices[point_index]]] =
trace_idx_to_matching_idx[sub_matchings[sub_matching_index].indices[point_index]] =
MatchingIndex{sub_matching_index, point_index};
}
}
for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
if (tidy_result.can_be_removed[trace_index])
{
waypoints.values.push_back(util::json::Null());
continue;
}
auto matching_index = trace_idx_to_matching_idx[trace_index];
if (matching_index.NotMatched())
{
@@ -121,7 +111,6 @@ class MatchAPI final : public RouteAPI
}
const MatchParameters &parameters;
const tidy::Result &tidy_result;
};
} // ns api
+3 -14
View File
@@ -50,34 +50,23 @@ namespace api
*/
struct MatchParameters : public RouteParameters
{
enum class GapsType
{
Split,
Ignore
};
MatchParameters()
: RouteParameters(false,
false,
false,
RouteParameters::GeometriesType::Polyline,
RouteParameters::OverviewType::Simplified,
{}),
gaps(GapsType::Split), tidy(false)
{})
{
}
template <typename... Args>
MatchParameters(std::vector<unsigned> timestamps_, GapsType gaps_, bool tidy_, Args... args_)
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)},
gaps(gaps_), tidy(tidy_)
MatchParameters(std::vector<unsigned> timestamps_, Args... args_)
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)}
{
}
std::vector<unsigned> timestamps;
GapsType gaps;
bool tidy;
bool IsValid() const
{
return RouteParameters::IsValid() &&
@@ -1,170 +0,0 @@
#ifndef COORDINATE_TIDY
#define COORDINATE_TIDY
#include <algorithm>
#include <cstdint>
#include <iterator>
#include "engine/api/match_parameters.hpp"
#include "util/coordinate_calculation.hpp"
#include <boost/assert.hpp>
#include <boost/dynamic_bitset.hpp>
namespace osrm
{
namespace engine
{
namespace api
{
namespace tidy
{
struct Thresholds
{
double distance_in_meters;
std::int32_t duration_in_seconds;
};
using Mask = boost::dynamic_bitset<>;
using Mapping = std::vector<std::size_t>;
struct Result
{
// Tidied parameters
MatchParameters parameters;
// Masking the MatchParameter parallel arrays for items which should be removed.
Mask can_be_removed;
// Maps the MatchParameter's original items to items which should not be removed.
Mapping tidied_to_original;
};
inline Result keep_all(const MatchParameters &params)
{
Result result;
result.can_be_removed.resize(params.coordinates.size(), false);
result.tidied_to_original.reserve(params.coordinates.size());
for (std::size_t current = 0; current < params.coordinates.size(); ++current)
{
result.tidied_to_original.push_back(current);
}
BOOST_ASSERT(result.can_be_removed.size() == params.coordinates.size());
// We have to filter parallel arrays that may be empty or the exact same size.
// result.parameters contains an empty MatchParameters at this point: conditionally fill.
for (std::size_t i = 0; i < result.can_be_removed.size(); ++i)
{
if (!result.can_be_removed[i])
{
result.parameters.coordinates.push_back(params.coordinates[i]);
if (!params.hints.empty())
result.parameters.hints.push_back(params.hints[i]);
if (!params.radiuses.empty())
result.parameters.radiuses.push_back(params.radiuses[i]);
if (!params.bearings.empty())
result.parameters.bearings.push_back(params.bearings[i]);
if (!params.timestamps.empty())
result.parameters.timestamps.push_back(params.timestamps[i]);
}
}
return result;
}
inline Result tidy(const MatchParameters &params, Thresholds cfg = {15., 5})
{
Result result;
result.can_be_removed.resize(params.coordinates.size(), false);
result.tidied_to_original.push_back(0);
std::size_t last_good = 0;
const auto uses_timestamps = !params.timestamps.empty();
Thresholds running{0., 0};
// Walk over adjacent (coord, ts)-pairs, with rhs being the candidate to discard or keep
for (std::size_t current = 0; current < params.coordinates.size() - 1; ++current)
{
const auto next = current + 1;
auto distance_delta = util::coordinate_calculation::haversineDistance(
params.coordinates[current], params.coordinates[next]);
running.distance_in_meters += distance_delta;
const auto over_distance = running.distance_in_meters >= cfg.distance_in_meters;
if (uses_timestamps)
{
auto duration_delta = params.timestamps[next] - params.timestamps[current];
running.duration_in_seconds += duration_delta;
const auto over_duration = running.duration_in_seconds >= cfg.duration_in_seconds;
if (over_distance && over_duration)
{
last_good = next;
result.tidied_to_original.push_back(next);
running = {0., 0}; // reset running distance and time
}
else
{
result.can_be_removed.set(next, true);
}
}
else
{
if (over_distance)
{
last_good = next;
result.tidied_to_original.push_back(next);
running = {0., 0}; // reset running distance and time
}
else
{
result.can_be_removed.set(next, true);
}
}
}
BOOST_ASSERT(result.can_be_removed.size() == params.coordinates.size());
// We have to filter parallel arrays that may be empty or the exact same size.
// result.parameters contains an empty MatchParameters at this point: conditionally fill.
for (std::size_t i = 0; i < result.can_be_removed.size(); ++i)
{
if (!result.can_be_removed[i])
{
result.parameters.coordinates.push_back(params.coordinates[i]);
if (!params.hints.empty())
result.parameters.hints.push_back(params.hints[i]);
if (!params.radiuses.empty())
result.parameters.radiuses.push_back(params.radiuses[i]);
if (!params.bearings.empty())
result.parameters.bearings.push_back(params.bearings[i]);
if (!params.timestamps.empty())
result.parameters.timestamps.push_back(params.timestamps[i]);
}
}
BOOST_ASSERT(result.tidied_to_original.size() == result.parameters.coordinates.size());
return result;
}
} // ns tidy
} // ns api
} // ns engine
} // ns osrm
#endif
+10 -19
View File
@@ -38,8 +38,7 @@ class RoutingAlgorithmsInterface
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision,
const bool allow_splitting) const = 0;
const std::vector<boost::optional<double>> &trace_gps_precision) const = 0;
virtual std::vector<routing_algorithms::TurnData>
GetTileTurns(const std::vector<datafacade::BaseDataFacade::RTreeLeaf> &edges,
@@ -80,12 +79,11 @@ template <typename AlgorithmT> class RoutingAlgorithms final : public RoutingAlg
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices) const final override;
routing_algorithms::SubMatchingList
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision,
const bool allow_splitting) const final override;
routing_algorithms::SubMatchingList MapMatching(
const routing_algorithms::CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision) const final override;
std::vector<routing_algorithms::TurnData>
GetTileTurns(const std::vector<datafacade::BaseDataFacade::RTreeLeaf> &edges,
@@ -165,16 +163,10 @@ inline routing_algorithms::SubMatchingList RoutingAlgorithms<AlgorithmT>::MapMat
const routing_algorithms::CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision,
const bool allow_splitting) const
const std::vector<boost::optional<double>> &trace_gps_precision) const
{
return routing_algorithms::mapMatching(heaps,
facade,
candidates_list,
trace_coordinates,
trace_timestamps,
trace_gps_precision,
allow_splitting);
return routing_algorithms::mapMatching(
heaps, facade, candidates_list, trace_coordinates, trace_timestamps, trace_gps_precision);
}
template <typename AlgorithmT>
@@ -215,8 +207,7 @@ inline routing_algorithms::SubMatchingList
RoutingAlgorithms<algorithm::MLD>::MapMatching(const routing_algorithms::CandidateLists &,
const std::vector<util::Coordinate> &,
const std::vector<unsigned> &,
const std::vector<boost::optional<double>> &,
const bool) const
const std::vector<boost::optional<double>> &) const
{
throw util::exception("MapMatching is not implemented");
}
@@ -28,8 +28,7 @@ mapMatching(SearchEngineData &engine_working_data,
const CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision,
const bool allow_splitting);
const std::vector<boost::optional<double>> &trace_gps_precision);
SubMatchingList
mapMatching(SearchEngineData &engine_working_data,
@@ -37,8 +36,7 @@ mapMatching(SearchEngineData &engine_working_data,
const CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision,
const bool allow_splitting);
const std::vector<boost::optional<double>> &trace_gps_precision);
}
}
}
+1 -9
View File
@@ -110,17 +110,9 @@ class MultiLevelGraph : public util::StaticGraph<EdgeDataT, UseSharedMemory>
// which can be smaller then the total number of nodes.
// this will save memory in case we sort the border nodes first
if (index >= node_to_edge_offset.size() - 1)
{
// On level 0 all edges are border edges
if (level == 0)
return SuperT::BeginEdges(node);
else
return SuperT::EndEdges(node);
}
return SuperT::BeginEdges(node);
else
{
return SuperT::BeginEdges(node) + node_to_edge_offset[index + level];
}
}
// We save the level as sentinel at the end
+2 -7
View File
@@ -13,12 +13,7 @@ namespace partition
struct PartitionConfig
{
PartitionConfig()
: requested_num_threads(0), balance(1.2), boundary_factor(0.25), num_optimizing_cuts(10),
small_component_size(1000),
max_cell_sizes{128, 128 * 32, 128 * 32 * 16, 128 * 32 * 16 * 32}
{
}
PartitionConfig() : requested_num_threads(0) {}
void UseDefaults()
{
@@ -54,11 +49,11 @@ struct PartitionConfig
unsigned requested_num_threads;
std::size_t minimum_cell_size;
double balance;
double boundary_factor;
std::size_t num_optimizing_cuts;
std::size_t small_component_size;
std::vector<std::size_t> max_cell_sizes;
};
}
}
+2 -13
View File
@@ -33,24 +33,13 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
(qi::uint_ %
';')[ph::bind(&engine::api::MatchParameters::timestamps, qi::_r1) = qi::_1];
gaps_type.add("split", engine::api::MatchParameters::GapsType::Split)(
"ignore", engine::api::MatchParameters::GapsType::Ignore);
root_rule =
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) |
(qi::lit("gaps=") >
gaps_type[ph::bind(&engine::api::MatchParameters::gaps, qi::_r1) = qi::_1]) |
(qi::lit("tidy=") >
qi::bool_[ph::bind(&engine::api::MatchParameters::tidy, qi::_r1) = qi::_1])) %
'&');
root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1)) % '&');
}
private:
qi::rule<Iterator, Signature> root_rule;
qi::rule<Iterator, Signature> timestamps_rule;
qi::symbols<char, engine::api::MatchParameters::GapsType> gaps_type;
};
}
}
+3 -3
View File
@@ -151,7 +151,7 @@ class SharedMemory
#else
void WaitForDetach()
{
util::Log(logDEBUG)
util::Log(logWARNING)
<< "Shared memory support for non-Linux systems does not wait for clients to "
"dettach. Going to sleep for 50ms.";
std::this_thread::sleep_for(std::chrono::milliseconds(50));
@@ -245,8 +245,8 @@ class SharedMemory
void WaitForDetach()
{
// FIXME this needs an implementation for Windows
util::Log(logDEBUG) << "Shared memory support for Windows does not wait for clients to "
"dettach. Going to sleep for 50ms.";
util::Log(logWARNING) << "Shared memory support for Windows does not wait for clients to "
"dettach. Going to sleep for 50ms.";
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
+19 -14
View File
@@ -1,12 +1,24 @@
{
"name": "osrm",
"version": "5.7.0-latest.1",
"private": false,
"version": "5.7.0-alpha.1",
"private": true,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": {
"chalk": "^1.1.3",
"cucumber": "^1.2.1",
"d3-queue": "^2.0.3",
"mkdirp": "^0.5.1",
"nan": "^2.1.0",
"node-cmake": "^1.2.1",
"node-pre-gyp": "^0.6.34"
"node-pre-gyp": "^0.6.34",
"node-timeout": "0.0.4",
"polyline": "^0.2.0",
"request": "^2.69.0",
"rimraf": "^2.5.4",
"xmlbuilder": "^4.2.1"
},
"bin": {
"cucumber": "./node_modules/cucumber/bin/cucumber.js"
},
"browserify": {
"transform": [
@@ -17,7 +29,8 @@
"scripts": {
"lint": "eslint -c ./.eslintrc features/step_definitions/ features/support/",
"test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld",
"clean": "rm -rf test/cache",
"clean-test": "rm -rf test/cache",
"cucumber": "./node_modules/cucumber/bin/cucumber.js",
"docs": "./scripts/build_api_docs.sh",
"install": "node-pre-gyp install --fallback-to-build=false"
},
@@ -38,17 +51,9 @@
"docbox": "^1.0.5",
"documentation": "^4.0.0-beta.18",
"eslint": "^2.4.0",
"chalk": "^1.1.3",
"cucumber": "^1.2.1",
"d3-queue": "^2.0.3",
"mkdirp": "^0.5.1",
"aws-sdk": "~2.0.31",
"tape": "^4.2.2",
"node-timeout": "0.0.4",
"polyline": "^0.2.0",
"request": "^2.69.0",
"rimraf": "^2.5.4",
"xmlbuilder": "^4.2.1"
"tape": "^4.2.2"
},
"bundleDependencies": [
"node-pre-gyp"
+6 -18
View File
@@ -444,29 +444,17 @@ function way_function (way, result)
end
-- cycleways
local has_cycleway_left, has_cycleway_right
if cycleway and profile.cycleway_tags[cycleway] then
has_cycleway_left = true
has_cycleway_right = true
elseif cycleway_left and profile.cycleway_tags[cycleway_left] then
has_cycleway_left = true
has_cycleway_right = true
elseif cycleway_right and profile.cycleway_tags[cycleway_right] then
has_cycleway_left = true
has_cycleway_right = true
end
if has_cycleway_right and
(result.forward_mode == mode.inaccessible or
result.forward_mode == mode.cycling) then
result.forward_speed = profile.bicycle_speeds["cycleway"]
end
if has_cycleway_left and
(result.backward_mode == mode.inaccessible or
result.backward_mode == mode.cycling) then
result.backward_speed = profile.bicycle_speeds["cycleway"]
elseif cycleway_left and profile.cycleway_tags[cycleway_left] then
result.forward_speed = profile.bicycle_speeds["cycleway"]
result.backward_speed = profile.bicycle_speeds["cycleway"]
elseif cycleway_right and profile.cycleway_tags[cycleway_right] then
result.forward_speed = profile.bicycle_speeds["cycleway"]
result.backward_speed = profile.bicycle_speeds["cycleway"]
end
-- dismount
if bicycle == "dismount" then
result.forward_mode = mode.pushing_bike
-1
View File
@@ -33,7 +33,6 @@ local profile = {
'sally_port',
'gate',
'no',
'kerb',
'block'
},
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env bash
set -eu
set -o pipefail
# defaults
export ENABLE_COVERAGE=${ENABLE_COVERAGE:-"Off"}
export BUILD_TYPE=${BUILD_TYPE:-"Release"}
export NODE=${NODE:-4}
export CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
export DEPS_DIR="$(pwd)/deps"
export PATH=${DEPS_DIR}/bin:${PATH}
mkdir -p ${DEPS_DIR}
export CLANG_VERSION="${CLANG_VERSION:-4.0.0}"
export CCACHE_VERSION=3.3.1
export CMAKE_VERSION=3.7.2
source ${CURRENT_DIR}/travis_helper.sh
# ensure we start inside the root directory (two level up)
cd ${CURRENT_DIR}/../../
if [[ ! $(which wget) ]]; then
echo "echo wget must be installed";
exit 1;
fi;
SYSTEM_NAME=$(uname -s)
if [[ "${SYSTEM_NAME}" == "Darwin" ]]; then
OS_NAME="osx"
elif [[ "${SYSTEM_NAME}" == "Linux" ]]; then
OS_NAME="linux"
fi
# FIXME This should be replaced by proper calls to mason but we currently have a chicken-egg problem
# since we rely on osrm-backend to ship mason for us. Once we merged this into osrm-backend this will not be needed.
CMAKE_URL="https://s3.amazonaws.com/mason-binaries/${OS_NAME}-x86_64/cmake/${CMAKE_VERSION}.tar.gz"
echo "Downloading cmake from ${CMAKE_URL} ..."
wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
CCACHE_URL="https://s3.amazonaws.com/mason-binaries/${OS_NAME}-x86_64/ccache/${CCACHE_VERSION}.tar.gz"
echo "Downloading ccache from ${CCACHE_URL} ..."
wget --quiet -O - ${CCACHE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
# install clang for linux but use the xcode version on OSX
if [[ "${OS_NAME}" != "osx" ]]; then
CLANG_URL="https://s3.amazonaws.com/mason-binaries/${OS_NAME}-x86_64/clang++/${CLANG_VERSION}.tar.gz"
echo "Downloading clang from ${CLANG_URL} ..."
wget --quiet -O - ${CLANG_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
export CCOMPILER='clang'
export CXXCOMPILER='clang++'
export CC='clang'
export CXX='clang++'
fi
if [[ "${OS_NAME}" == "osx" ]]; then
if [[ -f /etc/sysctl.conf ]] && [[ $(grep shmmax /etc/sysctl.conf) ]]; then
echo "Note: found shmmax setting in /etc/sysctl.conf, not modifying"
else
echo "WARNING: Did not find shmmax setting in /etc/sysctl.conf, adding now (requires sudo and restarting)..."
sudo sysctl -w kern.sysv.shmmax=4294967296
sudo sysctl -w kern.sysv.shmall=1048576
sudo sysctl -w kern.sysv.shmseg=128
fi
fi
echo "Now build node-osrm and dependencies"
export VERBOSE=1
if [[ "${ENABLE_COVERAGE}" == "On" ]]; then
mapbox_time "make" make -j4 coverage
else
mkdir -p build
pushd build
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_NODE_BINDINGS=On -DENABLE_MASON=On
mapbox_time "make" make -j4
popd
fi
## run tests, with backtrace support
#if [[ "${OS_NAME}" == "linux" ]]; then
# ulimit -c unlimited -S
# RESULT=0
# mapbox_time "make-test" make tests || RESULT=$?
# for i in $(find ./ -maxdepth 1 -name 'core*' -print);
# do gdb $(which node) $i -ex "thread apply all bt" -ex "set pagination 0" -batch;
# done;
# if [[ ${RESULT} != 0 ]]; then exit $RESULT; fi
#else
# # todo: coredump support on OS X
# RESULT=0
# mapbox_time "make-test" make tests || RESULT=$?
# if [[ ${RESULT} != 0 ]]; then exit $RESULT; fi
#fi
set +eu
set +o pipefail
+41 -23
View File
@@ -3,31 +3,49 @@
set -eu
set -o pipefail
if [[ ${PUBLISH} == 'On' ]]; then
echo "PUBLISH is set to '${PUBLISH}', publishing!"
# should be set for debug builds
export NPM_FLAGS=${NPM_FLAGS:-}
echo "node version is:"
which node
node -v
echo "node version is:"
which node
node -v
echo "dumping binary meta..."
./node_modules/.bin/node-pre-gyp reveal
echo "dumping binary meta..."
./node_modules/.bin/node-pre-gyp reveal ${NPM_FLAGS}
# enforce that binary has proper ORIGIN flags so that
# it can portably find libtbb.so in the same directory
if [[ $(uname -s) == 'Linux' ]]; then
readelf -d ./lib/binding/node-osrm.node > readelf-output.txt
if grep -q 'Flags: ORIGIN' readelf-output.txt; then
echo "Found ORIGIN flag in readelf output"
cat readelf-output.txt
else
echo "*** Error: Could not found ORIGIN flag in readelf output"
cat readelf-output.txt
exit 1
fi
# enforce that binary has proper ORIGIN flags so that
# it can portably find libtbb.so in the same directory
if [[ $(uname -s) == 'Linux' ]]; then
readelf -d ./lib/binding/node-osrm.node > readelf-output.txt
if grep -q 'Flags: ORIGIN' readelf-output.txt; then
echo "Found ORIGIN flag in readelf output"
cat readelf-output.txt
else
echo "*** Error: Could not found ORIGIN flag in readelf output"
cat readelf-output.txt
exit 1
fi
./node_modules/.bin/node-pre-gyp package publish info
else
echo "PUBLISH is set to '${PUBLISH}', skipping."
fi
echo "determining publishing status..."
if [[ $(./scripts/travis/is_pr_merge.sh) ]]; then
echo "Skipping publishing because this is a PR merge commit"
else
echo "This is a push commit, continuing to package..."
./node_modules/.bin/node-pre-gyp package ${NPM_FLAGS}
export COMMIT_MESSAGE=$(git log --format=%B --no-merges | head -n 1 | tr -d '\n')
echo "Commit message: ${COMMIT_MESSAGE}"
if [[ ${COMMIT_MESSAGE} =~ "[publish binary]" ]]; then
echo "Publishing"
./node_modules/.bin/node-pre-gyp publish ${NPM_FLAGS}
elif [[ ${COMMIT_MESSAGE} =~ "[republish binary]" ]]; then
echo "*** Error: Republishing is disallowed for this repository"
exit 1
#./node_modules/.bin/node-pre-gyp unpublish publish ${NPM_FLAGS}
else
echo "Skipping publishing"
fi;
fi
+10 -28
View File
@@ -3,7 +3,6 @@
#include "engine/api/match_api.hpp"
#include "engine/api/match_parameters.hpp"
#include "engine/api/match_parameters_tidy.hpp"
#include "engine/map_matching/bayes_classifier.hpp"
#include "engine/map_matching/sub_matching.hpp"
#include "util/coordinate_calculation.hpp"
@@ -146,33 +145,20 @@ Status MatchPlugin::HandleRequest(const datafacade::ContiguousInternalMemoryData
"InvalidValue", "Timestamps need to be monotonically increasing.", json_result);
}
SubMatchingList sub_matchings;
api::tidy::Result tidied;
if (parameters.tidy)
{
// Transparently tidy match parameters, do map matching on tidied parameters.
// Then use the mapping to restore the original <-> tidied relationship.
tidied = api::tidy::tidy(parameters);
}
else
{
tidied = api::tidy::keep_all(parameters);
}
// assuming radius is the standard deviation of a normal distribution
// that models GPS noise (in this model), x3 should give us the correct
// search radius with > 99% confidence
std::vector<double> search_radiuses;
if (tidied.parameters.radiuses.empty())
if (parameters.radiuses.empty())
{
search_radiuses.resize(tidied.parameters.coordinates.size(),
search_radiuses.resize(parameters.coordinates.size(),
routing_algorithms::DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER);
}
else
{
search_radiuses.resize(tidied.parameters.coordinates.size());
std::transform(tidied.parameters.radiuses.begin(),
tidied.parameters.radiuses.end(),
search_radiuses.resize(parameters.coordinates.size());
std::transform(parameters.radiuses.begin(),
parameters.radiuses.end(),
search_radiuses.begin(),
[](const boost::optional<double> &maybe_radius) {
if (maybe_radius)
@@ -187,9 +173,9 @@ Status MatchPlugin::HandleRequest(const datafacade::ContiguousInternalMemoryData
});
}
auto candidates_lists = GetPhantomNodesInRange(facade, tidied.parameters, search_radiuses);
auto candidates_lists = GetPhantomNodesInRange(facade, parameters, search_radiuses);
filterCandidates(tidied.parameters.coordinates, candidates_lists);
filterCandidates(parameters.coordinates, candidates_lists);
if (std::all_of(candidates_lists.begin(),
candidates_lists.end(),
[](const std::vector<PhantomNodeWithDistance> &candidates) {
@@ -202,12 +188,8 @@ Status MatchPlugin::HandleRequest(const datafacade::ContiguousInternalMemoryData
}
// call the actual map matching
sub_matchings =
algorithms.MapMatching(candidates_lists,
tidied.parameters.coordinates,
tidied.parameters.timestamps,
tidied.parameters.radiuses,
parameters.gaps == api::MatchParameters::GapsType::Split);
SubMatchingList sub_matchings = algorithms.MapMatching(
candidates_lists, parameters.coordinates, parameters.timestamps, parameters.radiuses);
if (sub_matchings.size() == 0)
{
@@ -238,7 +220,7 @@ Status MatchPlugin::HandleRequest(const datafacade::ContiguousInternalMemoryData
BOOST_ASSERT(sub_routes[index].shortest_path_length != INVALID_EDGE_WEIGHT);
}
api::MatchAPI match_api{facade, parameters, tidied};
api::MatchAPI match_api{facade, parameters};
match_api.MakeResponse(sub_matchings, sub_routes, json_result);
return Status::Ok;
+11 -24
View File
@@ -54,8 +54,7 @@ mapMatchingImpl(SearchEngineData &engine_working_data,
const CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision,
const bool allow_splitting)
const std::vector<boost::optional<double>> &trace_gps_precision)
{
map_matching::MatchingConfidence confidence;
map_matching::EmissionLogProbability default_emission_log_probability(DEFAULT_GPS_PRECISION);
@@ -157,24 +156,16 @@ mapMatchingImpl(SearchEngineData &engine_working_data,
for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
{
const bool gap_in_trace = [&]() {
// do not determine split if wasn't asked about it
if (allow_splitting)
const bool gap_in_trace = [&, use_timestamps]() {
// use temporal information if available to determine a split
if (use_timestamps)
{
// use temporal information if available to determine a split
if (use_timestamps)
{
return trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] >
max_broken_time;
}
else
{
return t - prev_unbroken_timestamps.back() > MAX_BROKEN_STATES;
}
return trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] >
max_broken_time;
}
else
{
return false;
return t - prev_unbroken_timestamps.back() > MAX_BROKEN_STATES;
}
}();
@@ -425,16 +416,14 @@ mapMatching(SearchEngineData &engine_working_data,
const CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision,
const bool use_tidying)
const std::vector<boost::optional<double>> &trace_gps_precision)
{
return mapMatchingImpl(engine_working_data,
facade,
candidates_list,
trace_coordinates,
trace_timestamps,
trace_gps_precision,
use_tidying);
trace_gps_precision);
}
SubMatchingList
@@ -443,8 +432,7 @@ mapMatching(SearchEngineData &engine_working_data,
const CandidateLists &candidates_list,
const std::vector<util::Coordinate> &trace_coordinates,
const std::vector<unsigned> &trace_timestamps,
const std::vector<boost::optional<double>> &trace_gps_precision,
const bool use_tidying)
const std::vector<boost::optional<double>> &trace_gps_precision)
{
return mapMatchingImpl(engine_working_data,
@@ -452,8 +440,7 @@ mapMatching(SearchEngineData &engine_working_data,
candidates_list,
trace_coordinates,
trace_timestamps,
trace_gps_precision,
use_tidying);
trace_gps_precision);
}
} // namespace routing_algorithms
+7 -3
View File
@@ -108,12 +108,12 @@ int Partitioner::Run(const PartitionConfig &config)
makeBisectionGraph(compressed_node_based_graph.coordinates,
adaptToBisectionEdge(std::move(compressed_node_based_graph.edges)));
util::Log() << " running partition: " << config.max_cell_sizes.front() << " " << config.balance
util::Log() << " running partition: " << config.minimum_cell_size << " " << config.balance
<< " " << config.boundary_factor << " " << config.num_optimizing_cuts << " "
<< config.small_component_size
<< " # max_cell_size balance boundary cuts small_component_size";
RecursiveBisection recursive_bisection(graph,
config.max_cell_sizes.front(),
config.minimum_cell_size,
config.balance,
config.boundary_factor,
config.num_optimizing_cuts,
@@ -161,7 +161,11 @@ int Partitioner::Run(const PartitionConfig &config)
std::vector<Partition> partitions;
std::vector<std::uint32_t> level_to_num_cells;
std::tie(partitions, level_to_num_cells) =
bisectionToPartition(edge_based_partition_ids, config.max_cell_sizes);
bisectionToPartition(edge_based_partition_ids,
{config.minimum_cell_size,
config.minimum_cell_size * 32,
config.minimum_cell_size * 32 * 16,
config.minimum_cell_size * 32 * 16 * 32});
auto num_unconnected = removeUnconnectedBoundaryNodes(*edge_based_graph, partitions);
util::Log() << "Fixed " << num_unconnected << " unconnected nodes";
+16 -74
View File
@@ -8,15 +8,11 @@
#include <tbb/task_scheduler_init.h>
#include <boost/algorithm/string/join.hpp>
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <iostream>
#include <iterator>
#include <regex>
using namespace osrm;
@@ -27,48 +23,7 @@ enum class return_code : unsigned
exit
};
struct MaxCellSizesArgument
{
std::vector<size_t> value;
};
std::ostream &operator<<(std::ostream &os, const MaxCellSizesArgument &arg)
{
auto to_string = [](std::size_t x) { return std::to_string(x); };
return os << boost::algorithm::join(arg.value | boost::adaptors::transformed(to_string), ",");
}
void validate(boost::any &v, const std::vector<std::string> &values, MaxCellSizesArgument *, int)
{
using namespace boost::program_options;
using namespace boost::adaptors;
// Make sure no previous assignment to 'v' was made.
validators::check_first_occurrence(v);
// Extract the first string from 'values'. If there is more than
// one string, it's an error, and exception will be thrown.
const std::string &s = validators::get_single_string(values);
std::regex re(",");
std::vector<size_t> output;
std::transform(std::sregex_token_iterator(s.begin(), s.end(), re, -1),
std::sregex_token_iterator(),
std::back_inserter(output),
[](const auto &x) {
try
{
return boost::lexical_cast<std::size_t>(x);
}
catch (const boost::bad_lexical_cast &)
{
throw validation_error(validation_error::invalid_option_value);
}
});
v = boost::any(MaxCellSizesArgument{output});
}
return_code parseArguments(int argc, char *argv[], partition::PartitionConfig &config)
return_code parseArguments(int argc, char *argv[], partition::PartitionConfig &partition_config)
{
// declare a group of options that will be allowed only on command line
boost::program_options::options_description generic_options("Options");
@@ -79,41 +34,40 @@ return_code parseArguments(int argc, char *argv[], partition::PartitionConfig &c
config_options.add_options()
//
("threads,t",
boost::program_options::value<unsigned int>(&config.requested_num_threads)
boost::program_options::value<unsigned int>(&partition_config.requested_num_threads)
->default_value(tbb::task_scheduler_init::default_num_threads()),
"Number of threads to use")
//
("min-cell-size",
boost::program_options::value<std::size_t>(&partition_config.minimum_cell_size)
->default_value(128),
"Bisection termination citerion based on cell size")
//
("balance",
boost::program_options::value<double>(&config.balance)->default_value(config.balance),
boost::program_options::value<double>(&partition_config.balance)->default_value(1.2),
"Balance for left and right side in single bisection")
//
("boundary",
boost::program_options::value<double>(&config.boundary_factor)
->default_value(config.boundary_factor),
boost::program_options::value<double>(&partition_config.boundary_factor)
->default_value(0.25),
"Percentage of embedded nodes to contract as sources and sinks")
//
("optimizing-cuts",
boost::program_options::value<std::size_t>(&config.num_optimizing_cuts)
->default_value(config.num_optimizing_cuts),
boost::program_options::value<std::size_t>(&partition_config.num_optimizing_cuts)
->default_value(10),
"Number of cuts to use for optimizing a single bisection")
//
("small-component-size",
boost::program_options::value<std::size_t>(&config.small_component_size)
->default_value(config.small_component_size),
"Size threshold for small components.")
//
("max-cell-sizes",
boost::program_options::value<MaxCellSizesArgument>()->default_value(
MaxCellSizesArgument{config.max_cell_sizes}),
"Maximum cell sizes starting from the level 1. The first cell size value is a bisection "
"termination citerion");
boost::program_options::value<std::size_t>(&partition_config.small_component_size)
->default_value(1000),
"Size threshold for small components.");
// hidden options, will be allowed on command line, but will not be
// shown to the user
boost::program_options::options_description hidden_options("Hidden options");
hidden_options.add_options()(
"input,i",
boost::program_options::value<boost::filesystem::path>(&config.base_path),
boost::program_options::value<boost::filesystem::path>(&partition_config.base_path),
"Input file in .osrm format");
// positional option
@@ -165,18 +119,6 @@ return_code parseArguments(int argc, char *argv[], partition::PartitionConfig &c
return return_code::fail;
}
if (option_variables.count("max-cell-sizes"))
{
config.max_cell_sizes = option_variables["max-cell-sizes"].as<MaxCellSizesArgument>().value;
if (!std::is_sorted(config.max_cell_sizes.begin(), config.max_cell_sizes.end()))
{
util::Log(logERROR)
<< "The maximum cell sizes array must be sorted in non-descending order.";
return return_code::fail;
}
}
return return_code::ok;
}
-132
View File
@@ -1,132 +0,0 @@
#include "engine/api/match_parameters_tidy.hpp"
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
#include <algorithm>
#include <iterator>
#include <vector>
BOOST_AUTO_TEST_SUITE(tidy_test)
using namespace osrm;
using namespace osrm::util;
using namespace osrm::engine::api;
BOOST_AUTO_TEST_CASE(two_item_trace_already_tidied_test)
{
MatchParameters params;
params.coordinates.emplace_back(FloatLongitude{13.207993}, FloatLatitude{52.446379});
params.coordinates.emplace_back(FloatLongitude{13.231658}, FloatLatitude{52.465416});
params.timestamps.emplace_back(1477090402);
params.timestamps.emplace_back(1477090663);
tidy::Thresholds thresholds;
thresholds.distance_in_meters = 15.;
thresholds.duration_in_seconds = 5;
auto result = tidy::tidy(params, thresholds);
BOOST_CHECK_EQUAL(result.can_be_removed.size(), 2);
BOOST_CHECK_EQUAL(result.tidied_to_original.size(), 2);
BOOST_CHECK(result.can_be_removed[0] == false);
BOOST_CHECK(result.can_be_removed[1] == false);
BOOST_CHECK_EQUAL(result.tidied_to_original[0], 0);
BOOST_CHECK_EQUAL(result.tidied_to_original[1], 1);
}
BOOST_AUTO_TEST_CASE(two_item_trace_needs_tidiying_test)
{
MatchParameters params;
params.coordinates.emplace_back(FloatLongitude{13.207993}, FloatLatitude{52.446379});
params.coordinates.emplace_back(FloatLongitude{13.231658}, FloatLatitude{52.465416});
params.timestamps.emplace_back(1477090402);
params.timestamps.emplace_back(1477090663);
tidy::Thresholds thresholds;
thresholds.distance_in_meters = 5000;
thresholds.duration_in_seconds = 5 * 60;
auto result = tidy::tidy(params, thresholds);
BOOST_CHECK_EQUAL(result.can_be_removed.size(), 2);
BOOST_CHECK_EQUAL(result.tidied_to_original.size(), 1);
BOOST_CHECK_EQUAL(result.can_be_removed[0], false);
BOOST_CHECK_EQUAL(result.can_be_removed[1], true);
BOOST_CHECK_EQUAL(result.tidied_to_original[0], 0);
}
BOOST_AUTO_TEST_CASE(two_blobs_in_traces_needs_tidiying_test)
{
MatchParameters params;
params.coordinates.emplace_back(FloatLongitude{13.207993}, FloatLatitude{52.446379});
params.coordinates.emplace_back(FloatLongitude{13.207994}, FloatLatitude{52.446380});
params.coordinates.emplace_back(FloatLongitude{13.207995}, FloatLatitude{52.446381});
params.coordinates.emplace_back(FloatLongitude{13.231658}, FloatLatitude{52.465416});
params.coordinates.emplace_back(FloatLongitude{13.231659}, FloatLatitude{52.465417});
params.coordinates.emplace_back(FloatLongitude{13.231660}, FloatLatitude{52.465417});
params.timestamps.emplace_back(1477090402);
params.timestamps.emplace_back(1477090403);
params.timestamps.emplace_back(1477090404);
params.timestamps.emplace_back(1477090661);
params.timestamps.emplace_back(1477090662);
params.timestamps.emplace_back(1477090663);
tidy::Thresholds thresholds;
thresholds.distance_in_meters = 15;
thresholds.duration_in_seconds = 5;
auto result = tidy::tidy(params, thresholds);
BOOST_CHECK_EQUAL(result.can_be_removed.size(), params.coordinates.size());
BOOST_CHECK_EQUAL(result.tidied_to_original.size(), 2);
BOOST_CHECK_EQUAL(result.tidied_to_original[0], 0);
BOOST_CHECK_EQUAL(result.tidied_to_original[1], 3);
const auto redundant = result.can_be_removed.count();
BOOST_CHECK_EQUAL(redundant, params.coordinates.size() - 2);
BOOST_CHECK_EQUAL(result.can_be_removed[0], false);
BOOST_CHECK_EQUAL(result.can_be_removed[3], false);
}
BOOST_AUTO_TEST_CASE(two_blobs_in_traces_needs_tidiying_no_timestamps_test)
{
MatchParameters params;
params.coordinates.emplace_back(FloatLongitude{13.207993}, FloatLatitude{52.446379});
params.coordinates.emplace_back(FloatLongitude{13.207994}, FloatLatitude{52.446380});
params.coordinates.emplace_back(FloatLongitude{13.207995}, FloatLatitude{52.446381});
params.coordinates.emplace_back(FloatLongitude{13.231658}, FloatLatitude{52.465416});
params.coordinates.emplace_back(FloatLongitude{13.231659}, FloatLatitude{52.465417});
params.coordinates.emplace_back(FloatLongitude{13.231660}, FloatLatitude{52.465417});
tidy::Thresholds thresholds;
thresholds.distance_in_meters = 15;
thresholds.duration_in_seconds = 5;
auto result = tidy::tidy(params, thresholds);
BOOST_CHECK_EQUAL(result.can_be_removed.size(), params.coordinates.size());
BOOST_CHECK_EQUAL(result.tidied_to_original.size(), 2);
BOOST_CHECK_EQUAL(result.tidied_to_original[0], 0);
BOOST_CHECK_EQUAL(result.tidied_to_original[1], 3);
const auto redundant = result.can_be_removed.count();
BOOST_CHECK_EQUAL(redundant, params.coordinates.size() - 2);
BOOST_CHECK_EQUAL(result.can_be_removed[0], false);
BOOST_CHECK_EQUAL(result.can_be_removed[3], false);
}
BOOST_AUTO_TEST_SUITE_END()
+7 -33
View File
@@ -46,11 +46,11 @@ BOOST_AUTO_TEST_SUITE(multi_level_graph)
BOOST_AUTO_TEST_CASE(check_edges_sorting)
{
// node: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
std::vector<CellID> l1{{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6}};
std::vector<CellID> l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4}};
std::vector<CellID> l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2}};
std::vector<CellID> l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}};
// node: 0 1 2 3 4 5 6 7 8 9 10 11 12
std::vector<CellID> l1{{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6}};
std::vector<CellID> l2{{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4}};
std::vector<CellID> l3{{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2}};
std::vector<CellID> l4{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
MultiLevelPartition mlp{{l1, l2, l3, l4}, {7, 5, 3, 2}};
std::vector<MockEdge> edges = {
@@ -69,8 +69,7 @@ BOOST_AUTO_TEST_CASE(check_edges_sorting)
{9, 8}, // i i i i
{10, 11}, // i i i i
{11, 10}, // i i i i
{11, 12}, // b b b b
{12, 13} // i i i i
{11, 12} // b b b b
};
auto graph = makeGraph(mlp, edges);
@@ -98,7 +97,7 @@ BOOST_AUTO_TEST_CASE(check_edges_sorting)
// the union of border and internal edge needs to equal the adjacent edges
for (auto level : util::irange<LevelID>(0, 4))
{
for (auto node : util::irange<NodeID>(0, 14))
for (auto node : util::irange<NodeID>(0, 13))
{
const auto adjacent = graph.GetAdjacentEdgeRange(node);
const auto border = graph.GetBorderEdgeRange(level, node);
@@ -123,7 +122,6 @@ BOOST_AUTO_TEST_CASE(check_edges_sorting)
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 10).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 11).size(), 2);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 12).size(), 1);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 13).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 0).size(), 1);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 1).size(), 0);
@@ -138,7 +136,6 @@ BOOST_AUTO_TEST_CASE(check_edges_sorting)
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 10).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 11).size(), 2);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 12).size(), 1);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 13).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 0).size(), 1);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 1).size(), 0);
@@ -153,7 +150,6 @@ BOOST_AUTO_TEST_CASE(check_edges_sorting)
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 10).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 11).size(), 1);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 12).size(), 1);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 13).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 0).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 1).size(), 0);
@@ -168,7 +164,6 @@ BOOST_AUTO_TEST_CASE(check_edges_sorting)
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 10).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 11).size(), 1);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(3, 12).size(), 1);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(4, 13).size(), 0);
CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 0), graph.FindEdge(0, 4));
CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(1, 3), graph.FindEdge(3, 7));
@@ -199,25 +194,4 @@ BOOST_AUTO_TEST_CASE(check_edges_sorting)
CHECK_EQUAL_RANGE(graph.GetBorderEdgeRange(4, 12), graph.FindEdge(12, 11));
}
BOOST_AUTO_TEST_CASE(check_last_internal_edge)
{
// a--b--c--d
std::vector<CellID> l1{{0, 0, 1, 1}};
std::vector<CellID> l2{{0, 0, 1, 1}};
MultiLevelPartition mlp{{l1, l2}, {2, 2}};
std::vector<MockEdge> edges = {{0, 1}, {1, 0}, {1, 2}, {2, 1}, {2, 3}, {3, 2}};
auto graph = makeGraph(mlp, edges);
auto all_edges = graph.GetAdjacentEdgeRange(3);
CHECK_EQUAL_COLLECTIONS(graph.GetBorderEdgeRange(0, 3), all_edges);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(1, 3).size(), 0);
BOOST_CHECK_EQUAL(graph.GetBorderEdgeRange(2, 3).size(), 0);
BOOST_CHECK_EQUAL(graph.GetInternalEdgeRange(0, 3).size(), 0);
CHECK_EQUAL_COLLECTIONS(graph.GetInternalEdgeRange(1, 3), all_edges);
CHECK_EQUAL_COLLECTIONS(graph.GetInternalEdgeRange(2, 3), all_edges);
}
BOOST_AUTO_TEST_SUITE_END()