Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 513a799665 | |||
| 74989f8906 | |||
| 9bf288c6dc | |||
| 3905074a81 | |||
| 42afcdf115 | |||
| 117c6b77aa | |||
| 5f5675d361 | |||
| c6472eb289 | |||
| 7b756bd0e9 | |||
| 8aed6d0d68 | |||
| d63c0ab9b9 | |||
| 0ef9580a9a | |||
| 31a997a3f7 | |||
| 2ab7fcb0b2 | |||
| e498dff90e | |||
| a9bde88dcb | |||
| d5d8f62c0d | |||
| f04377abff | |||
| e82f678665 |
+41
-28
@@ -1,3 +1,44 @@
|
|||||||
|
# 5.4.2
|
||||||
|
- Changes from 5.4.1
|
||||||
|
- Bugfixes
|
||||||
|
- #3032 Fixed a bug that could result in emitting `invalid` as an instruction type on sliproads with mode changes
|
||||||
|
- #3085 Fixed an outdated assertion that could throw without a cause for concern
|
||||||
|
- #3037 Fixed omitting the last coordinate for overview=simplified
|
||||||
|
- #3176 Fixed exposing wrong OSM ids in matching
|
||||||
|
- Fixes splitting logic in map matching
|
||||||
|
|
||||||
|
# 5.4.1
|
||||||
|
- Changes from 5.4.0
|
||||||
|
- Bugfixes
|
||||||
|
- #3016: Fixes shared memory updates while queries are running
|
||||||
|
|
||||||
|
# 5.4.0
|
||||||
|
- Changes from 5.3.0
|
||||||
|
- Profiles
|
||||||
|
- includes library guidance.lua that offers preliminary configuration on guidance.
|
||||||
|
- added left_hand_driving flag in global profile properties
|
||||||
|
- modified turn penalty function for car profile - better fit to real data
|
||||||
|
- return `ref` and `name` as separate fields. Do no use ref or destination as fallback for name value
|
||||||
|
- Guidance
|
||||||
|
- Handle Access tags for lanes, only considering valid lanes in lane-guidance (think car | car | bike | car)
|
||||||
|
- API:
|
||||||
|
- `annotations=true` now returns the data source id for each segment as `datasources`
|
||||||
|
- Reduced semantic of merge to refer only to merges from a lane onto a motorway-like road
|
||||||
|
- new `ref` field in the `RouteStep` object. It contains the reference code or name of a way. Previously merged into the `name` property like `name (ref)` and are now separate fields.
|
||||||
|
- Bugfixes
|
||||||
|
- Fixed an issue that would result in segfaults for viaroutes with an invalid intermediate segment when u-turns were allowed at the via-location
|
||||||
|
- Invalid only_* restrictions could result in loss of connectivity. As a fallback, we assume all turns allowed when the restriction is not valid
|
||||||
|
- Fixed a bug that could result in an infinite loop when finding information about an upcoming intersection
|
||||||
|
- Fixed a bug that led to not discovering if a road simply looses a considered prefix
|
||||||
|
- BREAKING: Fixed a bug that could crash postprocessing of instructions on invalid roundabout taggings. This change requires reprocessing datasets with osrm-extract and osrm-contract
|
||||||
|
- Fixed an issue that could emit `invalid` as instruction when ending on a sliproad after a traffic-light
|
||||||
|
- Fixed an issue that would detect turning circles as sliproads
|
||||||
|
- Fixed a bug where post-processing instructions (e.g. left + left -> uturn) could result in false pronunciations
|
||||||
|
- Fixes a bug where a bearing range of zero would cause exhaustive graph traversals
|
||||||
|
- Fixes a bug where certain looped geometries could cause an infinite loop during extraction
|
||||||
|
- Infrastructure:
|
||||||
|
- Adds a feature to limit results in nearest service with a default of 100 in `osrm-routed`
|
||||||
|
|
||||||
# 5.4.0-rc.7
|
# 5.4.0-rc.7
|
||||||
- Chages from 5.4.0-rc.6
|
- Chages from 5.4.0-rc.6
|
||||||
- Bugfixes re-introduce space between two entries in summaries
|
- Bugfixes re-introduce space between two entries in summaries
|
||||||
@@ -33,34 +74,6 @@
|
|||||||
- Trip Plugin
|
- Trip Plugin
|
||||||
- changed internal behaviour to prefer the smallest lexicographic result over the largest one
|
- changed internal behaviour to prefer the smallest lexicographic result over the largest one
|
||||||
|
|
||||||
# 5.4.0
|
|
||||||
- Changes from 5.3.0
|
|
||||||
- Profiles
|
|
||||||
- includes library guidance.lua that offers preliminary configuration on guidance.
|
|
||||||
- added left_hand_driving flag in global profile properties
|
|
||||||
- modified turn penalty function for car profile - better fit to real data
|
|
||||||
- return `ref` and `name` as separate fields. Do no use ref or destination as fallback for name value
|
|
||||||
- Guidance
|
|
||||||
- Handle Access tags for lanes, only considering valid lanes in lane-guidance (think car | car | bike | car)
|
|
||||||
- API:
|
|
||||||
- `annotations=true` now returns the data source id for each segment as `datasources`
|
|
||||||
- Reduced semantic of merge to refer only to merges from a lane onto a motorway-like road
|
|
||||||
- new `ref` field in the `RouteStep` object. It contains the reference code or name of a way. Previously merged into the `name` property like `name (ref)` and are now separate fields.
|
|
||||||
- Bugfixes
|
|
||||||
- Fixed an issue that would result in segfaults for viaroutes with an invalid intermediate segment when u-turns were allowed at the via-location
|
|
||||||
- Invalid only_* restrictions could result in loss of connectivity. As a fallback, we assume all turns allowed when the restriction is not valid
|
|
||||||
- Fixed a bug that could result in an infinite loop when finding information about an upcoming intersection
|
|
||||||
- Fixed a bug that led to not discovering if a road simply looses a considered prefix
|
|
||||||
- BREAKING: Fixed a bug that could crash postprocessing of instructions on invalid roundabout taggings. This change requires reprocessing datasets with osrm-extract and osrm-contract
|
|
||||||
- Fixed an issue that could emit `invalid` as instruction when ending on a sliproad after a traffic-light
|
|
||||||
- Fixed an issue that would detect turning circles as sliproads
|
|
||||||
- Fixed a bug where post-processing instructions (e.g. left + left -> uturn) could result in false pronunciations
|
|
||||||
- Fixes a bug where a bearing range of zero would cause exhaustive graph traversals
|
|
||||||
- Fixes a bug where certain looped geometries could cause an infinite loop during extraction
|
|
||||||
|
|
||||||
- Infrastructure:
|
|
||||||
- Adds a feature to limit results in nearest service with a default of 100 in `osrm-routed`
|
|
||||||
|
|
||||||
# 5.3.0
|
# 5.3.0
|
||||||
- Changes from 5.3.0-rc.3
|
- Changes from 5.3.0-rc.3
|
||||||
- Guidance
|
- Guidance
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var d3 = require('d3-queue');
|
|
||||||
var polyline = require('polyline');
|
var polyline = require('polyline');
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
@@ -43,7 +44,28 @@ module.exports = function () {
|
|||||||
|
|
||||||
if (res.statusCode === 200) {
|
if (res.statusCode === 200) {
|
||||||
if (headers.has('matchings')) {
|
if (headers.has('matchings')) {
|
||||||
subMatchings = json.matchings.filter(m => !!m).map(sub => sub.matched_points);
|
subMatchings = [];
|
||||||
|
|
||||||
|
// find the first matched
|
||||||
|
let start_index = 0;
|
||||||
|
while (start_index < json.tracepoints.length && json.tracepoints[start_index] === null) start_index++;
|
||||||
|
|
||||||
|
var sub = [];
|
||||||
|
let prev_index = null;
|
||||||
|
for(var i = start_index; i < json.tracepoints.length; i++){
|
||||||
|
if (json.tracepoints[i] === null) continue;
|
||||||
|
|
||||||
|
let current_index = json.tracepoints[i].matchings_index;
|
||||||
|
|
||||||
|
if(prev_index !== current_index) {
|
||||||
|
if (sub.length > 0) subMatchings.push(sub);
|
||||||
|
sub = [];
|
||||||
|
prev_index = current_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub.push(json.tracepoints[i].location);
|
||||||
|
}
|
||||||
|
subMatchings.push(sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headers.has('turns')) {
|
if (headers.has('turns')) {
|
||||||
@@ -68,11 +90,11 @@ module.exports = function () {
|
|||||||
|
|
||||||
if (headers.has('geometry')) {
|
if (headers.has('geometry')) {
|
||||||
if (json.matchings.length != 1) throw new Error('*** Checking geometry only supported for matchings with one subtrace');
|
if (json.matchings.length != 1) throw new Error('*** Checking geometry only supported for matchings with one subtrace');
|
||||||
geometry = json.matchings[0].geometry;
|
geometry = json.matchings[0].geometry.coordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headers.has('OSM IDs')) {
|
if (headers.has('OSM IDs')) {
|
||||||
if (json.matchings.length != 1) throw new Error('*** CHecking annotation only supported for matchings with one subtrace');
|
if (json.matchings.length != 1) throw new Error('*** Checking annotation only supported for matchings with one subtrace');
|
||||||
OSMIDs = this.OSMIDList(json.matchings[0]);
|
OSMIDs = this.OSMIDList(json.matchings[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,17 +130,8 @@ module.exports = function () {
|
|||||||
var encodedResult = '',
|
var encodedResult = '',
|
||||||
extendedTarget = '';
|
extendedTarget = '';
|
||||||
|
|
||||||
var q = d3.queue();
|
var testSubMatching = (sub, si) => {
|
||||||
|
var testSubNode = (ni) => {
|
||||||
var testSubMatching = (sub, si, scb) => {
|
|
||||||
if (si >= subMatchings.length) {
|
|
||||||
ok = false;
|
|
||||||
q.abort();
|
|
||||||
scb();
|
|
||||||
} else {
|
|
||||||
var sq = d3.queue();
|
|
||||||
|
|
||||||
var testSubNode = (ni, ncb) => {
|
|
||||||
var node = this.findNodeByName(sub[ni]),
|
var node = this.findNodeByName(sub[ni]),
|
||||||
outNode = subMatchings[si][ni];
|
outNode = subMatchings[si][ni];
|
||||||
|
|
||||||
@@ -126,26 +139,32 @@ module.exports = function () {
|
|||||||
encodedResult += sub[ni];
|
encodedResult += sub[ni];
|
||||||
extendedTarget += sub[ni];
|
extendedTarget += sub[ni];
|
||||||
} else {
|
} else {
|
||||||
|
if (outNode != null) {
|
||||||
encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]);
|
encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]);
|
||||||
|
} else {
|
||||||
|
encodedResult += '?';
|
||||||
|
}
|
||||||
extendedTarget += util.format('%s [%d,%d]', node.lat, node.lon);
|
extendedTarget += util.format('%s [%d,%d]', node.lat, node.lon);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
ncb();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var i=0; i<sub.length; i++) {
|
for (var i=0; i<sub.length; i++) {
|
||||||
sq.defer(testSubNode, i);
|
testSubNode(i);
|
||||||
}
|
|
||||||
|
|
||||||
sq.awaitAll(scb);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
row.matchings.split(',').forEach((sub, si) => {
|
if (headers.has('matchings')) {
|
||||||
q.defer(testSubMatching, sub, si);
|
if (subMatchings.length != row.matchings.split(',').length) {
|
||||||
});
|
ok = false;
|
||||||
|
cb(new Error('*** table matchings and api response are not the same'));
|
||||||
|
}
|
||||||
|
|
||||||
|
row.matchings.split(',').forEach((sub, si) => {
|
||||||
|
testSubMatching(sub, si);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
q.awaitAll(() => {
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
if (headers.has('matchings')) {
|
if (headers.has('matchings')) {
|
||||||
got.matchings = row.matchings;
|
got.matchings = row.matchings;
|
||||||
@@ -160,7 +179,6 @@ module.exports = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cb(null, got);
|
cb(null, got);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (row.request) {
|
if (row.request) {
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
matchLocation (got, want) {
|
matchLocation (got, want) {
|
||||||
|
if (got == null || want == null) return false;
|
||||||
return this.match(got[0], util.format('%d ~0.0025%', want.lon)) &&
|
return this.match(got[0], util.format('%d ~0.0025%', want.lon)) &&
|
||||||
this.match(got[1], util.format('%d ~0.0025%', want.lat));
|
this.match(got[1], util.format('%d ~0.0025%', want.lat));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ Feature: Basic Map Matching
|
|||||||
Given the profile "testbot"
|
Given the profile "testbot"
|
||||||
Given a grid size of 10 meters
|
Given a grid size of 10 meters
|
||||||
Given the extract extra arguments "--generate-edge-lookup"
|
Given the extract extra arguments "--generate-edge-lookup"
|
||||||
|
Given the query options
|
||||||
|
| geometries | geojson |
|
||||||
|
|
||||||
Scenario: Testbot - Map matching with outlier that has no candidate
|
Scenario: Testbot - Map matching with outlier that has no candidate
|
||||||
Given a grid size of 100 meters
|
Given a grid size of 100 meters
|
||||||
@@ -21,7 +23,7 @@ Feature: Basic Map Matching
|
|||||||
|
|
||||||
When I match I should get
|
When I match I should get
|
||||||
| trace | timestamps | matchings |
|
| trace | timestamps | matchings |
|
||||||
| ab1d | 0 1 2 3 | abcd |
|
| ab1d | 0 1 2 3 | ad |
|
||||||
|
|
||||||
Scenario: Testbot - Map matching with trace splitting
|
Scenario: Testbot - Map matching with trace splitting
|
||||||
Given the node map
|
Given the node map
|
||||||
@@ -103,8 +105,8 @@ Feature: Basic Map Matching
|
|||||||
|
|
||||||
When I match I should get
|
When I match I should get
|
||||||
| trace | matchings |
|
| trace | matchings |
|
||||||
| dcba | hg,gf,fe |
|
| dcba | hgfe |
|
||||||
| efgh | ab,bc,cd |
|
| efgh | abcd |
|
||||||
|
|
||||||
Scenario: Testbot - Duration details
|
Scenario: Testbot - Duration details
|
||||||
Given the query options
|
Given the query options
|
||||||
@@ -128,23 +130,47 @@ Feature: Basic Map Matching
|
|||||||
|
|
||||||
When I match I should get
|
When I match I should get
|
||||||
| trace | matchings | annotation |
|
| trace | matchings | annotation |
|
||||||
| abeh | abcedgh | 1:9.897633:1,0:0:0,1:10.008842:0,1:10.008842:0,1:10.008842:0,0:0:0,2:20.017685:0,1:10.008842:0 |
|
| abeh | abeh | 1:9.897633:1,0:0:0,1:10.008842:0,1:10.008842:0,1:10.008842:0,0:0:0,2:20.017685:0,1:10.008842:0 |
|
||||||
| abci | abc,ci | 1:9.897633:1,0:0:0,1:10.008842:0,0:0.111209:0,1:10.010367:0 |
|
| abci | abci | 1:9.897633:1,0:0:0,1:10.008842:0,0:0.111209:0,1:10.010367:0 |
|
||||||
|
|
||||||
# The following is the same as the above, but separated for readability (line length)
|
# The following is the same as the above, but separated for readability (line length)
|
||||||
When I match I should get
|
When I match I should get
|
||||||
| trace | matchings | OSM IDs |
|
| trace | matchings | OSM IDs |
|
||||||
| abeh | abcedgh | 1,2,3,2,3,4,5,4,5,6,7 |
|
| abeh | abeh | 1,2,3,2,3,4,5,4,5,6,7 |
|
||||||
| abci | abc,ci | 1,2,3,2,3,8,3,8 |
|
| abci | abci | 1,2,3,2,3,8,3,8 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Regression test for #3037
|
||||||
|
Given the query options
|
||||||
|
| overview | simplified |
|
||||||
|
| geometries | geojson |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
| a | | b | | c |
|
||||||
|
| | | | | |
|
||||||
|
| | | | | |
|
||||||
|
| | | | | |
|
||||||
|
| e | | f | | g |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abc | yes |
|
||||||
|
| efg | yes |
|
||||||
|
| ae | yes |
|
||||||
|
| cg | yes |
|
||||||
|
| fb | yes |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | matchings | geometry |
|
||||||
|
| efbc | efbc | 1,0.99964,1.000178,0.99964,1.000178,1,1.000359,1 |
|
||||||
|
|
||||||
Scenario: Testbot - Geometry details
|
Scenario: Testbot - Geometry details
|
||||||
Given the query options
|
Given the query options
|
||||||
| overview | full |
|
| overview | full |
|
||||||
| geometries | polyline |
|
| geometries | geojson |
|
||||||
|
|
||||||
Given the node map
|
Given the node map
|
||||||
| a | b | c |
|
| a | | b | | c |
|
||||||
| | d | |
|
| | | d | | |
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
| nodes | oneway |
|
| nodes | oneway |
|
||||||
@@ -153,4 +179,63 @@ Feature: Basic Map Matching
|
|||||||
|
|
||||||
When I match I should get
|
When I match I should get
|
||||||
| trace | matchings | geometry |
|
| trace | matchings | geometry |
|
||||||
| abd | abd | 1,1,1,1.00009,1,1.00009,0.99991,1.00009 |
|
| abd | abd | 1,1,1.000179,1,1.000178,1,1.000178,0.99991 |
|
||||||
|
|
||||||
|
# Regression test 1 for issue 3176
|
||||||
|
Scenario: Testbot - multiuple segments: properly expose OSM IDs
|
||||||
|
Given the query options
|
||||||
|
| annotations | true |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
| a | 1 | b | | c | | d | | e | | f | 2 | g |
|
||||||
|
|
||||||
|
And the nodes
|
||||||
|
| node | id |
|
||||||
|
| a | 1 |
|
||||||
|
| b | 2 |
|
||||||
|
| c | 3 |
|
||||||
|
| d | 4 |
|
||||||
|
| e | 5 |
|
||||||
|
| f | 6 |
|
||||||
|
| g | 7 |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| ab | no |
|
||||||
|
| bc | no |
|
||||||
|
| cd | no |
|
||||||
|
| de | no |
|
||||||
|
| ef | no |
|
||||||
|
| fg | no |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | OSM IDs |
|
||||||
|
| 12 | 1,2,3,4,5,6,7 |
|
||||||
|
| 21 | 7,6,5,4,3,2,1 |
|
||||||
|
|
||||||
|
# Regression test 2 for issue 3176
|
||||||
|
Scenario: Testbot - same edge: properly expose OSM IDs
|
||||||
|
Given the query options
|
||||||
|
| annotations | true |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
| a | 1 | b | | c | | d | | e | 2 | f |
|
||||||
|
|
||||||
|
And the nodes
|
||||||
|
| node | id |
|
||||||
|
| a | 1 |
|
||||||
|
| b | 2 |
|
||||||
|
| c | 3 |
|
||||||
|
| d | 4 |
|
||||||
|
| e | 5 |
|
||||||
|
| f | 6 |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abcdef | no |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | OSM IDs |
|
||||||
|
| 12 | 1,2,3,4,5,6 |
|
||||||
|
| 21 | 6,5,4,3,2,1 |
|
||||||
|
|
||||||
|
|||||||
@@ -94,8 +94,12 @@ class RouteAPI : public BaseAPI
|
|||||||
const bool reversed_source = source_traversed_in_reverse[idx];
|
const bool reversed_source = source_traversed_in_reverse[idx];
|
||||||
const bool reversed_target = target_traversed_in_reverse[idx];
|
const bool reversed_target = target_traversed_in_reverse[idx];
|
||||||
|
|
||||||
auto leg_geometry = guidance::assembleGeometry(
|
auto leg_geometry = guidance::assembleGeometry(BaseAPI::facade,
|
||||||
BaseAPI::facade, path_data, phantoms.source_phantom, phantoms.target_phantom);
|
path_data,
|
||||||
|
phantoms.source_phantom,
|
||||||
|
phantoms.target_phantom,
|
||||||
|
reversed_source,
|
||||||
|
reversed_target);
|
||||||
auto leg = guidance::assembleLeg(facade,
|
auto leg = guidance::assembleLeg(facade,
|
||||||
path_data,
|
path_data,
|
||||||
leg_geometry,
|
leg_geometry,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#ifndef ENGINE_HPP
|
#ifndef ENGINE_HPP
|
||||||
#define ENGINE_HPP
|
#define ENGINE_HPP
|
||||||
|
|
||||||
#include "storage/shared_barriers.hpp"
|
|
||||||
#include "engine/status.hpp"
|
#include "engine/status.hpp"
|
||||||
#include "util/json_container.hpp"
|
#include "util/json_container.hpp"
|
||||||
|
|
||||||
@@ -20,6 +19,11 @@ struct Object;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace storage
|
||||||
|
{
|
||||||
|
struct SharedBarriers;
|
||||||
|
}
|
||||||
|
|
||||||
// Fwd decls
|
// Fwd decls
|
||||||
namespace engine
|
namespace engine
|
||||||
{
|
{
|
||||||
@@ -52,9 +56,6 @@ class BaseDataFacade;
|
|||||||
class Engine final
|
class Engine final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Needs to be public
|
|
||||||
struct EngineLock;
|
|
||||||
|
|
||||||
explicit Engine(const EngineConfig &config);
|
explicit Engine(const EngineConfig &config);
|
||||||
|
|
||||||
Engine(Engine &&) noexcept;
|
Engine(Engine &&) noexcept;
|
||||||
@@ -71,7 +72,7 @@ class Engine final
|
|||||||
Status Tile(const api::TileParameters ¶meters, std::string &result) const;
|
Status Tile(const api::TileParameters ¶meters, std::string &result) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<EngineLock> lock;
|
std::unique_ptr<storage::SharedBarriers> lock;
|
||||||
|
|
||||||
std::unique_ptr<plugins::ViaRoutePlugin> route_plugin;
|
std::unique_ptr<plugins::ViaRoutePlugin> route_plugin;
|
||||||
std::unique_ptr<plugins::TablePlugin> table_plugin;
|
std::unique_ptr<plugins::TablePlugin> table_plugin;
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ namespace guidance
|
|||||||
inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||||
const std::vector<PathData> &leg_data,
|
const std::vector<PathData> &leg_data,
|
||||||
const PhantomNode &source_node,
|
const PhantomNode &source_node,
|
||||||
const PhantomNode &target_node)
|
const PhantomNode &target_node,
|
||||||
|
const bool reversed_source,
|
||||||
|
const bool reversed_target)
|
||||||
{
|
{
|
||||||
LegGeometry geometry;
|
LegGeometry geometry;
|
||||||
|
|
||||||
@@ -43,16 +45,30 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
|||||||
geometry.segment_offsets.push_back(0);
|
geometry.segment_offsets.push_back(0);
|
||||||
geometry.locations.push_back(source_node.location);
|
geometry.locations.push_back(source_node.location);
|
||||||
|
|
||||||
// Need to get the node ID preceding the source phantom node
|
// u * v
|
||||||
// TODO: check if this was traversed in reverse?
|
// 0 -- 1 -- 2 -- 3
|
||||||
std::vector<NodeID> reverse_geometry;
|
// fwd_segment_position: 1
|
||||||
facade.GetUncompressedGeometry(source_node.reverse_packed_geometry_id, reverse_geometry);
|
// source node fwd: 1 1 -> 2 -> 3
|
||||||
geometry.osm_node_ids.push_back(facade.GetOSMNodeIDOfNode(
|
// source node rev: 2 0 <- 1 <- 2
|
||||||
reverse_geometry[reverse_geometry.size() - source_node.fwd_segment_position - 1]));
|
const auto source_segment_start_coordinate =
|
||||||
|
source_node.fwd_segment_position + (reversed_source ? 1 : 0);
|
||||||
|
|
||||||
std::vector<uint8_t> forward_datasource_vector;
|
// we don't save the first node id in the forward geometry, we need to get it as last coordinate from the reverse
|
||||||
facade.GetUncompressedDatasources(source_node.forward_packed_geometry_id,
|
// geometry
|
||||||
forward_datasource_vector);
|
if (source_segment_start_coordinate == 0)
|
||||||
|
{
|
||||||
|
std::vector<NodeID> source_geometry;
|
||||||
|
facade.GetUncompressedGeometry(source_node.reverse_packed_geometry_id, source_geometry);
|
||||||
|
geometry.osm_node_ids.push_back(
|
||||||
|
facade.GetOSMNodeIDOfNode(source_geometry.back()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<NodeID> source_geometry;
|
||||||
|
facade.GetUncompressedGeometry(source_node.forward_packed_geometry_id, source_geometry);
|
||||||
|
geometry.osm_node_ids.push_back(
|
||||||
|
facade.GetOSMNodeIDOfNode(source_geometry[source_segment_start_coordinate - 1]));
|
||||||
|
}
|
||||||
|
|
||||||
auto cumulative_distance = 0.;
|
auto cumulative_distance = 0.;
|
||||||
auto current_distance = 0.;
|
auto current_distance = 0.;
|
||||||
@@ -94,12 +110,29 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
|||||||
geometry.segment_offsets.push_back(geometry.locations.size());
|
geometry.segment_offsets.push_back(geometry.locations.size());
|
||||||
geometry.locations.push_back(target_node.location);
|
geometry.locations.push_back(target_node.location);
|
||||||
|
|
||||||
// Need to get the node ID following the destination phantom node
|
// u * v
|
||||||
// TODO: check if this was traversed in reverse??
|
// 0 -- 1 -- 2 -- 3
|
||||||
std::vector<NodeID> forward_geometry;
|
// fwd_segment_position: 1
|
||||||
facade.GetUncompressedGeometry(target_node.forward_packed_geometry_id, forward_geometry);
|
// target node fwd: 2 0 -> 1 -> 2
|
||||||
|
// target node rev: 1 1 <- 2 <- 3
|
||||||
|
const auto target_segment_end_coordinate =
|
||||||
|
target_node.fwd_segment_position + (reversed_target ? 0 : 1);
|
||||||
|
// we don't save the first node id in the forward geometry, we need to get it as last coordinate from the reverse
|
||||||
|
// geometry
|
||||||
|
if (target_segment_end_coordinate == 0)
|
||||||
|
{
|
||||||
|
std::vector<NodeID> target_geometry;
|
||||||
|
facade.GetUncompressedGeometry(target_node.reverse_packed_geometry_id, target_geometry);
|
||||||
geometry.osm_node_ids.push_back(
|
geometry.osm_node_ids.push_back(
|
||||||
facade.GetOSMNodeIDOfNode(forward_geometry[target_node.fwd_segment_position]));
|
facade.GetOSMNodeIDOfNode(target_geometry.back()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<NodeID> target_geometry;
|
||||||
|
facade.GetUncompressedGeometry(target_node.forward_packed_geometry_id, target_geometry);
|
||||||
|
geometry.osm_node_ids.push_back(
|
||||||
|
facade.GetOSMNodeIDOfNode(target_geometry[target_segment_end_coordinate - 1]));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
|
BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
|
||||||
BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
|
BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
|
||||||
|
|||||||
@@ -176,56 +176,29 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
|
|||||||
prev_unbroken_timestamps.push_back(initial_timestamp);
|
prev_unbroken_timestamps.push_back(initial_timestamp);
|
||||||
for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
|
for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
|
||||||
{
|
{
|
||||||
// breakage recover has removed all previous good points
|
|
||||||
bool trace_split = prev_unbroken_timestamps.empty();
|
|
||||||
|
|
||||||
|
const bool gap_in_trace = [&, use_timestamps]() {
|
||||||
// use temporal information if available to determine a split
|
// use temporal information if available to determine a split
|
||||||
if (use_timestamps)
|
if (use_timestamps)
|
||||||
{
|
{
|
||||||
trace_split =
|
return trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] >
|
||||||
trace_split ||
|
max_broken_time;
|
||||||
(trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] >
|
|
||||||
max_broken_time);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trace_split =
|
return t - prev_unbroken_timestamps.back() > MAX_BROKEN_STATES;
|
||||||
trace_split || (t - prev_unbroken_timestamps.back() > MAX_BROKEN_STATES);
|
|
||||||
}
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
if (trace_split)
|
if (!gap_in_trace)
|
||||||
{
|
{
|
||||||
std::size_t split_index = t;
|
|
||||||
if (breakage_begin != map_matching::INVALID_STATE)
|
|
||||||
{
|
|
||||||
split_index = breakage_begin;
|
|
||||||
breakage_begin = map_matching::INVALID_STATE;
|
|
||||||
}
|
|
||||||
split_points.push_back(split_index);
|
|
||||||
|
|
||||||
// note: this preserves everything before split_index
|
|
||||||
model.Clear(split_index);
|
|
||||||
std::size_t new_start = model.initialize(split_index);
|
|
||||||
// no new start was found -> stop viterbi calculation
|
|
||||||
if (new_start == map_matching::INVALID_STATE)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev_unbroken_timestamps.clear();
|
|
||||||
prev_unbroken_timestamps.push_back(new_start);
|
|
||||||
// Important: We potentially go back here!
|
|
||||||
// However since t > new_start >= breakge_begin
|
|
||||||
// we can only reset trace_coordindates.size() times.
|
|
||||||
t = new_start + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT(!prev_unbroken_timestamps.empty());
|
BOOST_ASSERT(!prev_unbroken_timestamps.empty());
|
||||||
const std::size_t prev_unbroken_timestamp = prev_unbroken_timestamps.back();
|
const std::size_t prev_unbroken_timestamp = prev_unbroken_timestamps.back();
|
||||||
|
|
||||||
const auto &prev_viterbi = model.viterbi[prev_unbroken_timestamp];
|
const auto &prev_viterbi = model.viterbi[prev_unbroken_timestamp];
|
||||||
const auto &prev_pruned = model.pruned[prev_unbroken_timestamp];
|
const auto &prev_pruned = model.pruned[prev_unbroken_timestamp];
|
||||||
const auto &prev_unbroken_timestamps_list = candidates_list[prev_unbroken_timestamp];
|
const auto &prev_unbroken_timestamps_list =
|
||||||
|
candidates_list[prev_unbroken_timestamp];
|
||||||
const auto &prev_coordinate = trace_coordinates[prev_unbroken_timestamp];
|
const auto &prev_coordinate = trace_coordinates[prev_unbroken_timestamp];
|
||||||
|
|
||||||
auto ¤t_viterbi = model.viterbi[t];
|
auto ¤t_viterbi = model.viterbi[t];
|
||||||
@@ -238,7 +211,7 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
|
|||||||
const auto haversine_distance = util::coordinate_calculation::haversineDistance(
|
const auto haversine_distance = util::coordinate_calculation::haversineDistance(
|
||||||
prev_coordinate, current_coordinate);
|
prev_coordinate, current_coordinate);
|
||||||
// assumes minumum of 0.1 m/s
|
// assumes minumum of 0.1 m/s
|
||||||
const int duration_uppder_bound =
|
const int duration_upper_bound =
|
||||||
((haversine_distance + max_distance_delta) * 0.25) * 10;
|
((haversine_distance + max_distance_delta) * 0.25) * 10;
|
||||||
|
|
||||||
// compute d_t for this timestamp and the next one
|
// compute d_t for this timestamp and the next one
|
||||||
@@ -249,7 +222,8 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto s_prime : util::irange<std::size_t>(0UL, current_viterbi.size()))
|
for (const auto s_prime :
|
||||||
|
util::irange<std::size_t>(0UL, current_viterbi.size()))
|
||||||
{
|
{
|
||||||
const double emission_pr = emission_log_probabilities[t][s_prime];
|
const double emission_pr = emission_log_probabilities[t][s_prime];
|
||||||
double new_value = prev_viterbi[s] + emission_pr;
|
double new_value = prev_viterbi[s] + emission_pr;
|
||||||
@@ -273,7 +247,7 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
|
|||||||
reverse_core_heap,
|
reverse_core_heap,
|
||||||
prev_unbroken_timestamps_list[s].phantom_node,
|
prev_unbroken_timestamps_list[s].phantom_node,
|
||||||
current_timestamps_list[s_prime].phantom_node,
|
current_timestamps_list[s_prime].phantom_node,
|
||||||
duration_uppder_bound);
|
duration_upper_bound);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -325,6 +299,39 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// breakage recover has removed all previous good points
|
||||||
|
const bool trace_split = prev_unbroken_timestamps.empty();
|
||||||
|
|
||||||
|
if (trace_split || gap_in_trace)
|
||||||
|
{
|
||||||
|
std::size_t split_index = t;
|
||||||
|
if (breakage_begin != map_matching::INVALID_STATE)
|
||||||
|
{
|
||||||
|
split_index = breakage_begin;
|
||||||
|
breakage_begin = map_matching::INVALID_STATE;
|
||||||
|
}
|
||||||
|
split_points.push_back(split_index);
|
||||||
|
|
||||||
|
// note: this preserves everything before split_index
|
||||||
|
model.Clear(split_index);
|
||||||
|
std::size_t new_start = model.initialize(split_index);
|
||||||
|
// no new start was found -> stop viterbi calculation
|
||||||
|
if (new_start == map_matching::INVALID_STATE)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_unbroken_timestamps.clear();
|
||||||
|
prev_unbroken_timestamps.push_back(new_start);
|
||||||
|
// Important: We potentially go back here!
|
||||||
|
// However since t > new_start >= breakge_begin
|
||||||
|
// we can only reset trace_coordindates.size() times.
|
||||||
|
t = new_start;
|
||||||
|
// note: the head of the loop will call ++t, hence the next
|
||||||
|
// iteration will actually be on new_start+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!prev_unbroken_timestamps.empty())
|
if (!prev_unbroken_timestamps.empty())
|
||||||
{
|
{
|
||||||
split_points.push_back(prev_unbroken_timestamps.back() + 1);
|
split_points.push_back(prev_unbroken_timestamps.back() + 1);
|
||||||
|
|||||||
@@ -215,12 +215,13 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
|||||||
const PhantomNodes &phantom_node_pair,
|
const PhantomNodes &phantom_node_pair,
|
||||||
std::vector<PathData> &unpacked_path) const
|
std::vector<PathData> &unpacked_path) const
|
||||||
{
|
{
|
||||||
|
BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
|
||||||
|
|
||||||
const bool start_traversed_in_reverse =
|
const bool start_traversed_in_reverse =
|
||||||
(*packed_path_begin != phantom_node_pair.source_phantom.forward_segment_id.id);
|
(*packed_path_begin != phantom_node_pair.source_phantom.forward_segment_id.id);
|
||||||
const bool target_traversed_in_reverse =
|
const bool target_traversed_in_reverse =
|
||||||
(*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_segment_id.id);
|
(*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_segment_id.id);
|
||||||
|
|
||||||
BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
|
|
||||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
||||||
|
|
||||||
// We have to push the path in reverse order onto the stack because it's LIFO.
|
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <boost/interprocess/sync/named_condition.hpp>
|
#include <boost/interprocess/sync/named_condition.hpp>
|
||||||
#include <boost/interprocess/sync/named_mutex.hpp>
|
#include <boost/interprocess/sync/named_mutex.hpp>
|
||||||
|
#include <boost/interprocess/sync/named_sharable_mutex.hpp>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
@@ -13,25 +14,13 @@ struct SharedBarriers
|
|||||||
|
|
||||||
SharedBarriers()
|
SharedBarriers()
|
||||||
: pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
|
: pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
|
||||||
update_mutex(boost::interprocess::open_or_create, "update"),
|
query_mutex(boost::interprocess::open_or_create, "query")
|
||||||
query_mutex(boost::interprocess::open_or_create, "query"),
|
|
||||||
no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
|
|
||||||
update_ongoing(false), number_of_queries(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutex to protect access to the boolean variable
|
// Mutex to protect access to the boolean variable
|
||||||
boost::interprocess::named_mutex pending_update_mutex;
|
boost::interprocess::named_mutex pending_update_mutex;
|
||||||
boost::interprocess::named_mutex update_mutex;
|
boost::interprocess::named_sharable_mutex query_mutex;
|
||||||
boost::interprocess::named_mutex query_mutex;
|
|
||||||
|
|
||||||
// Condition that no update is running
|
|
||||||
boost::interprocess::named_condition no_running_queries_condition;
|
|
||||||
|
|
||||||
// Is there an ongoing update?
|
|
||||||
bool update_ongoing;
|
|
||||||
// Is there any query?
|
|
||||||
int number_of_queries;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-57
@@ -1,5 +1,5 @@
|
|||||||
#include "engine/engine.hpp"
|
|
||||||
#include "engine/api/route_parameters.hpp"
|
#include "engine/api/route_parameters.hpp"
|
||||||
|
#include "engine/engine.hpp"
|
||||||
#include "engine/engine_config.hpp"
|
#include "engine/engine_config.hpp"
|
||||||
#include "engine/status.hpp"
|
#include "engine/status.hpp"
|
||||||
|
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/interprocess/sync/named_condition.hpp>
|
#include <boost/interprocess/sync/named_condition.hpp>
|
||||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||||
|
#include <boost/interprocess/sync/sharable_lock.hpp>
|
||||||
#include <boost/thread/lock_types.hpp>
|
#include <boost/thread/lock_types.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -28,64 +29,13 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace engine
|
|
||||||
{
|
|
||||||
struct Engine::EngineLock
|
|
||||||
{
|
|
||||||
// will only be initialized if shared memory is used
|
|
||||||
storage::SharedBarriers barrier;
|
|
||||||
// decrease number of concurrent queries
|
|
||||||
void DecreaseQueryCount();
|
|
||||||
// increase number of concurrent queries
|
|
||||||
void IncreaseQueryCount();
|
|
||||||
};
|
|
||||||
|
|
||||||
// decrease number of concurrent queries
|
|
||||||
void Engine::EngineLock::DecreaseQueryCount()
|
|
||||||
{
|
|
||||||
// lock query
|
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
|
||||||
barrier.query_mutex);
|
|
||||||
|
|
||||||
// decrement query count
|
|
||||||
--(barrier.number_of_queries);
|
|
||||||
BOOST_ASSERT_MSG(0 <= barrier.number_of_queries, "invalid number of queries");
|
|
||||||
|
|
||||||
// notify all processes that were waiting for this condition
|
|
||||||
if (0 == barrier.number_of_queries)
|
|
||||||
{
|
|
||||||
barrier.no_running_queries_condition.notify_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// increase number of concurrent queries
|
|
||||||
void Engine::EngineLock::IncreaseQueryCount()
|
|
||||||
{
|
|
||||||
// lock update pending
|
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
|
|
||||||
barrier.pending_update_mutex);
|
|
||||||
|
|
||||||
// lock query
|
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
|
||||||
barrier.query_mutex);
|
|
||||||
|
|
||||||
// unlock update pending
|
|
||||||
pending_lock.unlock();
|
|
||||||
|
|
||||||
// increment query count
|
|
||||||
++(barrier.number_of_queries);
|
|
||||||
}
|
|
||||||
} // ns engine
|
|
||||||
} // ns osrm
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Abstracted away the query locking into a template function
|
// Abstracted away the query locking into a template function
|
||||||
// Works the same for every plugin.
|
// Works the same for every plugin.
|
||||||
template <typename ParameterT, typename PluginT, typename ResultT>
|
template <typename ParameterT, typename PluginT, typename ResultT>
|
||||||
osrm::engine::Status RunQuery(const std::unique_ptr<osrm::engine::Engine::EngineLock> &lock,
|
osrm::engine::Status
|
||||||
|
RunQuery(const std::unique_ptr<osrm::storage::SharedBarriers> &lock,
|
||||||
osrm::engine::datafacade::BaseDataFacade &facade,
|
osrm::engine::datafacade::BaseDataFacade &facade,
|
||||||
const ParameterT ¶meters,
|
const ParameterT ¶meters,
|
||||||
PluginT &plugin,
|
PluginT &plugin,
|
||||||
@@ -97,7 +47,10 @@ osrm::engine::Status RunQuery(const std::unique_ptr<osrm::engine::Engine::Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(lock);
|
BOOST_ASSERT(lock);
|
||||||
lock->IncreaseQueryCount();
|
// this locks aquires shared ownership of the query mutex: other requets are allowed
|
||||||
|
// to run, but data updates need to wait for all queries to finish until they can aquire an exclusive lock
|
||||||
|
boost::interprocess::sharable_lock<boost::interprocess::named_sharable_mutex> query_lock(
|
||||||
|
lock->query_mutex);
|
||||||
|
|
||||||
auto &shared_facade = static_cast<osrm::engine::datafacade::SharedDataFacade &>(facade);
|
auto &shared_facade = static_cast<osrm::engine::datafacade::SharedDataFacade &>(facade);
|
||||||
shared_facade.CheckAndReloadFacade();
|
shared_facade.CheckAndReloadFacade();
|
||||||
@@ -107,7 +60,6 @@ osrm::engine::Status RunQuery(const std::unique_ptr<osrm::engine::Engine::Engine
|
|||||||
|
|
||||||
osrm::engine::Status status = plugin.HandleRequest(parameters, result);
|
osrm::engine::Status status = plugin.HandleRequest(parameters, result);
|
||||||
|
|
||||||
lock->DecreaseQueryCount();
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,10 +77,11 @@ namespace engine
|
|||||||
{
|
{
|
||||||
|
|
||||||
Engine::Engine(const EngineConfig &config)
|
Engine::Engine(const EngineConfig &config)
|
||||||
|
: lock(config.use_shared_memory ? std::make_unique<storage::SharedBarriers>()
|
||||||
|
: std::unique_ptr<storage::SharedBarriers>())
|
||||||
{
|
{
|
||||||
if (config.use_shared_memory)
|
if (config.use_shared_memory)
|
||||||
{
|
{
|
||||||
lock = util::make_unique<EngineLock>();
|
|
||||||
query_data_facade = util::make_unique<datafacade::SharedDataFacade>();
|
query_data_facade = util::make_unique<datafacade::SharedDataFacade>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -43,37 +43,11 @@ unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometri
|
|||||||
return util::viewport::getFittedZoom(south_west, north_east);
|
return util::viewport::getFittedZoom(south_west, north_east);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<util::Coordinate> simplifyGeometry(const std::vector<LegGeometry> &leg_geometries,
|
|
||||||
const unsigned zoom_level)
|
|
||||||
{
|
|
||||||
std::vector<util::Coordinate> overview_geometry;
|
|
||||||
auto leg_index = 0UL;
|
|
||||||
for (const auto &geometry : leg_geometries)
|
|
||||||
{
|
|
||||||
auto simplified_geometry =
|
|
||||||
douglasPeucker(geometry.locations.begin(), geometry.locations.end(), zoom_level);
|
|
||||||
// not the last leg
|
|
||||||
if (leg_index < leg_geometries.size() - 1)
|
|
||||||
{
|
|
||||||
simplified_geometry.pop_back();
|
|
||||||
}
|
|
||||||
overview_geometry.insert(
|
|
||||||
overview_geometry.end(), simplified_geometry.begin(), simplified_geometry.end());
|
|
||||||
}
|
|
||||||
return overview_geometry;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries,
|
std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries,
|
||||||
const bool use_simplification)
|
const bool use_simplification)
|
||||||
{
|
{
|
||||||
if (use_simplification)
|
|
||||||
{
|
|
||||||
const auto zoom_level = std::min(18u, calculateOverviewZoomLevel(leg_geometries));
|
|
||||||
return simplifyGeometry(leg_geometries, zoom_level);
|
|
||||||
}
|
|
||||||
BOOST_ASSERT(!use_simplification);
|
|
||||||
|
|
||||||
auto overview_size =
|
auto overview_size =
|
||||||
std::accumulate(leg_geometries.begin(),
|
std::accumulate(leg_geometries.begin(),
|
||||||
leg_geometries.end(),
|
leg_geometries.end(),
|
||||||
@@ -85,16 +59,34 @@ std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &l
|
|||||||
std::vector<util::Coordinate> overview_geometry;
|
std::vector<util::Coordinate> overview_geometry;
|
||||||
overview_geometry.reserve(overview_size);
|
overview_geometry.reserve(overview_size);
|
||||||
|
|
||||||
|
using GeometryIter = decltype(overview_geometry)::const_iterator;
|
||||||
|
|
||||||
auto leg_reverse_index = leg_geometries.size();
|
auto leg_reverse_index = leg_geometries.size();
|
||||||
for (const auto &geometry : leg_geometries)
|
const auto insert_without_overlap = [&leg_reverse_index, &overview_geometry](GeometryIter begin, GeometryIter end) {
|
||||||
{
|
// not the last leg
|
||||||
auto begin = geometry.locations.begin();
|
if (leg_reverse_index > 1)
|
||||||
auto end = geometry.locations.end();
|
|
||||||
if (--leg_reverse_index > 0)
|
|
||||||
{
|
{
|
||||||
|
--leg_reverse_index;
|
||||||
end = std::prev(end);
|
end = std::prev(end);
|
||||||
}
|
}
|
||||||
overview_geometry.insert(overview_geometry.end(), begin, end);
|
overview_geometry.insert(overview_geometry.end(), begin, end);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (use_simplification)
|
||||||
|
{
|
||||||
|
const auto zoom_level = std::min(18u, calculateOverviewZoomLevel(leg_geometries));
|
||||||
|
for (const auto &geometry : leg_geometries)
|
||||||
|
{
|
||||||
|
const auto simplified = douglasPeucker(geometry.locations.begin(), geometry.locations.end(), zoom_level);
|
||||||
|
insert_without_overlap(simplified.begin(), simplified.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto &geometry : leg_geometries)
|
||||||
|
{
|
||||||
|
insert_without_overlap(geometry.locations.begin(), geometry.locations.end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return overview_geometry;
|
return overview_geometry;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "engine/guidance/post_processing.hpp"
|
|
||||||
#include "extractor/guidance/turn_instruction.hpp"
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
|
#include "engine/guidance/post_processing.hpp"
|
||||||
|
|
||||||
#include "engine/guidance/assemble_steps.hpp"
|
#include "engine/guidance/assemble_steps.hpp"
|
||||||
#include "engine/guidance/lane_processing.hpp"
|
#include "engine/guidance/lane_processing.hpp"
|
||||||
@@ -260,7 +260,8 @@ void closeOffRoundabout(const bool on_roundabout,
|
|||||||
BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
|
BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
|
||||||
steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout ||
|
steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout ||
|
||||||
steps[1].maneuver.instruction.type == TurnType::Suppressed ||
|
steps[1].maneuver.instruction.type == TurnType::Suppressed ||
|
||||||
steps[1].maneuver.instruction.type == TurnType::NoTurn);
|
steps[1].maneuver.instruction.type == TurnType::NoTurn ||
|
||||||
|
steps[1].maneuver.instruction.type == TurnType::UseLane);
|
||||||
steps[0].geometry_end = 1;
|
steps[0].geometry_end = 1;
|
||||||
steps[1].geometry_begin = 0;
|
steps[1].geometry_begin = 0;
|
||||||
steps[1] = forwardInto(steps[1], steps[0]);
|
steps[1] = forwardInto(steps[1], steps[0]);
|
||||||
@@ -838,6 +839,11 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
|||||||
::osrm::util::guidance::getTurnDirection(angle);
|
::osrm::util::guidance::getTurnDirection(angle);
|
||||||
invalidateStep(steps[step_index]);
|
invalidateStep(steps[step_index]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the sliproad turn is incompatible. So we handle it as a turn
|
||||||
|
steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Due to empty segments, we can get name-changes from A->A
|
// Due to empty segments, we can get name-changes from A->A
|
||||||
|
|||||||
@@ -510,17 +510,45 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
|||||||
!best_data.road_classification.IsRampClass()))
|
!best_data.road_classification.IsRampClass()))
|
||||||
{
|
{
|
||||||
// Find left/right deviation
|
// Find left/right deviation
|
||||||
const double left_deviation = angularDeviation(
|
// skipping over service roads
|
||||||
intersection[(best + 1) % intersection.size()].turn.angle, STRAIGHT_ANGLE);
|
const std::size_t left_index = [&]() {
|
||||||
|
const auto index_candidate = (best + 1) % intersection.size();
|
||||||
|
if (index_candidate == 0)
|
||||||
|
return index_candidate;
|
||||||
|
const auto &candidate_data =
|
||||||
|
node_based_graph.GetEdgeData(intersection[index_candidate].turn.eid);
|
||||||
|
if (obvious_by_road_class(in_data.road_classification,
|
||||||
|
best_data.road_classification,
|
||||||
|
candidate_data.road_classification))
|
||||||
|
return (index_candidate + 1) % intersection.size();
|
||||||
|
else
|
||||||
|
return index_candidate;
|
||||||
|
|
||||||
|
}();
|
||||||
|
const auto right_index = [&]() {
|
||||||
|
BOOST_ASSERT(best > 0);
|
||||||
|
const auto index_candidate = best - 1;
|
||||||
|
if (index_candidate == 0)
|
||||||
|
return index_candidate;
|
||||||
|
const auto candidate_data =
|
||||||
|
node_based_graph.GetEdgeData(intersection[index_candidate].turn.eid);
|
||||||
|
if (obvious_by_road_class(in_data.road_classification,
|
||||||
|
best_data.road_classification,
|
||||||
|
candidate_data.road_classification))
|
||||||
|
return index_candidate - 1;
|
||||||
|
else
|
||||||
|
return index_candidate;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const double left_deviation =
|
||||||
|
angularDeviation(intersection[left_index].turn.angle, STRAIGHT_ANGLE);
|
||||||
const double right_deviation =
|
const double right_deviation =
|
||||||
angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE);
|
angularDeviation(intersection[right_index].turn.angle, STRAIGHT_ANGLE);
|
||||||
|
|
||||||
if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
||||||
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
|
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
|
||||||
return best;
|
return best;
|
||||||
|
|
||||||
const auto left_index = (best + 1) % intersection.size();
|
|
||||||
const auto right_index = best - 1;
|
|
||||||
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].turn.eid);
|
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].turn.eid);
|
||||||
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].turn.eid);
|
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].turn.eid);
|
||||||
|
|
||||||
|
|||||||
+7
-12
@@ -42,11 +42,6 @@ namespace osrm
|
|||||||
namespace storage
|
namespace storage
|
||||||
{
|
{
|
||||||
|
|
||||||
using RTreeLeaf = engine::datafacade::BaseDataFacade::RTreeLeaf;
|
|
||||||
using RTreeNode =
|
|
||||||
util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>::TreeNode;
|
|
||||||
using QueryGraph = util::StaticGraph<contractor::QueryEdge::EdgeData>;
|
|
||||||
|
|
||||||
// delete a shared memory region. report warning if it could not be deleted
|
// delete a shared memory region. report warning if it could not be deleted
|
||||||
void deleteRegion(const SharedDataType region)
|
void deleteRegion(const SharedDataType region)
|
||||||
{
|
{
|
||||||
@@ -76,6 +71,11 @@ void deleteRegion(const SharedDataType region)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using RTreeLeaf = engine::datafacade::BaseDataFacade::RTreeLeaf;
|
||||||
|
using RTreeNode =
|
||||||
|
util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>::TreeNode;
|
||||||
|
using QueryGraph = util::StaticGraph<contractor::QueryEdge::EdgeData>;
|
||||||
|
|
||||||
Storage::Storage(StorageConfig config_) : config(std::move(config_)) {}
|
Storage::Storage(StorageConfig config_) : config(std::move(config_)) {}
|
||||||
|
|
||||||
int Storage::Run()
|
int Storage::Run()
|
||||||
@@ -738,20 +738,15 @@ int Storage::Run()
|
|||||||
SharedDataTimestamp *data_timestamp_ptr =
|
SharedDataTimestamp *data_timestamp_ptr =
|
||||||
static_cast<SharedDataTimestamp *>(data_type_memory->Ptr());
|
static_cast<SharedDataTimestamp *>(data_type_memory->Ptr());
|
||||||
|
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
|
||||||
barrier.query_mutex);
|
|
||||||
|
|
||||||
// notify all processes that were waiting for this condition
|
|
||||||
if (0 < barrier.number_of_queries)
|
|
||||||
{
|
{
|
||||||
barrier.no_running_queries_condition.wait(query_lock);
|
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> query_lock(barrier.query_mutex);
|
||||||
}
|
|
||||||
|
|
||||||
data_timestamp_ptr->layout = layout_region;
|
data_timestamp_ptr->layout = layout_region;
|
||||||
data_timestamp_ptr->data = data_region;
|
data_timestamp_ptr->data = data_region;
|
||||||
data_timestamp_ptr->timestamp += 1;
|
data_timestamp_ptr->timestamp += 1;
|
||||||
deleteRegion(previous_data_region);
|
deleteRegion(previous_data_region);
|
||||||
deleteRegion(previous_layout_region);
|
deleteRegion(previous_layout_region);
|
||||||
|
}
|
||||||
util::SimpleLogger().Write() << "all data loaded";
|
util::SimpleLogger().Write() << "all data loaded";
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
@@ -10,6 +10,5 @@ int main()
|
|||||||
osrm::storage::SharedBarriers barrier;
|
osrm::storage::SharedBarriers barrier;
|
||||||
barrier.pending_update_mutex.unlock();
|
barrier.pending_update_mutex.unlock();
|
||||||
barrier.query_mutex.unlock();
|
barrier.query_mutex.unlock();
|
||||||
barrier.update_mutex.unlock();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user