Compare commits

...

26 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
Daniel Patterson 85515f063a Render floating point numbers to string using Grisu2 algorithmt instead of stdlib to speed up JSON generation. 2018-09-05 14:20:47 -07:00
Daniel Patterson 69d7825542 Increase allowed shared memory regions to 512 from ~120 2018-09-05 11:48:02 -07:00
Patrick Niklaus 9b779c704f Update changelog 2018-08-02 12:19:24 +02:00
Patrick Niklaus 5bd7d04fe3 Fix formating 2018-08-02 12:19:24 +02:00
Patrick Niklaus 0f78f7b2cc Fix bug in computation of distance offset for phantom node 2018-08-02 12:19:24 +02:00
Patrick Niklaus 8473be69d2 Adjust text cases for flightly different matching due to rounding 2018-08-02 12:19:24 +02:00
Patrick Niklaus c0124f7d77 Round network distance to deci-meter to retain previous behavior 2018-08-02 12:19:24 +02:00
Patrick Niklaus b630b4e32a Preserve heap state in map matching 2018-08-02 12:19:24 +02:00
Patrick Niklaus 89fabc1b9c Use distance functions from many to many 2018-08-02 12:19:24 +02:00
Patrick Niklaus a649a8a5cf Use FCC algorithm for map matching distance calculation 2018-08-02 12:19:24 +02:00
Frédéric Rodrigo f928956584 Support maxlength and maxweight in car profile 2018-07-11 18:33:30 +02:00
Frédéric Rodrigo 7ff68792d7 Add helper for maxlength into measure.lua 2018-07-11 18:33:30 +02:00
Frédéric Rodrigo 3088dd0342 Better and flexible weight parsing in measure.lua 2018-07-11 18:33:30 +02:00
Frédéric Rodrigo d2590989f5 Default maxspeed for fr:rural is now 80km/h 2018-07-11 17:54:46 +02:00
Antoine Giret 3a7b377586 Update profiles.md 2018-06-27 14:27:17 +02:00
Michael Krasnyk 82b5648c97 Don't collapse segregated intersections at roundabout exits, #5114 2018-06-21 15:24:03 +02:00
Antoine Giret 1628a3c4d5 Update profiles.md 2018-06-07 15:43:06 +02:00
Matthias Gilch e5d8319c43 Removed unused variable
The variable name_data_mutex is declared in a block but never used
within this block. So I've removed the variable.
2018-06-02 22:49:30 +02:00
MichalPP 06699132eb allow routing over barrier=some_tag 2018-05-29 16:56:15 +02:00
MichalPP 918e794d6a change barrier_whitelist to barrier blacklist
change barrier_whitelist to barrier blacklist  in foot profile
fix #5067 and #3890 and #4823
2018-05-29 16:56:15 +02:00
MichalPP 8dd8ee1fc2 blacklisting barriers allow routing
blacklisting barriers allow routing over barrier=some_tag
2018-05-28 17:21:08 +02:00
MichalPP c3d0efda93 change barrier_whitelist to barrier_blacklist 2018-05-28 17:21:08 +02:00
31 changed files with 984 additions and 122 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*)?$/
+17 -1
View File
@@ -1,4 +1,20 @@
# UNRELEASED # 5.19.0
- Changes from 5.18.0:
- Optimizations:
- 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:
- FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114)
- Misc:
- CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185)
# 5.18.0
- Changes from 5.17.0: - Changes from 5.17.0:
- Features: - Features:
- ADDED: `table` plugin now optionally returns `distance` matrix as part of response [#4990](https://github.com/Project-OSRM/osrm-backend/pull/4990) - ADDED: `table` plugin now optionally returns `distance` matrix as part of response [#4990](https://github.com/Project-OSRM/osrm-backend/pull/4990)
+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
+2 -2
View File
@@ -138,7 +138,7 @@ Given an OpenStreetMap way, the `process_way` function will either return nothin
Argument | Description Argument | Description
---------|------------------------------------------------------- ---------|-------------------------------------------------------
profile | The configuration table you returned in `setup`. profile | The configuration table you returned in `setup`.
node | The input way to process (read-only). way | The input way to process (read-only).
result | The output that you will modify. result | The output that you will modify.
relations| Storage of relations to access relations, where `way` is a member. relations| Storage of relations to access relations, where `way` is a member.
@@ -199,7 +199,7 @@ source.lon | Read | Float | Co-ordinates of segment start
source.lat | Read | Float | "" source.lat | Read | Float | ""
target.lon | Read | Float | Co-ordinates of segment end target.lon | Read | Float | Co-ordinates of segment end
target.lat | Read | Float | "" target.lat | Read | Float | ""
target.distance | Read | Float | Length of segment distance | Read | Float | Length of segment
weight | Read/write | Float | Routing weight for this segment weight | Read/write | Float | Routing weight for this segment
duration | Read/write | Float | Duration for this segment duration | Read/write | Float | Duration for this segment
+1 -1
View File
@@ -19,7 +19,7 @@ Feature: Barriers
| entrance | x | | entrance | x |
| wall | | | wall | |
| fence | | | fence | |
| some_tag | | | some_tag | x |
| block | x | | block | x |
Scenario: Bike - Access tag trumphs barriers Scenario: Bike - Access tag trumphs barriers
+19
View File
@@ -48,3 +48,22 @@ Feature: Car - Handle physical limitation
| primary | | none | x | | primary | | none | x |
| primary | | no-sign | x | | primary | | no-sign | x |
| primary | | unsigned | x | | primary | | unsigned | x |
Scenario: Car - Limited by length
Then routability should be
| highway | maxlength | bothw |
| primary | | x |
| primary | 1 | |
| primary | 5 | x |
| primary | unsigned | x |
Scenario: Car - Limited by weight
Then routability should be
| highway | maxweight | bothw |
| primary | | x |
| primary | 1 | |
| primary | 3.5 | x |
| primary | 35000 kg | x |
| primary | 8.9t | x |
| primary | 0.1 lbs | |
| primary | unsigned | x |
+1 -1
View File
@@ -19,7 +19,7 @@ Feature: Barriers
| entrance | x | | entrance | x |
| wall | | | wall | |
| fence | | | fence | |
| some_tag | | | some_tag | x |
| block | x | | block | x |
Scenario: Foot - Access tag trumphs barriers Scenario: Foot - Access tag trumphs barriers
+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
+9 -10
View File
@@ -26,7 +26,7 @@ namespace serialization
inline void read(io::BufferReader &reader, DataLayout &layout); inline void read(io::BufferReader &reader, DataLayout &layout);
inline void write(io::BufferWriter &writer, const DataLayout &layout); inline void write(io::BufferWriter &writer, const DataLayout &layout);
} } // namespace serialization
namespace detail namespace detail
{ {
@@ -52,7 +52,7 @@ inline std::string trimName(const std::string &name_prefix, const std::string &n
return name; return name;
} }
} }
} } // namespace detail
class DataLayout class DataLayout
{ {
@@ -165,7 +165,7 @@ struct SharedRegion
static constexpr const int MAX_NAME_LENGTH = 254; static constexpr const int MAX_NAME_LENGTH = 254;
SharedRegion() : name{0}, timestamp{0} {} SharedRegion() : name{0}, timestamp{0} {}
SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint8_t shm_key) SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint16_t shm_key)
: name{0}, timestamp{timestamp}, shm_key{shm_key} : name{0}, timestamp{timestamp}, shm_key{shm_key}
{ {
std::copy_n(name_.begin(), std::min<std::size_t>(MAX_NAME_LENGTH, name_.size()), name); std::copy_n(name_.begin(), std::min<std::size_t>(MAX_NAME_LENGTH, name_.size()), name);
@@ -175,14 +175,14 @@ struct SharedRegion
char name[MAX_NAME_LENGTH + 1]; char name[MAX_NAME_LENGTH + 1];
std::uint64_t timestamp; std::uint64_t timestamp;
std::uint8_t shm_key; std::uint16_t shm_key;
}; };
// Keeps a list of all shared regions in a fixed-sized struct // Keeps a list of all shared regions in a fixed-sized struct
// for fast access and deserialization. // for fast access and deserialization.
struct SharedRegionRegister struct SharedRegionRegister
{ {
using RegionID = std::uint8_t; using RegionID = std::uint16_t;
static constexpr const RegionID INVALID_REGION_ID = std::numeric_limits<RegionID>::max(); static constexpr const RegionID INVALID_REGION_ID = std::numeric_limits<RegionID>::max();
using ShmKey = decltype(SharedRegion::shm_key); using ShmKey = decltype(SharedRegion::shm_key);
@@ -250,12 +250,11 @@ struct SharedRegionRegister
void ReleaseKey(ShmKey key) { shm_key_in_use[key] = false; } void ReleaseKey(ShmKey key) { shm_key_in_use[key] = false; }
static constexpr const std::uint8_t MAX_SHARED_REGIONS = static constexpr const std::size_t MAX_SHARED_REGIONS = 512;
std::numeric_limits<RegionID>::max() - 1;
static_assert(MAX_SHARED_REGIONS < std::numeric_limits<RegionID>::max(), static_assert(MAX_SHARED_REGIONS < std::numeric_limits<RegionID>::max(),
"Number of shared memory regions needs to be less than the region id size."); "Number of shared memory regions needs to be less than the region id size.");
static constexpr const std::uint8_t MAX_SHM_KEYS = std::numeric_limits<std::uint8_t>::max() - 1; static constexpr const std::size_t MAX_SHM_KEYS = MAX_SHARED_REGIONS * 2;
static constexpr const char *name = "osrm-region"; static constexpr const char *name = "osrm-region";
@@ -263,7 +262,7 @@ struct SharedRegionRegister
std::array<SharedRegion, MAX_SHARED_REGIONS> regions; std::array<SharedRegion, MAX_SHARED_REGIONS> regions;
std::array<bool, MAX_SHM_KEYS> shm_key_in_use; std::array<bool, MAX_SHM_KEYS> shm_key_in_use;
}; };
} } // namespace storage
} } // namespace osrm
#endif /* SHARED_DATA_TYPE_HPP */ #endif /* SHARED_DATA_TYPE_HPP */
+10 -9
View File
@@ -34,10 +34,10 @@ namespace storage
struct OSRMLockFile struct OSRMLockFile
{ {
boost::filesystem::path operator()() template <typename IdentifierT> boost::filesystem::path operator()(const IdentifierT &id)
{ {
boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path(); boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path();
boost::filesystem::path lock_file = temp_dir / "osrm.lock"; boost::filesystem::path lock_file = temp_dir / ("osrm-" + std::to_string(id) + ".lock");
return lock_file; return lock_file;
} }
}; };
@@ -93,7 +93,7 @@ class SharedMemory
try try
{ {
OSRMLockFile lock_file; OSRMLockFile lock_file;
boost::interprocess::xsi_key key(lock_file().string().c_str(), id); boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id);
result = RegionExists(key); result = RegionExists(key);
} }
catch (...) catch (...)
@@ -106,7 +106,7 @@ class SharedMemory
template <typename IdentifierT> static bool Remove(const IdentifierT id) template <typename IdentifierT> static bool Remove(const IdentifierT id)
{ {
OSRMLockFile lock_file; OSRMLockFile lock_file;
boost::interprocess::xsi_key key(lock_file().string().c_str(), id); boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id);
return Remove(key); return Remove(key);
} }
@@ -287,10 +287,11 @@ class SharedMemory
template <typename IdentifierT, typename LockFileT = OSRMLockFile> template <typename IdentifierT, typename LockFileT = OSRMLockFile>
std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint64_t size = 0) std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint64_t size = 0)
{ {
static_assert(sizeof(id) == sizeof(std::uint16_t), "Key type is not 16 bits");
try try
{ {
LockFileT lock_file; LockFileT lock_file;
if (!boost::filesystem::exists(lock_file())) if (!boost::filesystem::exists(lock_file(id)))
{ {
if (0 == size) if (0 == size)
{ {
@@ -298,10 +299,10 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint
} }
else else
{ {
boost::filesystem::ofstream ofs(lock_file()); boost::filesystem::ofstream ofs(lock_file(id));
} }
} }
return std::make_unique<SharedMemory>(lock_file(), id, size); return std::make_unique<SharedMemory>(lock_file(id), id, size);
} }
catch (const boost::interprocess::interprocess_exception &e) catch (const boost::interprocess::interprocess_exception &e)
{ {
@@ -310,7 +311,7 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint
throw util::exception(e.what() + SOURCE_REF); throw util::exception(e.what() + SOURCE_REF);
} }
} }
} } // namespace storage
} } // namespace osrm
#endif // SHARED_MEMORY_HPP #endif // SHARED_MEMORY_HPP
+6 -4
View File
@@ -33,7 +33,7 @@ template <class Lock> class InvertedLock
InvertedLock(Lock &lock) : lock(lock) { lock.unlock(); } InvertedLock(Lock &lock) : lock(lock) { lock.unlock(); }
~InvertedLock() { lock.lock(); } ~InvertedLock() { lock.lock(); }
}; };
} } // namespace
// The shared monitor implementation based on a semaphore and mutex // The shared monitor implementation based on a semaphore and mutex
template <typename Data> struct SharedMonitor template <typename Data> struct SharedMonitor
@@ -146,7 +146,9 @@ template <typename Data> struct SharedMonitor
// like two-turnstile reusable barrier or boost/interprocess/sync/spin/condition.hpp // like two-turnstile reusable barrier or boost/interprocess/sync/spin/condition.hpp
// fail if a waiter is killed. // fail if a waiter is killed.
static constexpr int buffer_size = 256; // Buffer size needs to be large enough to hold all the semaphores for every
// listener you want to support.
static constexpr int buffer_size = 4096 * 4;
struct InternalData struct InternalData
{ {
@@ -232,8 +234,8 @@ template <typename Data> struct SharedMonitor
bi::shared_memory_object shmem; bi::shared_memory_object shmem;
bi::mapped_region region; bi::mapped_region region;
}; };
} } // namespace storage
} } // namespace osrm
#undef USE_BOOST_INTERPROCESS_CONDITION #undef USE_BOOST_INTERPROCESS_CONDITION
+517
View File
@@ -0,0 +1,517 @@
#ifndef IEEE754_HPP
#define IEEE754_HPP
/**
Copyright (C) 2014 Milo Yip
Imported from:
https://github.com/miloyip/dtoa-benchmark/blob/c4020c62754950d38a1aaaed2975b05b441d1e7d/src/milo/dtoa_milo.h
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
**/
#include <assert.h>
#include <math.h>
#if defined(_MSC_VER)
#include "msinttypes/stdint.h"
#include <intrin.h>
#else
#include <stdint.h>
#endif
#define UINT64_C2(h, l) ((static_cast<uint64_t>(h) << 32) | static_cast<uint64_t>(l))
namespace osrm
{
namespace util
{
namespace ieee754
{
struct DiyFp
{
DiyFp() {}
DiyFp(uint64_t f, int e) : f(f), e(e) {}
DiyFp(double d)
{
union {
double d;
uint64_t u64;
} u = {d};
int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0)
{
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
}
else
{
f = significand;
e = kDpMinExponent + 1;
}
}
DiyFp operator-(const DiyFp &rhs) const
{
assert(e == rhs.e);
assert(f >= rhs.f);
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp &rhs) const
{
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
unsigned __int128 p =
static_cast<unsigned __int128>(f) * static_cast<unsigned __int128>(rhs.f);
uint64_t h = p >> 64;
uint64_t l = static_cast<uint64_t>(p);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#else
const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
tmp += 1U << 31; /// mult_round
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
#endif
}
DiyFp Normalize() const
{
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__)
int s = __builtin_clzll(f);
return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & kDpHiddenBit))
{
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
return res;
#endif
}
DiyFp NormalizeBoundary() const
{
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#else
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1)))
{
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
return res;
#endif
}
void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const
{
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMinExponent = -kDpExponentBias;
static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000);
uint64_t f;
int e;
};
inline DiyFp GetCachedPower(int e, int *K)
{
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76),
UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea),
UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df),
UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f),
UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c),
UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5),
UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d),
UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637),
UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7),
UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5),
UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b),
UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996),
UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8),
UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053),
UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd),
UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94),
UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b),
UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac),
UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3),
UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb),
UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c),
UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000),
UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984),
UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70),
UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245),
UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8),
UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a),
UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea),
UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85),
UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2),
UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3),
UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25),
UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece),
UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5),
UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a),
UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a),
UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129),
UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429),
UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d),
UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841),
UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9),
UINT64_C2(0xaf87023b, 0x9bf0ee6b)};
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901,
-874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555,
-529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210,
-183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136,
162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481,
508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827,
853, 880, 907, 933, 960, 986, 1013, 1039, 1066};
// int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk =
(-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if (k != dk)
k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1);
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0]));
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
inline void
GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w)
{
while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer
wp_w - rest > rest + ten_kappa - wp_w))
{
buffer[len - 1]--;
rest += ten_kappa;
}
}
inline unsigned CountDecimalDigit32(uint32_t n)
{
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
if (n < 10)
return 1;
if (n < 100)
return 2;
if (n < 1000)
return 3;
if (n < 10000)
return 4;
if (n < 100000)
return 5;
if (n < 1000000)
return 6;
if (n < 10000000)
return 7;
if (n < 100000000)
return 8;
if (n < 1000000000)
return 9;
return 10;
}
inline void
DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K)
{
static const uint32_t kPow10[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1);
int kappa = static_cast<int>(CountDecimalDigit32(p1));
*len = 0;
while (kappa > 0)
{
uint32_t d;
switch (kappa)
{
case 10:
d = p1 / 1000000000;
p1 %= 1000000000;
break;
case 9:
d = p1 / 100000000;
p1 %= 100000000;
break;
case 8:
d = p1 / 10000000;
p1 %= 10000000;
break;
case 7:
d = p1 / 1000000;
p1 %= 1000000;
break;
case 6:
d = p1 / 100000;
p1 %= 100000;
break;
case 5:
d = p1 / 10000;
p1 %= 10000;
break;
case 4:
d = p1 / 1000;
p1 %= 1000;
break;
case 3:
d = p1 / 100;
p1 %= 100;
break;
case 2:
d = p1 / 10;
p1 %= 10;
break;
case 1:
d = p1;
p1 = 0;
break;
default:
#if defined(_MSC_VER)
__assume(0);
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
__builtin_unreachable();
#else
d = 0;
#endif
}
if (d || *len)
buffer[(*len)++] = '0' + static_cast<char>(d);
kappa--;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta)
{
*K += kappa;
GrisuRound(
buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
return;
}
}
// kappa = 0
for (;;)
{
p2 *= 10;
delta *= 10;
char d = static_cast<char>(p2 >> -one.e);
if (d || *len)
buffer[(*len)++] = '0' + d;
p2 &= one.f - 1;
kappa--;
if (p2 < delta)
{
*K += kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
return;
}
}
}
inline void Grisu2(double value, char *buffer, int *length, int *K)
{
const DiyFp v(value);
DiyFp w_m, w_p;
v.NormalizedBoundaries(&w_m, &w_p);
const DiyFp c_mk = GetCachedPower(w_p.e, K);
const DiyFp W = v.Normalize() * c_mk;
DiyFp Wp = w_p * c_mk;
DiyFp Wm = w_m * c_mk;
Wm.f++;
Wp.f--;
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
}
inline const char *GetDigitsLut()
{
static const char cDigitsLut[200] = {
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0',
'8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6',
'1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2',
'5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3',
'3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', '4',
'2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0',
'5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5',
'9', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7',
'6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7',
'6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
'8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9',
'3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'};
return cDigitsLut;
}
inline void WriteExponent(int K, char *buffer)
{
if (K < 0)
{
*buffer++ = '-';
K = -K;
}
if (K >= 100)
{
*buffer++ = '0' + static_cast<char>(K / 100);
K %= 100;
const char *d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else if (K >= 10)
{
const char *d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else
*buffer++ = '0' + static_cast<char>(K);
*buffer = '\0';
}
inline void Prettify(char *buffer, int length, int k)
{
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (length <= kk && kk <= 21)
{
// 1234e7 -> 12340000000
for (int i = length; i < kk; i++)
buffer[i] = '0';
buffer[kk] = '.';
buffer[kk + 1] = '0';
buffer[kk + 2] = '\0';
}
else if (0 < kk && kk <= 21)
{
// 1234e-2 -> 12.34
memmove(&buffer[kk + 1], &buffer[kk], length - kk);
buffer[kk] = '.';
buffer[length + 1] = '\0';
}
else if (-6 < kk && kk <= 0)
{
// 1234e-6 -> 0.001234
const int offset = 2 - kk;
memmove(&buffer[offset], &buffer[0], length);
buffer[0] = '0';
buffer[1] = '.';
for (int i = 2; i < offset; i++)
buffer[i] = '0';
buffer[length + offset] = '\0';
}
else if (length == 1)
{
// 1e30
buffer[1] = 'e';
WriteExponent(kk - 1, &buffer[2]);
}
else
{
// 1234e30 -> 1.234e33
memmove(&buffer[2], &buffer[1], length - 1);
buffer[1] = '.';
buffer[length + 1] = 'e';
WriteExponent(kk - 1, &buffer[0 + length + 2]);
}
}
inline void dtoa_milo(double value, char *buffer)
{
// Not handling NaN and inf
assert(!isnan(value));
assert(!isinf(value));
if (value == 0)
{
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
buffer[3] = '\0';
}
else
{
if (value < 0)
{
*buffer++ = '-';
value = -value;
}
int length, K;
Grisu2(value, buffer, &length, &K);
Prettify(buffer, length, K);
}
}
} // namespace ieee754
} // namespace util
} // namespace osrm
#endif // IEEE754_HPP
+31 -2
View File
@@ -5,6 +5,7 @@
#define JSON_RENDERER_HPP #define JSON_RENDERER_HPP
#include "util/cast.hpp" #include "util/cast.hpp"
#include "util/ieee754.hpp"
#include "util/string_util.hpp" #include "util/string_util.hpp"
#include "osrm/json_container.hpp" #include "osrm/json_container.hpp"
@@ -21,6 +22,11 @@ namespace util
namespace json namespace json
{ {
namespace
{
constexpr int MAX_FLOAT_STRING_LENGTH = 256;
}
struct Renderer struct Renderer
{ {
explicit Renderer(std::ostream &_out) : out(_out) {} explicit Renderer(std::ostream &_out) : out(_out) {}
@@ -34,8 +40,31 @@ struct Renderer
void operator()(const Number &number) const void operator()(const Number &number) const
{ {
out.precision(10); char buffer[MAX_FLOAT_STRING_LENGTH] = {'\0'};
out << number.value; ieee754::dtoa_milo(number.value, buffer);
// Trucate to 10 decimal places
int pos = 0;
int decimalpos = 0;
while (decimalpos == 0 && pos < MAX_FLOAT_STRING_LENGTH && buffer[pos] != 0)
{
if (buffer[pos] == '.')
{
decimalpos = pos;
break;
}
++pos;
}
while (pos < MAX_FLOAT_STRING_LENGTH && buffer[pos] != 0)
{
if (pos - decimalpos == 10)
{
buffer[pos] = '\0';
break;
}
++pos;
}
out << buffer;
} }
void operator()(const Object &object) const void operator()(const Object &object) const
+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": {
+5 -15
View File
@@ -38,20 +38,10 @@ function setup()
mode.pushing_bike mode.pushing_bike
}, },
barrier_whitelist = Set { barrier_blacklist = Set {
'sump_buster', 'yes',
'bus_trap', 'wall',
'cycle_barrier', 'fence'
'bollard',
'entrance',
'cattle_grid',
'border_control',
'toll_booth',
'sally_port',
'gate',
'lift_gate',
'no',
'block'
}, },
access_tag_whitelist = Set { access_tag_whitelist = Set {
@@ -245,7 +235,7 @@ function process_node(profile, node, result)
else else
local barrier = node:get_value_by_key("barrier") local barrier = node:get_value_by_key("barrier")
if barrier and "" ~= barrier then if barrier and "" ~= barrier then
if not profile.barrier_whitelist[barrier] then if profile.barrier_blacklist[barrier] then
result.barrier = true result.barrier = true
end end
end end
+7
View File
@@ -42,6 +42,10 @@ function setup()
vehicle_height = 2.5, -- in meters, 2.5m is the height of van vehicle_height = 2.5, -- in meters, 2.5m is the height of van
vehicle_width = 1.9, -- in meters, ways with narrow tag are considered narrower than 2.2m vehicle_width = 1.9, -- in meters, ways with narrow tag are considered narrower than 2.2m
-- Size of the vehicle, to be limited mostly by legal restriction of the way
vehicle_length = 4.8, -- in meters, 4.8m is the length of large or familly car
vehicle_weight = 3500, -- in kilograms
-- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other -- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other
suffix_list = { suffix_list = {
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea' 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea'
@@ -276,6 +280,7 @@ function setup()
["de:rural"] = 100, ["de:rural"] = 100,
["de:motorway"] = 0, ["de:motorway"] = 0,
["dk:rural"] = 80, ["dk:rural"] = 80,
["fr:rural"] = 80,
["gb:nsl_single"] = (60*1609)/1000, ["gb:nsl_single"] = (60*1609)/1000,
["gb:nsl_dual"] = (70*1609)/1000, ["gb:nsl_dual"] = (70*1609)/1000,
["gb:motorway"] = (70*1609)/1000, ["gb:motorway"] = (70*1609)/1000,
@@ -387,6 +392,8 @@ function process_way(profile, way, result, relations)
WayHandlers.avoid_ways, WayHandlers.avoid_ways,
WayHandlers.handle_height, WayHandlers.handle_height,
WayHandlers.handle_width, WayHandlers.handle_width,
WayHandlers.handle_length,
WayHandlers.handle_weight,
-- determine access status by checking our hierarchy of -- determine access status by checking our hierarchy of
-- access tags, e.g: motorcar, motor_vehicle, vehicle -- access tags, e.g: motorcar, motor_vehicle, vehicle
+5 -14
View File
@@ -24,19 +24,10 @@ function setup()
default_speed = walking_speed, default_speed = walking_speed,
oneway_handling = 'specific', -- respect 'oneway:foot' but not 'oneway' oneway_handling = 'specific', -- respect 'oneway:foot' but not 'oneway'
barrier_whitelist = Set { barrier_blacklist = Set {
'cycle_barrier', 'yes',
'bollard', 'wall',
'entrance', 'fence'
'cattle_grid',
'border_control',
'toll_booth',
'sally_port',
'gate',
'lift_gate',
'no',
'kerb',
'block'
}, },
access_tag_whitelist = Set { access_tag_whitelist = Set {
@@ -157,7 +148,7 @@ function process_node(profile, node, result)
local bollard = node:get_value_by_key("bollard") local bollard = node:get_value_by_key("bollard")
local rising_bollard = bollard and "rising" == bollard local rising_bollard = bollard and "rising" == bollard
if not profile.barrier_whitelist[barrier] and not rising_bollard then if profile.barrier_blacklist[barrier] and not rising_bollard then
result.barrier = true result.barrier = true
end end
end end
+20 -26
View File
@@ -5,6 +5,7 @@ Measure = {}
-- measurements conversion constants -- measurements conversion constants
local inch_to_meters = 0.0254 local inch_to_meters = 0.0254
local feet_to_inches = 12 local feet_to_inches = 12
local pound_to_kilograms = 0.45359237
--- Parse string as a height in meters. --- Parse string as a height in meters.
--- according to http://wiki.openstreetmap.org/wiki/Key:maxheight --- according to http://wiki.openstreetmap.org/wiki/Key:maxheight
@@ -25,33 +26,19 @@ function Measure.parse_value_meters(value)
end end
end end
--- according to http://wiki.openstreetmap.org/wiki/Map_Features/Units#Explicit_specifications --- Parse weight value in kilograms.
local tonns_parse_patterns = Sequence { --- according to https://wiki.openstreetmap.org/wiki/Key:maxweight
"%d+",
"%d+.%d+",
"%d+.%d+ ?t"
}
local kg_parse_patterns = Sequence {
"%d+ ?kg"
}
--- Parse weight value in kilograms
function Measure.parse_value_kilograms(value) function Measure.parse_value_kilograms(value)
-- try to parse kilograms local n = tonumber(value:gsub(",", "."):match("%d+%.?%d*"))
for i, templ in ipairs(kg_parse_patterns) do if n then
m = string.match(value, templ) if string.match(value, "lbs") then
if m then n = n * pound_to_kilograms
return tonumber(m) elseif string.match(value, "kg") then
end -- n = n
end else -- Default, metric tons
n = n * 1000
-- try to parse tonns
for i, templ in ipairs(tonns_parse_patterns) do
m = string.match(value, templ)
if m then
return tonumber(m) * 1000
end end
return n
end end
end end
@@ -83,7 +70,14 @@ function Measure.get_max_width(raw_value)
end end
end end
--- Get maxweight of specified way in kilogramms --- Get maxlength of specified way in meters.
function Measure.get_max_length(raw_value)
if raw_value then
return Measure.parse_value_meters(raw_value)
end
end
--- Get maxweight of specified way in kilogramms.
function Measure.get_max_weight(raw_value) function Measure.get_max_weight(raw_value)
if raw_value then if raw_value then
return Measure.parse_value_kilograms(raw_value) return Measure.parse_value_kilograms(raw_value)
+32
View File
@@ -511,6 +511,38 @@ function WayHandlers.handle_width(profile,way,result,data)
end end
end end
-- handle maxweight tags
function WayHandlers.handle_weight(profile,way,result,data)
local keys = Sequence { 'maxweight' }
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
forward = Measure.get_max_weight(forward)
backward = Measure.get_max_weight(backward)
if forward and forward < profile.vehicle_weight then
result.forward_mode = mode.inaccessible
end
if backward and backward < profile.vehicle_weight then
result.backward_mode = mode.inaccessible
end
end
-- handle maxlength tags
function WayHandlers.handle_length(profile,way,result,data)
local keys = Sequence { 'maxlength' }
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
forward = Measure.get_max_length(forward)
backward = Measure.get_max_length(backward)
if forward and forward < profile.vehicle_length then
result.forward_mode = mode.inaccessible
end
if backward and backward < profile.vehicle_length then
result.backward_mode = mode.inaccessible
end
end
-- handle oneways tags -- handle oneways tags
function WayHandlers.oneway(profile,way,result,data) function WayHandlers.oneway(profile,way,result,data)
if not profile.oneway_handling then if not profile.oneway_handling then
+1
View File
@@ -621,6 +621,7 @@ RouteSteps collapseSegregatedTurnInstructions(RouteSteps steps)
// else if the current step is segregated and the next step is not segregated // else if the current step is segregated and the next step is not segregated
// and the next step is not a roundabout then combine with turn adjustment // and the next step is not a roundabout then combine with turn adjustment
else if (curr_step->is_segregated && !next_step->is_segregated && else if (curr_step->is_segregated && !next_step->is_segregated &&
!hasRoundaboutType(curr_step->maneuver.instruction) &&
!hasRoundaboutType(next_step->maneuver.instruction)) !hasRoundaboutType(next_step->maneuver.instruction))
{ {
// Determine if u-turn // Determine if u-turn
-1
View File
@@ -430,7 +430,6 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
util::UnbufferedLog log; util::UnbufferedLog log;
log << "Sorting edges by renumbered start ... "; log << "Sorting edges by renumbered start ... ";
TIMER_START(sort_edges_by_renumbered_start); TIMER_START(sort_edges_by_renumbered_start);
std::mutex name_data_mutex;
tbb::parallel_sort(all_edges_list.begin(), tbb::parallel_sort(all_edges_list.begin(),
all_edges_list.end(), all_edges_list.end(),
CmpEdgeByInternalSourceTargetAndName{ CmpEdgeByInternalSourceTargetAndName{
+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
+1 -1
View File
@@ -66,7 +66,7 @@ struct RegionHandle
{ {
std::unique_ptr<SharedMemory> memory; std::unique_ptr<SharedMemory> memory;
char *data_ptr; char *data_ptr;
std::uint8_t shm_key; std::uint16_t shm_key;
}; };
auto setupRegion(SharedRegionRegister &shared_register, const DataLayout &layout) auto setupRegion(SharedRegionRegister &shared_register, const DataLayout &layout)
+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 -1
View File
@@ -82,7 +82,8 @@ void springClean()
} }
else else
{ {
for (auto key : util::irange<std::uint8_t>(0, storage::SharedRegionRegister::MAX_SHM_KEYS)) for (auto key : util::irange<storage::SharedRegionRegister::RegionID>(
0, storage::SharedRegionRegister::MAX_SHM_KEYS))
{ {
deleteRegion(key); deleteRegion(key);
} }
+1
View File
@@ -159,6 +159,7 @@
{"key": "maxspeed", "value": "DE:rural"}, {"key": "maxspeed", "value": "DE:rural"},
{"key": "maxspeed", "value": "DE:motorway"}, {"key": "maxspeed", "value": "DE:motorway"},
{"key": "maxspeed", "value": "DK:rural"}, {"key": "maxspeed", "value": "DK:rural"},
{"key": "maxspeed", "value": "FR:rural"},
{"key": "maxspeed", "value": "GB:nsl_single"}, {"key": "maxspeed", "value": "GB:nsl_single"},
{"key": "maxspeed", "value": "GB:nsl_dual"}, {"key": "maxspeed", "value": "GB:nsl_dual"},
{"key": "maxspeed", "value": "GB:motorway"}, {"key": "maxspeed", "value": "GB:motorway"},
+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) {