Compare commits

...

4 Commits

Author SHA1 Message Date
Kajari Ghosh 17e19663ba rc in travis, changelog and package.json
update changelog to include profile changes

bump version to rc2
2018-09-10 11:56:29 -04:00
Kajari Ghosh 5597415f28 Revert "Improve speed of Map Matching" (#5196)
* Revert "Update changelog"

This reverts commit 9b779c704f.

* Revert "Fix formating"

This reverts commit 5bd7d04fe3.

* Revert "Fix bug in computation of distance offset for phantom node"

This reverts commit 0f78f7b2cc.

* Revert "Adjust text cases for flightly different matching due to rounding"

This reverts commit 8473be69d2.

* Revert "Round network distance to deci-meter to retain previous behavior"

This reverts commit c0124f7d77.

* Revert "Preserve heap state in map matching"

This reverts commit b630b4e32a.

* Revert "Use distance functions from many to many"

This reverts commit 89fabc1b9c.

* Revert "Use FCC algorithm for map matching distance calculation"

This reverts commit a649a8a5cf.
2018-09-06 12:05:28 -04:00
Jie 5476f6ab27 Fix GDB not work for osrm-routed on Linux (#5157)
As I mentioned in the issue #5156, I met below issue on my Win10+WSL(Ubuntu) env:
The remote debugger (VSCode on Win10, gdb on Ubuntu 18.04 LTS) works well from the beginning of the main() function. But when I step over the code pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); (src/tools/routed.cpp(289)), below breakpoints can not work and displayed unverified breakpoint.

Then I found that gdb breakpoint need at least SIGTRAP, SIGSTOP to work (Please refer to [how debugger works](http://www.alexonlinux.com/how-debugger-works) for more details), but all signals are blocked in the source code until server initialized done.

In my understanding, block all signals DO NOT make sense for this osrm-routed process. Only several signals (SIGINT, SIGQUIT, SIGTERM) are expected to wait. So I made the change and it works well for me then.
2018-09-05 16:23:48 -07:00
Daniel Patterson 0971f06193 Add option to node bindings to return result as a pre-generated JSON string (this avoids a lot of overhead, and moves JSON string rendering out of the main event loop). 2018-09-05 15:09:13 -07:00
22 changed files with 519 additions and 324 deletions
+1
View File
@@ -13,6 +13,7 @@ notifications:
branches: branches:
only: only:
- master - master
- "5.19"
# enable building tags # enable building tags
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/ - /^v\d+\.\d+(\.\d+)?(-\S*)?$/
+8 -3
View File
@@ -1,11 +1,16 @@
# UNRELEASED # 5.19.0
- Changes from 5.18.0: - Changes from 5.18.0:
- Optimizations: - Optimizations:
- CHANGED: Map matching is now almost twice as fast. [#5060](https://github.com/Project-OSRM/osrm-backend/pull/5060)
- CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188) - CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188)
- ADDED: Node bindings can return pre-rendered JSON buffer. [#5189](https://github.com/Project-OSRM/osrm-backend/pull/5189)
- Profiles:
- CHANGED: Bicycle profile now blacklists barriers instead of whitelisting them [#5076
](https://github.com/Project-OSRM/osrm-backend/pull/5076/)
- CHANGED: Foot profile now blacklists barriers instead of whitelisting them [#5077
](https://github.com/Project-OSRM/osrm-backend/pull/5077/)
- CHANGED: Support maxlength and maxweight in car profile [#5101](https://github.com/Project-OSRM/osrm-backend/pull/5101]
- Bugfixes: - Bugfixes:
- FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114) - FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114)
- FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106)
- Misc: - Misc:
- CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185) - CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185)
+23
View File
@@ -297,6 +297,29 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
2) `waypoint_index`: index of the point in the trip. 2) `waypoint_index`: index of the point in the trip.
**`trips`**: an array of [`Route`](#route) objects that assemble the trace. **`trips`**: an array of [`Route`](#route) objects that assemble the trace.
## Plugin behaviour
All plugins support a second additional object that is available to configure some NodeJS specific behaviours.
- `plugin_config` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query.
- `plugin_config.format` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The format of the result object to various API calls. Valid options are `object` (default), which returns a standard Javascript object, as described above, and `json_buffer`, which will return a NodeJS **[Buffer](https://nodejs.org/api/buffer.html)** object, containing a JSON string. The latter has the advantage that it can be immediately serialized to disk/sent over the network, and the generation of the string is performed outside the main NodeJS event loop. This option is ignored by the `tile` plugin.
**Examples**
```javascript
var osrm = new OSRM('network.osrm');
var options = {
coordinates: [
[13.36761474609375, 52.51663871100423],
[13.374481201171875, 52.506191342034576]
]
};
osrm.route(options, { format: "json_buffer" }, function(err, response) {
if (err) throw err;
console.log(response.toString("utf-8"));
});
```
## Responses ## Responses
Responses Responses
+1 -1
View File
@@ -792,4 +792,4 @@ Feature: Basic Map Matching
When I match I should get When I match I should get
| trace | geometry | a:distance | a:duration | a:weight | duration | | trace | geometry | a:distance | a:duration | a:weight | duration |
| 2345 | 1.00018,1,1.000315,1 | 15.013264 | 1.5 | 1.5 | 1.5 | | 2345 | 1.00018,1,1.000315,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
| 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 | | 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
+14 -13
View File
@@ -449,7 +449,6 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id); const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id);
const auto forward_geometry = datafacade.GetUncompressedForwardGeometry(geometry_id); const auto forward_geometry = datafacade.GetUncompressedForwardGeometry(geometry_id);
const auto reverse_geometry = datafacade.GetUncompressedReverseGeometry(geometry_id);
const auto forward_weight_offset = const auto forward_weight_offset =
std::accumulate(forward_weights.begin(), std::accumulate(forward_weights.begin(),
@@ -480,19 +479,19 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position)), datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position)),
point_on_segment); point_on_segment);
const auto rev_segment_position = reverse_weights.size() - data.fwd_segment_position - 1; const auto reverse_weight_offset =
std::accumulate(reverse_weights.begin(),
const auto reverse_weight_offset = std::accumulate( reverse_weights.end() - data.fwd_segment_position - 1,
reverse_weights.begin(), reverse_weights.begin() + rev_segment_position, EdgeWeight{0}); EdgeWeight{0});
const auto reverse_duration_offset = const auto reverse_duration_offset =
std::accumulate(reverse_durations.begin(), std::accumulate(reverse_durations.begin(),
reverse_durations.begin() + rev_segment_position, reverse_durations.end() - data.fwd_segment_position - 1,
EdgeDuration{0}); EdgeDuration{0});
EdgeDistance reverse_distance_offset = 0; EdgeDistance reverse_distance_offset = 0;
for (auto current = reverse_geometry.begin(); for (auto current = forward_geometry.begin();
current < reverse_geometry.begin() + rev_segment_position; current < forward_geometry.end() - data.fwd_segment_position - 2;
++current) ++current)
{ {
reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance( reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance(
@@ -500,11 +499,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
datafacade.GetCoordinateOfNode(*std::next(current))); datafacade.GetCoordinateOfNode(*std::next(current)));
} }
EdgeWeight reverse_weight = reverse_weights[rev_segment_position]; EdgeWeight reverse_weight =
EdgeDuration reverse_duration = reverse_durations[rev_segment_position]; reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1];
EdgeDuration reverse_duration =
reverse_durations[reverse_durations.size() - data.fwd_segment_position - 1];
EdgeDistance reverse_distance = util::coordinate_calculation::fccApproximateDistance( EdgeDistance reverse_distance = util::coordinate_calculation::fccApproximateDistance(
point_on_segment, point_on_segment,
datafacade.GetCoordinateOfNode(reverse_geometry(rev_segment_position))); datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1)));
ratio = std::min(1.0, std::max(0.0, ratio)); ratio = std::min(1.0, std::max(0.0, ratio));
if (data.forward_segment_id.id != SPECIAL_SEGMENTID) if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
@@ -692,7 +693,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const CoordinateList &coordinates; const CoordinateList &coordinates;
DataFacadeT &datafacade; DataFacadeT &datafacade;
}; };
} // namespace engine }
} // namespace osrm }
#endif #endif
@@ -44,19 +44,50 @@ bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &ta
bool needsLoopForward(const PhantomNodes &phantoms); bool needsLoopForward(const PhantomNodes &phantoms);
bool needsLoopBackwards(const PhantomNodes &phantoms); bool needsLoopBackwards(const PhantomNodes &phantoms);
namespace detail template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
{ {
template <typename Algorithm> const auto &source = nodes.source_phantom;
void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap, if (source.IsValidForwardSource())
const PhantomNode &phantom_node) {
forward_heap.Insert(source.forward_segment_id.id,
-source.GetForwardWeightPlusOffset(),
source.forward_segment_id.id);
}
if (source.IsValidReverseSource())
{
forward_heap.Insert(source.reverse_segment_id.id,
-source.GetReverseWeightPlusOffset(),
source.reverse_segment_id.id);
}
const auto &target = nodes.target_phantom;
if (target.IsValidForwardTarget())
{
reverse_heap.Insert(target.forward_segment_id.id,
target.GetForwardWeightPlusOffset(),
target.forward_segment_id.id);
}
if (target.IsValidReverseTarget())
{
reverse_heap.Insert(target.reverse_segment_id.id,
target.GetReverseWeightPlusOffset(),
target.reverse_segment_id.id);
}
}
template <typename ManyToManyQueryHeap>
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
{ {
if (phantom_node.IsValidForwardTarget()) if (phantom_node.IsValidForwardSource())
{ {
heap.Insert(phantom_node.forward_segment_id.id, heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(), -phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); {phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()});
} }
if (phantom_node.IsValidReverseTarget()) if (phantom_node.IsValidReverseSource())
{ {
heap.Insert(phantom_node.reverse_segment_id.id, heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(), -phantom_node.GetReverseWeightPlusOffset(),
@@ -64,9 +95,8 @@ void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHea
} }
} }
template <typename Algorithm> template <typename ManyToManyQueryHeap>
void insertTargetInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap, void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
const PhantomNode &phantom_node)
{ {
if (phantom_node.IsValidForwardTarget()) if (phantom_node.IsValidForwardTarget())
{ {
@@ -82,109 +112,6 @@ void insertTargetInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHea
} }
} }
template <typename Algorithm>
void insertSourceInHeap(typename SearchEngineData<Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardSource())
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
phantom_node.forward_segment_id.id);
}
if (phantom_node.IsValidReverseSource())
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
phantom_node.reverse_segment_id.id);
}
}
template <typename Algorithm>
void insertTargetInHeap(typename SearchEngineData<Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardTarget())
{
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.forward_segment_id.id);
}
if (phantom_node.IsValidReverseTarget())
{
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.reverse_segment_id.id);
}
}
} // namespace detail
inline void insertTargetInHeap(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertTargetInHeap<mld::Algorithm>(heap, phantom_node);
}
inline void insertTargetInHeap(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertTargetInHeap<ch::Algorithm>(heap, phantom_node);
}
inline void insertTargetInHeap(typename SearchEngineData<mld::Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertTargetInHeap<mld::Algorithm>(heap, phantom_node);
}
inline void insertTargetInHeap(typename SearchEngineData<ch::Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertTargetInHeap<ch::Algorithm>(heap, phantom_node);
}
inline void insertSourceInHeap(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertSourceInHeap<mld::Algorithm>(heap, phantom_node);
}
inline void insertSourceInHeap(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertSourceInHeap<ch::Algorithm>(heap, phantom_node);
}
inline void insertSourceInHeap(typename SearchEngineData<mld::Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertSourceInHeap<mld::Algorithm>(heap, phantom_node);
}
inline void insertSourceInHeap(typename SearchEngineData<ch::Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertSourceInHeap<ch::Algorithm>(heap, phantom_node);
}
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
{
insertSourceInHeap(forward_heap, nodes.source_phantom);
insertTargetInHeap(reverse_heap, nodes.target_phantom);
}
template <typename Algorithm>
void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardSource())
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()});
}
if (phantom_node.IsValidReverseSource())
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()});
}
}
template <typename FacadeT> template <typename FacadeT>
void annotatePath(const FacadeT &facade, void annotatePath(const FacadeT &facade,
const PhantomNodes &phantom_node_pair, const PhantomNodes &phantom_node_pair,
@@ -394,10 +321,58 @@ void annotatePath(const FacadeT &facade,
} }
} }
EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector<NodeID> &path, template <typename Algorithm>
const PhantomNode &source_phantom, double getPathDistance(const DataFacade<Algorithm> &facade,
const PhantomNode &target_phantom, const std::vector<PathData> unpacked_path,
const EdgeDistance distance); const PhantomNode &source_phantom,
const PhantomNode &target_phantom)
{
using util::coordinate_calculation::detail::DEGREE_TO_RAD;
using util::coordinate_calculation::detail::EARTH_RADIUS;
double distance = 0;
double prev_lat =
static_cast<double>(util::toFloating(source_phantom.location.lat)) * DEGREE_TO_RAD;
double prev_lon =
static_cast<double>(util::toFloating(source_phantom.location.lon)) * DEGREE_TO_RAD;
double prev_cos = std::cos(prev_lat);
for (const auto &p : unpacked_path)
{
const auto current_coordinate = facade.GetCoordinateOfNode(p.turn_via_node);
const double current_lat =
static_cast<double>(util::toFloating(current_coordinate.lat)) * DEGREE_TO_RAD;
const double current_lon =
static_cast<double>(util::toFloating(current_coordinate.lon)) * DEGREE_TO_RAD;
const double current_cos = std::cos(current_lat);
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
distance += EARTH_RADIUS * charv;
prev_lat = current_lat;
prev_lon = current_lon;
prev_cos = current_cos;
}
const double current_lat =
static_cast<double>(util::toFloating(target_phantom.location.lat)) * DEGREE_TO_RAD;
const double current_lon =
static_cast<double>(util::toFloating(target_phantom.location.lon)) * DEGREE_TO_RAD;
const double current_cos = std::cos(current_lat);
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
distance += EARTH_RADIUS * charv;
return distance;
}
template <typename AlgorithmT> template <typename AlgorithmT>
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade, InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
@@ -97,6 +97,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
const std::vector<std::size_t> &phantom_indices) const std::vector<std::size_t> &phantom_indices)
{ {
auto min_level = [&partition, node](const PhantomNode &phantom_node) { auto min_level = [&partition, node](const PhantomNode &phantom_node) {
const auto &forward_segment = phantom_node.forward_segment_id; const auto &forward_segment = phantom_node.forward_segment_id;
const auto forward_level = const auto forward_level =
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id) forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
@@ -119,7 +120,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
} }
return result; return result;
} }
} // namespace }
// Heaps only record for each node its predecessor ("parent") on the shortest path. // Heaps only record for each node its predecessor ("parent") on the shortest path.
// For re-constructing the actual path we need to trace back all parent "pointers". // For re-constructing the actual path we need to trace back all parent "pointers".
@@ -390,27 +391,21 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
EdgeWeight weight_upper_bound, EdgeWeight weight_upper_bound,
Args... args) Args... args)
{ {
if (forward_heap.Empty() && reverse_heap.Empty()) if (forward_heap.Empty() || reverse_heap.Empty())
{ {
return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector<NodeID>(), std::vector<EdgeID>()); return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector<NodeID>(), std::vector<EdgeID>());
} }
const auto &partition = facade.GetMultiLevelPartition(); const auto &partition = facade.GetMultiLevelPartition();
BOOST_ASSERT(forward_heap.Empty() || forward_heap.MinKey() < INVALID_EDGE_WEIGHT); BOOST_ASSERT(!forward_heap.Empty() && forward_heap.MinKey() < INVALID_EDGE_WEIGHT);
BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() < INVALID_EDGE_WEIGHT); BOOST_ASSERT(!reverse_heap.Empty() && reverse_heap.MinKey() < INVALID_EDGE_WEIGHT);
// run two-Target Dijkstra routing step. // run two-Target Dijkstra routing step.
NodeID middle = SPECIAL_NODEID; NodeID middle = SPECIAL_NODEID;
EdgeWeight weight = weight_upper_bound; EdgeWeight weight = weight_upper_bound;
EdgeWeight forward_heap_min = forward_heap.MinKey();
EdgeWeight forward_heap_min = 0; EdgeWeight reverse_heap_min = reverse_heap.MinKey();
if (!forward_heap.Empty())
forward_heap_min = forward_heap.MinKey();
EdgeWeight reverse_heap_min = 0;
if (!reverse_heap.Empty())
reverse_heap_min = reverse_heap.MinKey();
while (forward_heap.Size() + reverse_heap.Size() > 0 && while (forward_heap.Size() + reverse_heap.Size() > 0 &&
forward_heap_min + reverse_heap_min < weight) forward_heap_min + reverse_heap_min < weight)
{ {
@@ -662,7 +657,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
const PhantomNode &target_phantom, const PhantomNode &target_phantom,
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT) EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
{ {
forward_heap.Clear();
reverse_heap.Clear();
const PhantomNodes phantom_nodes{source_phantom, target_phantom}; const PhantomNodes phantom_nodes{source_phantom, target_phantom};
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
EdgeWeight weight = INVALID_EDGE_WEIGHT; EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> unpacked_nodes; std::vector<NodeID> unpacked_nodes;
@@ -681,22 +680,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
return std::numeric_limits<double>::max(); return std::numeric_limits<double>::max();
} }
EdgeDistance distance = 0; std::vector<PathData> unpacked_path;
if (!unpacked_nodes.empty()) annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
{
distance = std::accumulate(unpacked_nodes.begin(),
std::prev(unpacked_nodes.end()),
EdgeDistance{0},
[&](const EdgeDistance distance, const auto node_id) {
return distance + computeEdgeDistance(facade, node_id);
});
}
distance = adjustPathDistanceToPhantomNodes( return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
unpacked_nodes, phantom_nodes.source_phantom, phantom_nodes.target_phantom, distance);
return distance;
} }
} // namespace mld } // namespace mld
+68 -5
View File
@@ -2,6 +2,7 @@
#define OSRM_BINDINGS_NODE_SUPPORT_HPP #define OSRM_BINDINGS_NODE_SUPPORT_HPP
#include "nodejs/json_v8_renderer.hpp" #include "nodejs/json_v8_renderer.hpp"
#include "util/json_renderer.hpp"
#include "osrm/approach.hpp" #include "osrm/approach.hpp"
#include "osrm/bearing.hpp" #include "osrm/bearing.hpp"
@@ -24,6 +25,7 @@
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
#include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -42,6 +44,13 @@ using match_parameters_ptr = std::unique_ptr<osrm::MatchParameters>;
using nearest_parameters_ptr = std::unique_ptr<osrm::NearestParameters>; using nearest_parameters_ptr = std::unique_ptr<osrm::NearestParameters>;
using table_parameters_ptr = std::unique_ptr<osrm::TableParameters>; using table_parameters_ptr = std::unique_ptr<osrm::TableParameters>;
struct PluginParameters
{
bool renderJSONToBuffer = false;
};
using ObjectOrString = typename mapbox::util::variant<osrm::json::Object, std::string>;
template <typename ResultT> inline v8::Local<v8::Value> render(const ResultT &result); template <typename ResultT> inline v8::Local<v8::Value> render(const ResultT &result);
template <> v8::Local<v8::Value> inline render(const std::string &result) template <> v8::Local<v8::Value> inline render(const std::string &result)
@@ -49,11 +58,21 @@ template <> v8::Local<v8::Value> inline render(const std::string &result)
return Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked(); return Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked();
} }
template <> v8::Local<v8::Value> inline render(const osrm::json::Object &result) template <> v8::Local<v8::Value> inline render(const ObjectOrString &result)
{ {
v8::Local<v8::Value> value; if (result.is<osrm::json::Object>())
renderToV8(value, result); {
return value; // Convert osrm::json object tree into matching v8 object tree
v8::Local<v8::Value> value;
renderToV8(value, result.get<osrm::json::Object>());
return value;
}
else
{
// Return the string object as a node Buffer
return Nan::CopyBuffer(result.get<std::string>().data(), result.get<std::string>().size())
.ToLocalChecked();
}
} }
inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result) inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result)
@@ -814,6 +833,50 @@ inline bool parseCommonParameters(const v8::Local<v8::Object> &obj, ParamType &p
return true; return true;
} }
inline PluginParameters
argumentsToPluginParameters(const Nan::FunctionCallbackInfo<v8::Value> &args)
{
if (args.Length() < 3 || !args[1]->IsObject())
{
return {};
}
v8::Local<v8::Object> obj = Nan::To<v8::Object>(args[1]).ToLocalChecked();
if (obj->Has(Nan::New("format").ToLocalChecked()))
{
v8::Local<v8::Value> format = obj->Get(Nan::New("format").ToLocalChecked());
if (format.IsEmpty())
{
return {};
}
if (!format->IsString())
{
Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\"");
return {};
}
const Nan::Utf8String format_utf8str(format);
std::string format_str{*format_utf8str, *format_utf8str + format_utf8str.length()};
if (format_str == "object")
{
return {false};
}
else if (format_str == "json_buffer")
{
return {true};
}
else
{
Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\"");
return {};
}
}
return {};
}
inline route_parameters_ptr inline route_parameters_ptr
argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args, argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
bool requires_multiple_coordinates) bool requires_multiple_coordinates)
@@ -1357,6 +1420,6 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
return params; return params;
} }
} // ns node_osrm } // namespace node_osrm
#endif #endif
+3
View File
@@ -23,6 +23,9 @@ namespace detail
{ {
const constexpr double DEGREE_TO_RAD = 0.017453292519943295769236907684886; const constexpr double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
const constexpr double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD; const constexpr double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
const constexpr long double EARTH_RADIUS = 6372797.560856;
inline double degToRad(const double degree) inline double degToRad(const double degree)
{ {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "osrm", "name": "osrm",
"version": "5.18.0-latest.1", "version": "5.19.0",
"private": false, "private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": { "dependencies": {
@@ -240,12 +240,74 @@ void calculateDistances(typename SearchEngineData<ch::Algorithm>::ManyToManyQuer
} }
if (!packed_leg.empty()) if (!packed_leg.empty())
{ {
EdgeDistance annotation = auto annotation =
ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end()); ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end());
annotation = adjustPathDistanceToPhantomNodes(
packed_leg, source_phantom, target_phantom, annotation);
distances_table[row_index * number_of_targets + column_index] = annotation; distances_table[row_index * number_of_targets + column_index] = annotation;
// check the direction of travel to figure out how to calculate the offset to/from
// the source/target
if (source_phantom.forward_segment_id.id == packed_leg.front())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// -->s <-- subtract offset to start at source
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset = source_phantom.GetForwardDistance();
distances_table[row_index * number_of_targets + column_index] -= offset;
}
else if (source_phantom.reverse_segment_id.id == packed_leg.front())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// s<------- <-- subtract offset to start at source
// ... <-- want this distance
// entry 0---1---2---3 <-- 3 is exit node
EdgeDistance offset = source_phantom.GetReverseDistance();
distances_table[row_index * number_of_targets + column_index] -= offset;
}
if (target_phantom.forward_segment_id.id == packed_leg.back())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// ++>t <-- add offset to get to target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset = target_phantom.GetForwardDistance();
distances_table[row_index * number_of_targets + column_index] += offset;
}
else if (target_phantom.reverse_segment_id.id == packed_leg.back())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// <++t <-- add offset to get from target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset = target_phantom.GetReverseDistance();
distances_table[row_index * number_of_targets + column_index] += offset;
}
}
else
{
// there is no shortcut to unpack. source and target are on the same EBG Node.
// if the offset of the target is greater than the offset of the source, subtract it
if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance())
{
// --------->t <-- offsets
// ->s <-- subtract source offset from target offset
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset =
target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance();
distances_table[row_index * number_of_targets + column_index] = offset;
}
else
{
// s<--- <-- offsets
// t<--------- <-- subtract source offset from target offset
// ...... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset =
target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance();
distances_table[row_index * number_of_targets + column_index] = offset;
}
} }
packed_leg.clear(); packed_leg.clear();
} }
+8 -16
View File
@@ -227,9 +227,6 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
{ {
continue; continue;
} }
forward_heap.Clear();
const auto &source_phantom = prev_unbroken_timestamps_list[s].phantom_node;
insertSourceInHeap(forward_heap, source_phantom);
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()))
{ {
@@ -240,19 +237,14 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
continue; continue;
} }
reverse_heap.Clear(); double network_distance =
const auto &target_phantom = current_timestamps_list[s_prime].phantom_node; getNetworkDistance(engine_working_data,
insertTargetInHeap(reverse_heap, target_phantom); facade,
forward_heap,
double network_distance = getNetworkDistance(engine_working_data, reverse_heap,
facade, prev_unbroken_timestamps_list[s].phantom_node,
forward_heap, current_timestamps_list[s_prime].phantom_node,
reverse_heap, weight_upper_bound);
source_phantom,
target_phantom,
weight_upper_bound);
network_distance = std::round(network_distance * 10) / 10;
// get distance diff between loc1/2 and locs/s_prime // get distance diff between loc1/2 and locs/s_prime
const auto d_t = std::abs(network_distance - haversine_distance); const auto d_t = std::abs(network_distance - haversine_distance);
@@ -33,79 +33,6 @@ bool needsLoopBackwards(const PhantomNodes &phantoms)
return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom); return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom);
} }
EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector<NodeID> &path,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
const EdgeDistance uncorrected_distance)
{
EdgeDistance distance = uncorrected_distance;
if (!path.empty())
{
// check the direction of travel to figure out how to calculate the offset to/from
// the source/target
if (source_phantom.forward_segment_id.id == path.front())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// -->s <-- subtract offset to start at source
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance -= source_phantom.GetForwardDistance();
}
else if (source_phantom.reverse_segment_id.id == path.front())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// s<------- <-- subtract offset to start at source
// ... <-- want this distance
// entry 0---1---2---3 <-- 3 is exit node
distance -= source_phantom.GetReverseDistance();
}
if (target_phantom.forward_segment_id.id == path.back())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// ++>t <-- add offset to get to target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance += target_phantom.GetForwardDistance();
}
else if (target_phantom.reverse_segment_id.id == path.back())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// <++t <-- add offset to get from target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance += target_phantom.GetReverseDistance();
}
}
else
{
// there is no shortcut to unpack. source and target are on the same EBG Node.
// if the offset of the target is greater than the offset of the source, subtract it
if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance())
{
// --------->t <-- offsets
// ->s <-- subtract source offset from target offset
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance = target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance();
}
else
{
// s<--- <-- offsets
// t<--------- <-- subtract source offset from target offset
// ...... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance = target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance();
}
}
BOOST_ASSERT_MSG(distance >= 0 || distance > -1.0f,
"Distance correction generated negative number");
// guard against underflow errors caused by rounding
distance = std::max(EdgeDistance{0}, distance);
return distance;
}
} // namespace routing_algorithms } // namespace routing_algorithms
} // namespace engine } // namespace engine
} // namespace osrm } // namespace osrm
@@ -100,7 +100,7 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
const PhantomNodes & /*phantom_nodes*/, const PhantomNodes & /*phantom_nodes*/,
const EdgeWeight weight_upper_bound) const EdgeWeight weight_upper_bound)
{ {
if (forward_heap.Empty() && reverse_heap.Empty()) if (forward_heap.Empty() || reverse_heap.Empty())
{ {
weight = INVALID_EDGE_WEIGHT; weight = INVALID_EDGE_WEIGHT;
return; return;
@@ -110,14 +110,10 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
weight = weight_upper_bound; weight = weight_upper_bound;
// get offset to account for offsets on phantom nodes on compressed edges // get offset to account for offsets on phantom nodes on compressed edges
EdgeWeight min_edge_offset = 0; const auto min_edge_offset = std::min(0, forward_heap.MinKey());
if (forward_heap.Size() > 0) BOOST_ASSERT(min_edge_offset <= 0);
{
min_edge_offset = std::min(min_edge_offset, forward_heap.MinKey());
BOOST_ASSERT(min_edge_offset <= 0);
}
// we only every insert negative offsets for nodes in the forward heap // we only every insert negative offsets for nodes in the forward heap
BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() >= 0); BOOST_ASSERT(reverse_heap.MinKey() >= 0);
// run two-Target Dijkstra routing step. // run two-Target Dijkstra routing step.
while (0 < (forward_heap.Size() + reverse_heap.Size())) while (0 < (forward_heap.Size() + reverse_heap.Size()))
@@ -180,6 +176,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
const PhantomNode &target_phantom, const PhantomNode &target_phantom,
EdgeWeight weight_upper_bound) EdgeWeight weight_upper_bound)
{ {
forward_heap.Clear();
reverse_heap.Clear();
insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom});
EdgeWeight weight = INVALID_EDGE_WEIGHT; EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_path; std::vector<NodeID> packed_path;
search(engine_working_data, search(engine_working_data,
@@ -198,31 +199,14 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
return std::numeric_limits<double>::max(); return std::numeric_limits<double>::max();
} }
EdgeDistance distance = 0; std::vector<PathData> unpacked_path;
unpackPath(facade,
packed_path.begin(),
packed_path.end(),
{source_phantom, target_phantom},
unpacked_path);
std::vector<NodeID> unpacked_nodes; return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
unpacked_nodes.reserve(packed_path.size());
if (!packed_path.empty())
{
unpacked_nodes.push_back(packed_path.front());
unpackPath(
facade, packed_path.begin(), packed_path.end(), [&](const auto &edge, const auto &) {
BOOST_ASSERT(edge.first == unpacked_nodes.back());
unpacked_nodes.push_back(edge.second);
});
distance = std::accumulate(unpacked_nodes.begin(),
std::prev(unpacked_nodes.end()),
EdgeDistance{0},
[&](const EdgeDistance distance, const auto node_id) {
return distance + computeEdgeDistance(facade, node_id);
});
}
distance =
adjustPathDistanceToPhantomNodes(unpacked_nodes, source_phantom, target_phantom, distance);
return distance;
} }
} // namespace ch } // namespace ch
+92 -11
View File
@@ -9,12 +9,15 @@
#include "osrm/trip_parameters.hpp" #include "osrm/trip_parameters.hpp"
#include <exception> #include <exception>
#include <sstream>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "nodejs/node_osrm.hpp" #include "nodejs/node_osrm.hpp"
#include "nodejs/node_osrm_support.hpp" #include "nodejs/node_osrm_support.hpp"
#include "util/json_renderer.hpp"
namespace node_osrm namespace node_osrm
{ {
@@ -122,6 +125,8 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
if (!params) if (!params)
return; return;
auto pluginParams = argumentsToPluginParameters(info);
BOOST_ASSERT(params->IsValid()); BOOST_ASSERT(params->IsValid());
if (!info[info.Length() - 1]->IsFunction()) if (!info[info.Length() - 1]->IsFunction())
@@ -137,9 +142,89 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
Worker(std::shared_ptr<osrm::OSRM> osrm_, Worker(std::shared_ptr<osrm::OSRM> osrm_,
ParamPtr params_, ParamPtr params_,
ServiceMemFn service, ServiceMemFn service,
Nan::Callback *callback) Nan::Callback *callback,
PluginParameters pluginParams_)
: Base(callback), osrm{std::move(osrm_)}, service{std::move(service)}, : Base(callback), osrm{std::move(osrm_)}, service{std::move(service)},
params{std::move(params_)} params{std::move(params_)}, pluginParams{std::move(pluginParams_)}
{
}
void Execute() override try
{
osrm::json::Object r;
const auto status = ((*osrm).*(service))(*params, r);
ParseResult(status, r);
if (pluginParams.renderJSONToBuffer)
{
std::ostringstream buf;
osrm::util::json::render(buf, r);
result = buf.str();
}
else
{
result = r;
}
}
catch (const std::exception &e)
{
SetErrorMessage(e.what());
}
void HandleOKCallback() override
{
Nan::HandleScope scope;
const constexpr auto argc = 2u;
v8::Local<v8::Value> argv[argc] = {Nan::Null(), render(result)};
callback->Call(argc, argv);
}
// Keeps the OSRM object alive even after shutdown until we're done with callback
std::shared_ptr<osrm::OSRM> osrm;
ServiceMemFn service;
const ParamPtr params;
const PluginParameters pluginParams;
ObjectOrString result;
};
auto *callback = new Nan::Callback{info[info.Length() - 1].As<v8::Function>()};
Nan::AsyncQueueWorker(
new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)});
}
template <typename ParameterParser, typename ServiceMemFn>
inline void asyncForTiles(const Nan::FunctionCallbackInfo<v8::Value> &info,
ParameterParser argsToParams,
ServiceMemFn service,
bool requires_multiple_coordinates)
{
auto params = argsToParams(info, requires_multiple_coordinates);
if (!params)
return;
auto pluginParams = argumentsToPluginParameters(info);
BOOST_ASSERT(params->IsValid());
if (!info[info.Length() - 1]->IsFunction())
return Nan::ThrowTypeError("last argument must be a callback function");
auto *const self = Nan::ObjectWrap::Unwrap<Engine>(info.Holder());
using ParamPtr = decltype(params);
struct Worker final : Nan::AsyncWorker
{
using Base = Nan::AsyncWorker;
Worker(std::shared_ptr<osrm::OSRM> osrm_,
ParamPtr params_,
ServiceMemFn service,
Nan::Callback *callback,
PluginParameters pluginParams_)
: Base(callback), osrm{std::move(osrm_)}, service{std::move(service)},
params{std::move(params_)}, pluginParams{std::move(pluginParams_)}
{ {
} }
@@ -167,18 +252,14 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
std::shared_ptr<osrm::OSRM> osrm; std::shared_ptr<osrm::OSRM> osrm;
ServiceMemFn service; ServiceMemFn service;
const ParamPtr params; const ParamPtr params;
const PluginParameters pluginParams;
// All services return json::Object .. except for Tile! std::string result;
using ObjectOrString =
typename std::conditional<std::is_same<ParamPtr, tile_parameters_ptr>::value,
std::string,
osrm::json::Object>::type;
ObjectOrString result;
}; };
auto *callback = new Nan::Callback{info[info.Length() - 1].As<v8::Function>()}; auto *callback = new Nan::Callback{info[info.Length() - 1].As<v8::Function>()};
Nan::AsyncQueueWorker(new Worker{self->this_, std::move(params), service, callback}); Nan::AsyncQueueWorker(
new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)});
} }
// clang-format off // clang-format off
@@ -341,7 +422,7 @@ NAN_METHOD(Engine::table) //
// clang-format on // clang-format on
NAN_METHOD(Engine::tile) NAN_METHOD(Engine::tile)
{ {
async(info, &argumentsToTileParameters, &osrm::OSRM::Tile, {/*unused*/}); asyncForTiles(info, &argumentsToTileParameters, &osrm::OSRM::Tile, {/*unused*/});
} }
// clang-format off // clang-format off
+9 -13
View File
@@ -70,8 +70,8 @@ std::istream &operator>>(std::istream &in, EngineConfig::Algorithm &algorithm)
throw util::RuntimeError(token, ErrorCode::UnknownAlgorithm, SOURCE_REF); throw util::RuntimeError(token, ErrorCode::UnknownAlgorithm, SOURCE_REF);
return in; return in;
} }
} } // namespace engine
} } // namespace osrm
// generate boost::program_options object for the routing part // generate boost::program_options object for the routing part
inline unsigned generateServerProgramOptions(const int argc, inline unsigned generateServerProgramOptions(const int argc,
@@ -273,10 +273,12 @@ int main(int argc, const char *argv[]) try
#ifndef _WIN32 #ifndef _WIN32
int sig = 0; int sig = 0;
sigset_t new_mask; sigset_t wait_mask;
sigset_t old_mask; sigemptyset(&wait_mask);
sigfillset(&new_mask); sigaddset(&wait_mask, SIGINT);
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); sigaddset(&wait_mask, SIGQUIT);
sigaddset(&wait_mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr); // only block necessary signals
#endif #endif
auto service_handler = std::make_unique<server::ServiceHandler>(config); auto service_handler = std::make_unique<server::ServiceHandler>(config);
@@ -298,19 +300,13 @@ int main(int argc, const char *argv[]) try
std::thread server_thread(std::move(server_task)); std::thread server_thread(std::move(server_task));
#ifndef _WIN32 #ifndef _WIN32
sigset_t wait_mask;
pthread_sigmask(SIG_SETMASK, &old_mask, nullptr);
sigemptyset(&wait_mask);
sigaddset(&wait_mask, SIGINT);
sigaddset(&wait_mask, SIGQUIT);
sigaddset(&wait_mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr);
util::Log() << "running and waiting for requests"; util::Log() << "running and waiting for requests";
if (std::getenv("SIGNAL_PARENT_WHEN_READY")) if (std::getenv("SIGNAL_PARENT_WHEN_READY"))
{ {
kill(getppid(), SIGUSR1); kill(getppid(), SIGUSR1);
} }
sigwait(&wait_mask, &sig); sigwait(&wait_mask, &sig);
util::Log() << "received signal " << sig;
#else #else
// Set console control handler to allow server to be stopped. // Set console control handler to allow server to be stopped.
console_ctrl_function = std::bind(&server::Server::Stop, routing_server); console_ctrl_function = std::bind(&server::Server::Stop, routing_server);
+2 -7
View File
@@ -22,11 +22,6 @@ namespace coordinate_calculation
namespace namespace
{ {
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
const constexpr double EARTH_RADIUS = 6372797.560856;
class CheapRulerContainer class CheapRulerContainer
{ {
public: public:
@@ -117,7 +112,7 @@ double haversineDistance(const Coordinate coordinate_1, const Coordinate coordin
const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) + const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) +
std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2); std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2);
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv)); const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
return EARTH_RADIUS * charv; return detail::EARTH_RADIUS * charv;
} }
double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2) double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
@@ -138,7 +133,7 @@ double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coord
const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0); const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0);
const double y_value = float_lat2 - float_lat1; const double y_value = float_lat2 - float_lat1;
return std::hypot(x_value, y_value) * EARTH_RADIUS; return std::hypot(x_value, y_value) * detail::EARTH_RADIUS;
} }
double perpendicularDistance(const Coordinate segment_source, double perpendicularDistance(const Coordinate segment_source,
+32
View File
@@ -25,6 +25,28 @@ test('match: match in Monaco', function(assert) {
}); });
}); });
test('match: match in Monaco returning a buffer', function(assert) {
assert.plan(6);
var osrm = new OSRM(data_path);
var options = {
coordinates: three_test_coordinates,
timestamps: [1424684612, 1424684616, 1424684620]
};
osrm.match(options, { format: 'json_buffer' }, function(err, response) {
assert.ifError(err);
assert.ok(response instanceof Buffer);
response = JSON.parse(response);
assert.equal(response.matchings.length, 1);
assert.ok(response.matchings.every(function(m) {
return !!m.distance && !!m.duration && Array.isArray(m.legs) && !!m.geometry && m.confidence > 0;
}))
assert.equal(response.tracepoints.length, 3);
assert.ok(response.tracepoints.every(function(t) {
return !!t.hint && !isNaN(t.matchings_index) && !isNaN(t.waypoint_index) && !!t.name;
}));
});
});
test('match: match in Monaco without timestamps', function(assert) { test('match: match in Monaco without timestamps', function(assert) {
assert.plan(3); assert.plan(3);
var osrm = new OSRM(data_path); var osrm = new OSRM(data_path);
@@ -225,6 +247,16 @@ test('match: throws on invalid tidy param', function(assert) {
/tidy must be of type Boolean/); /tidy must be of type Boolean/);
}); });
test('match: throws on invalid config param', function(assert) {
assert.plan(1);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: three_test_coordinates,
};
assert.throws(function() { osrm.match(options, { format: 'invalid' }, function(err, response) {}) },
/format must be a string:/);
});
test('match: match in Monaco without motorways', function(assert) { test('match: match in Monaco without motorways', function(assert) {
assert.plan(3); assert.plan(3);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'}); var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
+20 -1
View File
@@ -19,6 +19,21 @@ test('nearest', function(assert) {
}); });
}); });
test('nearest', function(assert) {
assert.plan(5);
var osrm = new OSRM(data_path);
osrm.nearest({
coordinates: [three_test_coordinates[0]]
}, { format: 'json_buffer' }, function(err, result) {
assert.ifError(err);
assert.ok(result instanceof Buffer);
result = JSON.parse(result);
assert.equal(result.waypoints.length, 1);
assert.equal(result.waypoints[0].location.length, 2);
assert.ok(result.waypoints[0].hasOwnProperty('name'));
});
});
test('nearest: can ask for multiple nearest pts', function(assert) { test('nearest: can ask for multiple nearest pts', function(assert) {
assert.plan(2); assert.plan(2);
var osrm = new OSRM(data_path); var osrm = new OSRM(data_path);
@@ -32,7 +47,7 @@ test('nearest: can ask for multiple nearest pts', function(assert) {
}); });
test('nearest: throws on invalid args', function(assert) { test('nearest: throws on invalid args', function(assert) {
assert.plan(6); assert.plan(7);
var osrm = new OSRM(data_path); var osrm = new OSRM(data_path);
var options = {}; var options = {};
assert.throws(function() { osrm.nearest(options); }, assert.throws(function() { osrm.nearest(options); },
@@ -52,6 +67,10 @@ test('nearest: throws on invalid args', function(assert) {
options.number = 0; options.number = 0;
assert.throws(function() { osrm.nearest(options, function(err, res) {}); }, assert.throws(function() { osrm.nearest(options, function(err, res) {}); },
/Number must be an integer greater than or equal to 1/); /Number must be an integer greater than or equal to 1/);
options.number = 1;
assert.throws(function() { osrm.nearest(options, { format: 'invalid' }, function(err, res) {}); },
/format must be a string:/);
}); });
test('nearest: nearest in Monaco without motorways', function(assert) { test('nearest: nearest in Monaco without motorways', function(assert) {
+17 -1
View File
@@ -43,8 +43,22 @@ test('route: routes Monaco on CoreCH', function(assert) {
}); });
}); });
test('route: routes Monaco and returns a JSON buffer', function(assert) {
assert.plan(6);
var osrm = new OSRM({path: monaco_corech_path, algorithm: 'CoreCH'});
osrm.route({coordinates: [[13.43864,52.51993],[13.415852,52.513191]]}, { format: 'json_buffer'}, function(err, result) {
assert.ifError(err);
assert.ok(result instanceof Buffer);
const route = JSON.parse(result);
assert.ok(route.waypoints);
assert.ok(route.routes);
assert.ok(route.routes.length);
assert.ok(route.routes[0].geometry);
});
});
test('route: throws with too few or invalid args', function(assert) { test('route: throws with too few or invalid args', function(assert) {
assert.plan(3); assert.plan(4);
var osrm = new OSRM(monaco_path); var osrm = new OSRM(monaco_path);
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}) }, assert.throws(function() { osrm.route({coordinates: two_test_coordinates}) },
/Two arguments required/); /Two arguments required/);
@@ -52,6 +66,8 @@ test('route: throws with too few or invalid args', function(assert) {
/First arg must be an object/); /First arg must be an object/);
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, true)}, assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, true)},
/last argument must be a callback function/); /last argument must be a callback function/);
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, route) {})},
/format must be a string:/);
}); });
test('route: provides no alternatives by default, but when requested it may (not guaranteed)', function(assert) { test('route: provides no alternatives by default, but when requested it may (not guaranteed)', function(assert) {
+18 -1
View File
@@ -48,6 +48,20 @@ test('table: test annotations paramater combination', function(assert) {
}); });
}); });
test('table: returns buffer', function(assert) {
assert.plan(3);
var osrm = new OSRM(data_path);
var options = {
coordinates: [three_test_coordinates[0], three_test_coordinates[1]],
};
osrm.table(options, { format: 'json_buffer' }, function(err, table) {
assert.ifError(err);
assert.ok(table instanceof Buffer);
table = JSON.parse(table);
assert.ok(table['durations'], 'distances table result should exist');
});
});
var tables = ['distances', 'durations']; var tables = ['distances', 'durations'];
tables.forEach(function(annotation) { tables.forEach(function(annotation) {
@@ -116,7 +130,7 @@ tables.forEach(function(annotation) {
}); });
test('table: ' + annotation + ' throws on invalid arguments', function(assert) { test('table: ' + annotation + ' throws on invalid arguments', function(assert) {
assert.plan(14); assert.plan(15);
var osrm = new OSRM(data_path); var osrm = new OSRM(data_path);
var options = {annotations: [annotation.slice(0,-1)]}; var options = {annotations: [annotation.slice(0,-1)]};
assert.throws(function() { osrm.table(options); }, assert.throws(function() { osrm.table(options); },
@@ -135,6 +149,9 @@ tables.forEach(function(annotation) {
/Coordinates must be an array of \(lon\/lat\) pairs/); /Coordinates must be an array of \(lon\/lat\) pairs/);
options.coordinates = two_test_coordinates; options.coordinates = two_test_coordinates;
assert.throws(function() { osrm.table(options, { format: 'invalid' }, function(err, response) {}) },
/format must be a string:/);
options.sources = true; options.sources = true;
assert.throws(function() { osrm.table(options, function(err, response) {}) }, assert.throws(function() { osrm.table(options, function(err, response) {}) },
/Sources must be an array of indices \(or undefined\)/); /Sources must be an array of indices \(or undefined\)/);
+16 -1
View File
@@ -17,6 +17,19 @@ test('trip: trip in Monaco', function(assert) {
}); });
}); });
test('trip: trip in Monaco as a buffer', function(assert) {
assert.plan(3);
var osrm = new OSRM(data_path);
osrm.trip({coordinates: two_test_coordinates}, { format: 'json_buffer' }, function(err, trip) {
assert.ifError(err);
assert.ok(trip instanceof Buffer);
trip = JSON.parse(trip);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t].geometry);
}
});
});
test('trip: trip with many locations in Monaco', function(assert) { test('trip: trip with many locations in Monaco', function(assert) {
assert.plan(2); assert.plan(2);
@@ -33,12 +46,14 @@ test('trip: trip with many locations in Monaco', function(assert) {
}); });
test('trip: throws with too few or invalid args', function(assert) { test('trip: throws with too few or invalid args', function(assert) {
assert.plan(2); assert.plan(3);
var osrm = new OSRM(data_path); var osrm = new OSRM(data_path);
assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}) }, assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}) },
/Two arguments required/); /Two arguments required/);
assert.throws(function() { osrm.trip(null, function(err, trip) {}) }, assert.throws(function() { osrm.trip(null, function(err, trip) {}) },
/First arg must be an object/); /First arg must be an object/);
assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, trip) {}) },
/format must be a string:/);
}); });
test('trip: throws with bad params', function(assert) { test('trip: throws with bad params', function(assert) {