2014-08-26 10:35:43 -04:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
Redistributions of source code must retain the above copyright notice, this list
|
|
|
|
of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright notice, this
|
|
|
|
list of conditions and the following disclaimer in the documentation and/or
|
|
|
|
other materials provided with the distribution.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
|
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "RestrictionParser.h"
|
|
|
|
#include "ExtractionWay.h"
|
|
|
|
#include "ScriptingEnvironment.h"
|
|
|
|
|
2014-08-29 05:38:53 -04:00
|
|
|
#include "../DataStructures/ExternalMemoryNode.h"
|
2014-08-26 10:35:43 -04:00
|
|
|
#include "../Util/LuaUtil.h"
|
|
|
|
#include "../Util/OSRMException.h"
|
2014-10-13 07:53:06 -04:00
|
|
|
#include "../Util/simple_logger.hpp"
|
2014-08-26 10:35:43 -04:00
|
|
|
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#include <boost/algorithm/string/regex.hpp>
|
|
|
|
#include <boost/ref.hpp>
|
|
|
|
#include <boost/regex.hpp>
|
|
|
|
|
2014-11-20 04:46:14 -05:00
|
|
|
namespace
|
|
|
|
{
|
2014-11-20 08:55:43 -05:00
|
|
|
int lua_error_callback(lua_State *lua_state)
|
2014-09-22 05:42:52 -04:00
|
|
|
{
|
2014-11-20 08:55:43 -05:00
|
|
|
luabind::object error_msg(luabind::from_stack(lua_state, -1));
|
2014-09-22 05:42:52 -04:00
|
|
|
std::ostringstream error_stream;
|
|
|
|
error_stream << error_msg;
|
|
|
|
throw OSRMException("ERROR occured in profile script:\n" + error_stream.str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-18 10:54:48 -05:00
|
|
|
RestrictionParser::RestrictionParser(lua_State *lua_state)
|
|
|
|
: /*lua_state(scripting_environment.getLuaState()),*/ use_turn_restrictions(true)
|
2014-08-26 10:35:43 -04:00
|
|
|
{
|
2014-11-18 10:54:48 -05:00
|
|
|
ReadUseRestrictionsSetting(lua_state);
|
2014-09-22 05:42:52 -04:00
|
|
|
|
|
|
|
if (use_turn_restrictions)
|
|
|
|
{
|
2014-11-18 10:54:48 -05:00
|
|
|
ReadRestrictionExceptions(lua_state);
|
2014-09-22 05:42:52 -04:00
|
|
|
}
|
2014-08-26 10:35:43 -04:00
|
|
|
}
|
|
|
|
|
2014-11-18 10:54:48 -05:00
|
|
|
void RestrictionParser::ReadUseRestrictionsSetting(lua_State *lua_state)
|
2014-08-26 10:35:43 -04:00
|
|
|
{
|
2014-11-20 08:58:32 -05:00
|
|
|
if (0 == luaL_dostring(lua_state, "return use_turn_restrictions\n") && lua_isboolean(lua_state, -1))
|
2014-08-26 10:35:43 -04:00
|
|
|
{
|
2014-11-20 08:58:32 -05:00
|
|
|
use_turn_restrictions = lua_toboolean(lua_state, -1);
|
2014-08-26 10:35:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (use_turn_restrictions)
|
|
|
|
{
|
|
|
|
SimpleLogger().Write() << "Using turn restrictions";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SimpleLogger().Write() << "Ignoring turn restrictions";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-18 10:54:48 -05:00
|
|
|
void RestrictionParser::ReadRestrictionExceptions(lua_State *lua_state)
|
2014-08-26 10:35:43 -04:00
|
|
|
{
|
|
|
|
if (lua_function_exists(lua_state, "get_exceptions"))
|
|
|
|
{
|
2014-09-22 05:42:52 -04:00
|
|
|
luabind::set_pcall_callback(&lua_error_callback);
|
2014-08-26 10:35:43 -04:00
|
|
|
// get list of turn restriction exceptions
|
|
|
|
luabind::call_function<void>(
|
|
|
|
lua_state, "get_exceptions", boost::ref(restriction_exceptions));
|
|
|
|
const unsigned exception_count = restriction_exceptions.size();
|
|
|
|
SimpleLogger().Write() << "Found " << exception_count
|
|
|
|
<< " exceptions to turn restrictions:";
|
|
|
|
for (const std::string &str : restriction_exceptions)
|
|
|
|
{
|
|
|
|
SimpleLogger().Write() << " " << str;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SimpleLogger().Write() << "Found no exceptions to turn restrictions";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-20 04:46:14 -05:00
|
|
|
mapbox::util::optional<InputRestrictionContainer>
|
2014-11-20 08:55:43 -05:00
|
|
|
RestrictionParser::TryParse(osmium::Relation &relation) const
|
2014-08-26 10:35:43 -04:00
|
|
|
{
|
|
|
|
// return if turn restrictions should be ignored
|
|
|
|
if (!use_turn_restrictions)
|
|
|
|
{
|
2014-08-29 05:27:51 -04:00
|
|
|
return mapbox::util::optional<InputRestrictionContainer>();
|
2014-08-26 10:35:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
osmium::tags::KeyPrefixFilter filter(false);
|
|
|
|
filter.add(true, "restriction");
|
|
|
|
|
|
|
|
const osmium::TagList &tag_list = relation.tags();
|
|
|
|
|
|
|
|
osmium::tags::KeyPrefixFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
|
|
|
|
osmium::tags::KeyPrefixFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
|
|
|
|
|
|
|
|
// if it's a restriction, continue;
|
|
|
|
if (std::distance(fi_begin, fi_end) == 0)
|
|
|
|
{
|
2014-08-29 05:27:51 -04:00
|
|
|
return mapbox::util::optional<InputRestrictionContainer>();
|
2014-08-26 10:35:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// check if the restriction should be ignored
|
|
|
|
const char *except = relation.get_value_by_key("except");
|
|
|
|
if (except != nullptr)
|
|
|
|
{
|
|
|
|
if (ShouldIgnoreRestriction(except))
|
|
|
|
{
|
2014-08-29 05:27:51 -04:00
|
|
|
return mapbox::util::optional<InputRestrictionContainer>();
|
2014-08-26 10:35:43 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_only_restriction = false;
|
|
|
|
|
|
|
|
for (auto iter = fi_begin; iter != fi_end; ++iter)
|
|
|
|
{
|
|
|
|
if (std::string("restriction") == iter->key() ||
|
|
|
|
std::string("restriction::hgv") == iter->key())
|
|
|
|
{
|
|
|
|
const std::string restriction_value(iter->value());
|
|
|
|
|
|
|
|
if (restriction_value.find("only_") == 0)
|
|
|
|
{
|
|
|
|
is_only_restriction = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
InputRestrictionContainer restriction_container(is_only_restriction);
|
|
|
|
|
|
|
|
for (const auto &member : relation.members())
|
|
|
|
{
|
|
|
|
const char *role = member.role();
|
|
|
|
if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (member.type())
|
|
|
|
{
|
|
|
|
case osmium::item_type::node:
|
|
|
|
// Make sure nodes appear only in the role if a via node
|
|
|
|
if (0 == strcmp("from", role) || 0 == strcmp("to", role))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
BOOST_ASSERT(0 == strcmp("via", role));
|
|
|
|
// set the via node id
|
|
|
|
// SimpleLogger().Write() << "via: " << member.ref();
|
|
|
|
|
|
|
|
restriction_container.restriction.via.node = member.ref();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case osmium::item_type::way:
|
|
|
|
BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
|
|
|
|
0 == strcmp("via", role));
|
|
|
|
if (0 == strcmp("from", role))
|
|
|
|
{
|
|
|
|
// SimpleLogger().Write() << "from: " << member.ref();
|
|
|
|
restriction_container.restriction.from.way = member.ref();
|
|
|
|
}
|
|
|
|
else if (0 == strcmp("to", role))
|
|
|
|
{
|
|
|
|
// SimpleLogger().Write() << "to: " << member.ref();
|
|
|
|
restriction_container.restriction.to.way = member.ref();
|
|
|
|
}
|
|
|
|
else if (0 == strcmp("via", role))
|
|
|
|
{
|
|
|
|
// not yet suppported
|
|
|
|
// restriction_container.restriction.via.way = member.ref();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case osmium::item_type::relation:
|
|
|
|
// not yet supported, but who knows what the future holds...
|
|
|
|
continue;
|
|
|
|
BOOST_ASSERT(false);
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BOOST_ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SimpleLogger().Write() << (restriction_container.restriction.flags.is_only ? "only" : "no")
|
|
|
|
// << "-restriction "
|
|
|
|
// << "<" << restriction_container.restriction.from.node << "->"
|
2014-11-20 04:46:14 -05:00
|
|
|
// << restriction_container.restriction.via.node << "->" <<
|
|
|
|
// restriction_container.restriction.to.node
|
2014-08-26 10:35:43 -04:00
|
|
|
// << ">";
|
|
|
|
|
2014-08-29 05:27:51 -04:00
|
|
|
return mapbox::util::optional<InputRestrictionContainer>(restriction_container);
|
2014-08-26 10:35:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
|
|
|
|
{
|
|
|
|
// should this restriction be ignored? yes if there's an overlap between:
|
|
|
|
// a) the list of modes in the except tag of the restriction
|
|
|
|
// (except_tag_string), eg: except=bus;bicycle
|
|
|
|
// b) the lua profile defines a hierachy of modes,
|
|
|
|
// eg: [access, vehicle, bicycle]
|
|
|
|
|
|
|
|
if (except_tag_string.empty())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Be warned, this is quadratic work here, but we assume that
|
|
|
|
// only a few exceptions are actually defined.
|
|
|
|
std::vector<std::string> exceptions;
|
|
|
|
boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
|
|
|
|
for (std::string ¤t_string : exceptions)
|
|
|
|
{
|
|
|
|
const auto string_iterator =
|
|
|
|
std::find(restriction_exceptions.begin(), restriction_exceptions.end(), current_string);
|
|
|
|
if (restriction_exceptions.end() != string_iterator)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|