Conditional turn restriction support (#3841)

* optionally include condition and via node coords in InputRestrictionContainer

* only write conditionals to disk, custom serialization for restrictions

* conditional turn lookup, reuse timezone validation from
extract-conditionals

* adapt updater to use coordinates/osm ids, remove internal to external map

* add utc time now parameter to contraction

* only compile timezone code where libshp is found, adapt test running

* slight refactor, more tests

* catch invalid via nodes in restriction parsing, set default cucumber
origin to guinée

* add another run to test mld routed paths

* cosmetic review changes

* Simplify Timezoner for windows build

* Split declaration and parsing parts for opening hours

* adjust conditional tests to run without shapefiles

* always include parse conditionals option

* Adjust travis timeout

* Added dummy TZ shapefile with test timezone polygons

* [skip ci] update changelog
This commit is contained in:
Karen Shea
2017-05-11 12:13:52 +02:00
committed by GitHub
parent 12f47708cd
commit 799a677e7a
42 changed files with 2116 additions and 1310 deletions
@@ -52,13 +52,13 @@ namespace lookup
#pragma pack(push, 1)
struct TurnIndexBlock
{
OSMNodeID from_id;
OSMNodeID via_id;
OSMNodeID to_id;
NodeID from_id;
NodeID via_id;
NodeID to_id;
};
#pragma pack(pop)
static_assert(std::is_trivial<TurnIndexBlock>::value, "TurnIndexBlock is not trivial");
static_assert(sizeof(TurnIndexBlock) == 24, "TurnIndexBlock is not packed correctly");
static_assert(sizeof(TurnIndexBlock) == 12, "TurnIndexBlock is not packed correctly");
} // ns lookup
struct NodeBasedGraphToEdgeBasedGraphMappingWriter; // fwd. decl
+4 -3
View File
@@ -40,7 +40,7 @@ class ExtractionContainers
void PrepareEdges(ScriptingEnvironment &scripting_environment);
void WriteNodes(storage::io::FileWriter &file_out) const;
void WriteRestrictions(const std::string &restrictions_file_name) const;
void WriteRestrictions(const std::string &restrictions_file_name);
void WriteEdges(storage::io::FileWriter &file_out) const;
void WriteCharData(const std::string &file_name);
@@ -48,7 +48,7 @@ class ExtractionContainers
using STXXLNodeIDVector = stxxl::vector<OSMNodeID>;
using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
using STXXLEdgeVector = stxxl::vector<InternalExtractorEdge>;
using STXXLRestrictionsVector = stxxl::vector<InputRestrictionContainer>;
using RestrictionsVector = std::vector<InputRestrictionContainer>;
using STXXLWayIDStartEndVector = stxxl::vector<FirstAndLastSegmentOfWay>;
using STXXLNameCharData = stxxl::vector<unsigned char>;
using STXXLNameOffsets = stxxl::vector<unsigned>;
@@ -59,10 +59,11 @@ class ExtractionContainers
STXXLNameCharData name_char_data;
STXXLNameOffsets name_offsets;
// an adjacency array containing all turn lane masks
STXXLRestrictionsVector restrictions_list;
RestrictionsVector restrictions_list;
STXXLWayIDStartEndVector way_start_end_id_list;
std::unordered_map<OSMNodeID, NodeID> external_to_internal_node_id_map;
unsigned max_internal_node_id;
std::vector<TurnRestriction> unconditional_turn_restrictions;
ExtractionContainers();
+5 -1
View File
@@ -56,6 +56,9 @@ class Extractor
private:
ExtractorConfig config;
std::vector<TurnRestriction> ParseOSMData(ScriptingEnvironment &scripting_environment,
const unsigned number_of_threads);
std::pair<std::size_t, EdgeID>
BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
std::vector<util::Coordinate> &coordinates,
@@ -64,7 +67,8 @@ class Extractor
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
const std::string &intersection_class_output_file);
const std::string &intersection_class_output_file,
std::vector<TurnRestriction> &turn_restrictions);
void WriteProfileProperties(const std::string &output_path,
const ProfileProperties &properties) const;
void FindComponents(unsigned max_edge_id,
+1
View File
@@ -112,6 +112,7 @@ struct ExtractorConfig
std::string turn_penalties_index_path;
bool use_metadata;
bool parse_conditionals;
};
}
}
+4
View File
@@ -1,6 +1,8 @@
#ifndef RESTRICTION_HPP
#define RESTRICTION_HPP
#include "util/coordinate.hpp"
#include "util/opening_hours.hpp"
#include "util/typedefs.hpp"
#include <limits>
@@ -20,6 +22,8 @@ struct TurnRestriction
WayOrNode from;
WayOrNode to;
std::vector<util::OpeningHours> condition;
struct Bits
{ // mostly unused
Bits()
+1 -1
View File
@@ -95,7 +95,7 @@ class RestrictionMap
return;
}
// find all potential start edges. It is more efficent to get a (small) list
// find all potential start edges. It is more efficient to get a (small) list
// of potential start edges than iterating over all buckets
std::vector<NodeID> predecessors;
for (const EdgeID current_edge_id : graph.GetAdjacentEdgeRange(node_u))
+6 -3
View File
@@ -41,14 +41,17 @@ class ScriptingEnvironment;
class RestrictionParser
{
public:
RestrictionParser(ScriptingEnvironment &scripting_environment);
boost::optional<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
RestrictionParser(bool use_turn_restrictions,
bool parse_conditionals,
std::vector<std::string> &restrictions);
std::vector<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
private:
bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
std::vector<std::string> restrictions;
bool use_turn_restrictions;
bool parse_conditionals;
std::vector<std::string> restrictions;
};
}
}
+49
View File
@@ -4,6 +4,7 @@
#include "extractor/datasources.hpp"
#include "extractor/nbg_to_ebg.hpp"
#include "extractor/node_data_container.hpp"
#include "extractor/restriction.hpp"
#include "extractor/segment_data_container.hpp"
#include "extractor/turn_data_container.hpp"
@@ -19,6 +20,7 @@ namespace extractor
namespace serialization
{
// read/write for datasources file
inline void read(storage::io::FileReader &reader, Datasources &sources)
{
reader.ReadInto(sources);
@@ -29,6 +31,7 @@ inline void write(storage::io::FileWriter &writer, Datasources &sources)
writer.WriteFrom(sources);
}
// read/write for segment data file
template <storage::Ownership Ownership>
inline void read(storage::io::FileReader &reader,
detail::SegmentDataContainerImpl<Ownership> &segment_data)
@@ -55,6 +58,7 @@ inline void write(storage::io::FileWriter &writer,
storage::serialization::write(writer, segment_data.datasources);
}
// read/write for turn data file
template <storage::Ownership Ownership>
inline void read(storage::io::FileReader &reader,
detail::TurnDataContainerImpl<Ownership> &turn_data_container)
@@ -94,6 +98,51 @@ inline void write(storage::io::FileWriter &writer,
storage::serialization::write(writer, node_data_container.name_ids);
storage::serialization::write(writer, node_data_container.travel_modes);
}
// read/write for conditional turn restrictions file
inline void read(storage::io::FileReader &reader, std::vector<TurnRestriction> &restrictions)
{
auto num_indices = reader.ReadElementCount64();
restrictions.reserve(num_indices);
TurnRestriction restriction;
while (num_indices > 0)
{
bool is_only;
reader.ReadInto(restriction.via);
reader.ReadInto(restriction.from);
reader.ReadInto(restriction.to);
reader.ReadInto(is_only);
auto num_conditions = reader.ReadElementCount64();
restriction.condition.resize(num_conditions);
for (uint64_t i = 0; i < num_conditions; i++)
{
reader.ReadInto(restriction.condition[i].modifier);
storage::serialization::read(reader, restriction.condition[i].times);
storage::serialization::read(reader, restriction.condition[i].weekdays);
storage::serialization::read(reader, restriction.condition[i].monthdays);
}
restriction.flags.is_only = is_only;
restrictions.push_back(std::move(restriction));
num_indices--;
}
}
inline void write(storage::io::FileWriter &writer, const TurnRestriction &restriction)
{
writer.WriteOne(restriction.via);
writer.WriteOne(restriction.from);
writer.WriteOne(restriction.to);
writer.WriteOne(restriction.flags.is_only);
writer.WriteElementCount64(restriction.condition.size());
for (const auto &c : restriction.condition)
{
writer.WriteOne(c.modifier);
storage::serialization::write(writer, c.times);
storage::serialization::write(writer, c.weekdays);
storage::serialization::write(writer, c.monthdays);
}
}
}
}
}
+3 -4
View File
@@ -63,10 +63,9 @@ struct Turn final
: from(from), via(via), to(to)
{
}
template <typename Other>
Turn(const Other &turn)
: from(static_cast<std::uint64_t>(turn.from_id)),
via(static_cast<std::uint64_t>(turn.via_id)), to(static_cast<std::uint64_t>(turn.to_id))
Turn(const OSMNodeID &from_id, const OSMNodeID &via_id, const OSMNodeID &to_id)
: from(static_cast<std::uint64_t>(from_id)), via(static_cast<std::uint64_t>(via_id)),
to(static_cast<std::uint64_t>(to_id))
{
}
bool operator<(const Turn &rhs) const
+1
View File
@@ -5,6 +5,7 @@
#include "extractor/edge_based_edge.hpp"
#include <chrono>
#include <vector>
namespace osrm
+5
View File
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/filesystem/path.hpp>
#include <chrono>
#include <string>
namespace osrm
@@ -53,6 +54,7 @@ struct UpdaterConfig final
rtree_leaf_path = osrm_input_path.string() + ".fileIndex";
datasource_names_path = osrm_input_path.string() + ".datasource_names";
profile_properties_path = osrm_input_path.string() + ".properties";
turn_restrictions_path = osrm_input_path.string() + ".restrictions";
}
boost::filesystem::path osrm_input_path;
@@ -69,11 +71,14 @@ struct UpdaterConfig final
std::string rtree_leaf_path;
double log_edge_updates_factor;
std::time_t valid_now;
std::vector<std::string> segment_speed_lookup_paths;
std::vector<std::string> turn_penalty_lookup_paths;
std::string datasource_names_path;
std::string profile_properties_path;
std::string turn_restrictions_path;
std::string tz_file_path;
};
}
}
+3 -85
View File
@@ -1,9 +1,8 @@
#ifndef OSRM_CONDITIONAL_RESTRICTIONS_HPP
#define OSRM_CONDITIONAL_RESTRICTIONS_HPP
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <vector>
namespace osrm
{
@@ -20,88 +19,7 @@ struct ConditionalRestriction
std::string condition;
};
#ifndef NDEBUG
// Debug output stream operators for use with BOOST_SPIRIT_DEBUG
inline std::ostream &operator<<(std::ostream &stream, const ConditionalRestriction &restriction)
{
return stream << restriction.value << "=" << restriction.condition;
}
#endif
}
}
BOOST_FUSION_ADAPT_STRUCT(osrm::util::ConditionalRestriction,
(std::string, value)(std::string, condition))
namespace osrm
{
namespace util
{
namespace detail
{
namespace
{
namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi;
}
template <typename Iterator, typename Skipper = qi::blank_type>
struct conditional_restrictions_grammar
: qi::grammar<Iterator, Skipper, std::vector<ConditionalRestriction>()>
{
// http://wiki.openstreetmap.org/wiki/Conditional_restrictions
conditional_restrictions_grammar() : conditional_restrictions_grammar::base_type(restrictions)
{
using qi::_1;
using qi::_val;
using qi::lit;
// clang-format off
restrictions
= restriction % ';'
;
restriction
= value >> '@' >> condition
;
value
= +(qi::char_ - '@')
;
condition
= *qi::blank
>> (lit('(') >> qi::as_string[qi::no_skip[*~lit(')')]][_val = _1] >> lit(')')
| qi::as_string[qi::no_skip[*~lit(';')]][_val = _1]
)
;
// clang-format on
BOOST_SPIRIT_DEBUG_NODES((restrictions)(restriction)(value)(condition));
}
qi::rule<Iterator, Skipper, std::vector<ConditionalRestriction>()> restrictions;
qi::rule<Iterator, Skipper, ConditionalRestriction()> restriction;
qi::rule<Iterator, Skipper, std::string()> value, condition;
};
}
inline std::vector<ConditionalRestriction> ParseConditionalRestrictions(const std::string &str)
{
auto it(str.begin()), end(str.end());
const detail::conditional_restrictions_grammar<decltype(it)> static grammar;
std::vector<ConditionalRestriction> result;
bool ok = boost::spirit::qi::phrase_parse(it, end, grammar, boost::spirit::qi::blank, result);
if (!ok || it != end)
return std::vector<ConditionalRestriction>();
return result;
}
std::vector<ConditionalRestriction> ParseConditionalRestrictions(const std::string &str);
} // util
} // osrm
-18
View File
@@ -31,24 +31,6 @@ namespace osrm
namespace util
{
/**
* Reads the .restrictions file and loads it to a vector.
* The since the restrictions reference nodes using their external node id,
* we need to renumber it to the new internal id.
*/
inline unsigned loadRestrictionsFromFile(storage::io::FileReader &file_reader,
std::vector<extractor::TurnRestriction> &restriction_list)
{
auto number_of_usable_restrictions = file_reader.ReadElementCount64();
restriction_list.resize(number_of_usable_restrictions);
if (number_of_usable_restrictions > 0)
{
file_reader.ReadInto(restriction_list.data(), number_of_usable_restrictions);
}
return number_of_usable_restrictions;
}
/**
* Reads the beginning of an .osrm file and produces:
* - barrier nodes
+3 -423
View File
@@ -2,17 +2,9 @@
#define OSRM_OPENING_HOURS_HPP
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/io/ios_state.hpp>
#include <algorithm>
#include <cctype>
#include <iomanip>
#include <iterator>
#include <limits>
#include <string>
#include <vector>
namespace osrm
{
@@ -219,421 +211,9 @@ struct OpeningHours
Modifier modifier;
};
#ifndef NDEBUG
// Debug output stream operators for use with BOOST_SPIRIT_DEBUG
inline std::ostream &operator<<(std::ostream &stream, const OpeningHours::Modifier value)
{
switch (value)
{
case OpeningHours::unknown:
return stream << "unknown";
case OpeningHours::open:
return stream << "open";
case OpeningHours::closed:
return stream << "closed";
case OpeningHours::off:
return stream << "off";
case OpeningHours::is24_7:
return stream << "24/7";
}
return stream;
}
std::vector<OpeningHours> ParseOpeningHours(const std::string &str);
inline std::ostream &operator<<(std::ostream &stream, const OpeningHours::Time::Event value)
{
switch (value)
{
case OpeningHours::Time::dawn:
return stream << "dawn";
case OpeningHours::Time::sunrise:
return stream << "sunrise";
case OpeningHours::Time::sunset:
return stream << "sunset";
case OpeningHours::Time::dusk:
return stream << "dusk";
default:
break;
}
return stream;
}
inline std::ostream &operator<<(std::ostream &stream, const OpeningHours::Time &value)
{
boost::io::ios_flags_saver ifs(stream);
if (value.event == OpeningHours::Time::invalid)
return stream << "???";
if (value.event == OpeningHours::Time::none)
return stream << std::setfill('0') << std::setw(2) << value.minutes / 60 << ":"
<< std::setfill('0') << std::setw(2) << value.minutes % 60;
stream << value.event;
if (value.minutes != 0)
stream << value.minutes;
return stream;
}
inline std::ostream &operator<<(std::ostream &stream, const OpeningHours::TimeSpan &value)
{
return stream << value.from << "-" << value.to;
}
inline std::ostream &operator<<(std::ostream &stream, const OpeningHours::Monthday &value)
{
bool empty = true;
if (value.year != 0)
{
stream << (int)value.year;
empty = false;
};
if (value.month != 0)
{
stream << (empty ? "" : "/") << (int)value.month;
empty = false;
};
if (value.day != 0)
{
stream << (empty ? "" : "/") << (int)value.day;
};
return stream;
}
inline std::ostream &operator<<(std::ostream &stream, const OpeningHours::WeekdayRange &value)
{
boost::io::ios_flags_saver ifs(stream);
return stream << std::hex << std::setfill('0') << std::setw(2) << value.weekdays;
}
inline std::ostream &operator<<(std::ostream &stream, const OpeningHours::MonthdayRange &value)
{
return stream << value.from << "-" << value.to;
}
inline std::ostream &operator<<(std::ostream &stream, const OpeningHours &value)
{
if (value.modifier == OpeningHours::is24_7)
return stream << OpeningHours::is24_7;
for (auto x : value.monthdays)
stream << x << ", ";
for (auto x : value.weekdays)
stream << x << ", ";
for (auto x : value.times)
stream << x << ", ";
return stream << " |" << value.modifier << "|";
}
#endif
namespace detail
{
namespace
{
namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi;
}
template <typename Iterator, typename Skipper = qi::blank_type>
struct opening_hours_grammar : qi::grammar<Iterator, Skipper, std::vector<OpeningHours>()>
{
// http://wiki.openstreetmap.org/wiki/Key:opening_hours/specification
opening_hours_grammar() : opening_hours_grammar::base_type(time_domain)
{
using qi::_1;
using qi::_a;
using qi::_b;
using qi::_c;
using qi::_r1;
using qi::_pass;
using qi::_val;
using qi::eoi;
using qi::lit;
using qi::char_;
using qi::uint_;
using oh = osrm::util::OpeningHours;
// clang-format off
// General syntax
time_domain = rule_sequence[ph::push_back(_val, _1)] % any_rule_separator;
rule_sequence
= lit("24/7")[ph::bind(&oh::modifier, _val) = oh::is24_7]
| (selector_sequence[_val = _1] >> -rule_modifier[ph::bind(&oh::modifier, _val) = _1] >> -comment)
| comment
;
any_rule_separator = char_(';') | lit("||") | additional_rule_separator;
additional_rule_separator = char_(',');
// Rule modifiers
rule_modifier.add
("unknown", oh::unknown)
("open", oh::open)
("closed", oh::closed)
("off", oh::off)
;
// Selectors
selector_sequence = (wide_range_selectors(_a) >> small_range_selectors(_a))[_val = _a];
wide_range_selectors
= (-monthday_selector(_r1)
>> -year_selector(_r1)
>> -week_selector(_r1) // TODO week_selector
) >> -lit(':')
;
small_range_selectors = -(weekday_selector(_r1) >> (&~lit(',') | eoi)) >> -time_selector(_r1);
// Time selector
time_selector = (timespan % ',')[ph::bind(&OpeningHours::times, _r1) = _1];
timespan
= (time[_a = _1]
>> -(lit('+')[_b = ph::construct<OpeningHours::Time>(24, 0)]
| ('-' >> extended_time[_b = _1]
>> -('+' | '/' >> (minute | hour_minutes))))
)[_val = ph::construct<OpeningHours::TimeSpan>(_a, _b)]
;
time = hour_minutes | variable_time;
extended_time = extended_hour_minutes | variable_time;
variable_time
= event[_val = ph::construct<OpeningHours::Time>(_1)]
| ('(' >> event[_a = _1] >> plus_or_minus[_b = _1] >> hour_minutes[_c = _1] >> ')')
[_val = ph::construct<OpeningHours::Time>(_a, _b, _c)]
;
event.add
("dawn", OpeningHours::Time::dawn)
("sunrise", OpeningHours::Time::sunrise)
("sunset", OpeningHours::Time::sunset)
("dusk", OpeningHours::Time::dusk)
;
// Weekday selector
weekday_selector
= (holiday_sequence(_r1) >> -(char_(", ") >> weekday_sequence(_r1)))
| (weekday_sequence(_r1) >> -(char_(", ") >> holiday_sequence(_r1)))
;
weekday_sequence = (weekday_range % ',')[ph::bind(&OpeningHours::weekdays, _r1) = _1];
weekday_range
= wday[_a = _1, _b = _1]
>> -(('-' >> wday[_b = _1])
| ('[' >> (nth_entry % ',') >> ']' >> -day_offset))
[_val = ph::construct<OpeningHours::WeekdayRange>(_a, _b)]
;
holiday_sequence = (lit("SH") >> -day_offset) | lit("PH");
nth_entry = nth | nth >> '-' >> nth | '-' >> nth;
nth = char_("12345");
day_offset = plus_or_minus >> uint_ >> lit("days");
// Week selector
week_selector = (lit("week ") >> week) % ',';
week = weeknum >> -('-' >> weeknum >> -('/' >> uint_));
// Month selector
monthday_selector = (monthday_range % ',')[ph::bind(&OpeningHours::monthdays, _r1) = _1];
monthday_range
= (date_from[ph::bind(&OpeningHours::MonthdayRange::from, _val) = _1]
>> -date_offset
>> '-'
>> date_to[ph::bind(&OpeningHours::MonthdayRange::to, _val) = _1]
>> -date_offset)
| (date_from[ph::bind(&OpeningHours::MonthdayRange::from, _val) = _1]
>> -(date_offset
>> -lit('+')[ph::bind(&OpeningHours::MonthdayRange::from, _val) = ph::construct<OpeningHours::Monthday>(-1)]
))
;
date_offset = (plus_or_minus >> wday) | day_offset;
date_from
= ((-year[_a = _1] >> ((month[_b = _1] >> -daynum[_c = _1]) | daynum[_c = _1]))
| variable_date)
[_val = ph::construct<OpeningHours::Monthday>(_a, _b, _c)]
;
date_to
= date_from[_val = _1]
| daynum[_val = ph::construct<OpeningHours::Monthday>(0, 0, _1)]
;
variable_date = lit("easter");
// Year selector
year_selector = (year_range % ',')[ph::bind(&OpeningHours::monthdays, _r1) = _1];
year_range
= year[ph::bind(&OpeningHours::MonthdayRange::from, _val) = ph::construct<OpeningHours::Monthday>(_1)]
>> -(('-' >> year[ph::bind(&OpeningHours::MonthdayRange::to, _val) = ph::construct<OpeningHours::Monthday>(_1)]
>> -('/' >> uint_))
| lit('+')[ph::bind(&OpeningHours::MonthdayRange::to, _val) = ph::construct<OpeningHours::Monthday>(-1)]);
// Basic elements
plus_or_minus = lit('+')[_val = true] | lit('-')[_val = false];
hour = uint2_p[_pass = bind([](unsigned x) { return x <= 24; }, _1), _val = _1];
extended_hour = uint2_p[_pass = bind([](unsigned x) { return x <= 48; }, _1), _val = _1];
minute = uint2_p[_pass = bind([](unsigned x) { return x < 60; }, _1), _val = _1];
hour_minutes =
hour[_a = _1] >> ':' >> minute[_val = ph::construct<OpeningHours::Time>(_a, _1)];
extended_hour_minutes = extended_hour[_a = _1] >> ':' >>
minute[_val = ph::construct<OpeningHours::Time>(_a, _1)];
wday.add
("Su", 0)
("Mo", 1)
("Tu", 2)
("We", 3)
("Th", 4)
("Fr", 5)
("Sa", 6)
;
daynum
= uint2_p[_pass = bind([](unsigned x) { return 01 <= x && x <= 31; }, _1), _val = _1]
>> (&~lit(':') | eoi)
;
weeknum = uint2_p[_pass = bind([](unsigned x) { return 01 <= x && x <= 53; }, _1), _val = _1];
month.add
("Jan", 1)
("Feb", 2)
("Mar", 3)
("Apr", 4)
("May", 5)
("Jun", 6)
("Jul", 7)
("Aug", 8)
("Sep", 9)
("Oct", 10)
("Nov", 11)
("Dec", 12)
;
year = uint4_p[_pass = bind([](unsigned x) { return x > 1900; }, _1), _val = _1];
comment = lit('"') >> *(~qi::char_('"')) >> lit('"');
// clang-format on
BOOST_SPIRIT_DEBUG_NODES((time_domain)(rule_sequence)(any_rule_separator)(
selector_sequence)(wide_range_selectors)(small_range_selectors)(time_selector)(
timespan)(time)(extended_time)(variable_time)(weekday_selector)(weekday_sequence)(
weekday_range)(holiday_sequence)(nth_entry)(nth)(day_offset)(week_selector)(week)(
monthday_selector)(monthday_range)(date_offset)(date_from)(date_to)(variable_date)(
year_selector)(year_range)(plus_or_minus)(hour_minutes)(extended_hour_minutes)(comment)(
hour)(extended_hour)(minute)(daynum)(weeknum)(year));
}
qi::rule<Iterator, Skipper, std::vector<OpeningHours>()> time_domain;
qi::rule<Iterator, Skipper, OpeningHours()> rule_sequence;
qi::rule<Iterator, Skipper, void()> any_rule_separator, additional_rule_separator;
qi::rule<Iterator, Skipper, OpeningHours(), qi::locals<OpeningHours>> selector_sequence;
qi::symbols<char const, OpeningHours::Modifier> rule_modifier;
qi::rule<Iterator, Skipper, void(OpeningHours &)> wide_range_selectors, small_range_selectors,
time_selector, weekday_selector, year_selector, monthday_selector, week_selector;
// Time rules
qi::rule<Iterator,
Skipper,
OpeningHours::TimeSpan(),
qi::locals<OpeningHours::Time, OpeningHours::Time>>
timespan;
qi::rule<Iterator, Skipper, OpeningHours::Time()> time, extended_time;
qi::rule<Iterator,
Skipper,
OpeningHours::Time(),
qi::locals<OpeningHours::Time::Event, bool, OpeningHours::Time>>
variable_time;
qi::rule<Iterator, Skipper, OpeningHours::Time(), qi::locals<unsigned>> hour_minutes,
extended_hour_minutes;
qi::symbols<char const, OpeningHours::Time::Event> event;
qi::rule<Iterator, Skipper, bool()> plus_or_minus;
// Weekday rules
qi::rule<Iterator, Skipper, void(OpeningHours &)> weekday_sequence, holiday_sequence;
qi::rule<Iterator,
Skipper,
OpeningHours::WeekdayRange(),
qi::locals<unsigned char, unsigned char>>
weekday_range;
// Monthday rules
qi::rule<Iterator, Skipper, OpeningHours::MonthdayRange()> monthday_range;
qi::rule<Iterator, Skipper, OpeningHours::Monthday(), qi::locals<unsigned, unsigned, unsigned>>
date_from;
qi::rule<Iterator, Skipper, OpeningHours::Monthday()> date_to;
// Year rules
qi::rule<Iterator, Skipper, OpeningHours::MonthdayRange()> year_range;
// Unused rules
qi::rule<Iterator, Skipper, void()> nth_entry, nth, day_offset, week, date_offset,
variable_date, comment;
// Basic rules and parsers
qi::rule<Iterator, Skipper, unsigned()> hour, extended_hour, minute, daynum, weeknum, year;
qi::symbols<char const, unsigned char> wday, month;
qi::uint_parser<unsigned, 10, 2, 2> uint2_p;
qi::uint_parser<unsigned, 10, 4, 4> uint4_p;
};
}
inline std::vector<OpeningHours> ParseOpeningHours(const std::string &str)
{
auto it(str.begin()), end(str.end());
const detail::opening_hours_grammar<decltype(it)> static grammar;
std::vector<OpeningHours> result;
bool ok = boost::spirit::qi::phrase_parse(it, end, grammar, boost::spirit::qi::blank, result);
if (!ok || it != end)
return std::vector<OpeningHours>();
return result;
}
inline bool CheckOpeningHours(const std::vector<OpeningHours> &input, const struct tm &time)
{
bool is_open = false;
for (auto &opening_hours : input)
{
if (opening_hours.modifier == OpeningHours::is24_7)
return true;
if (opening_hours.IsInRange(time))
{
is_open = opening_hours.modifier == OpeningHours::open;
}
}
return is_open;
}
bool CheckOpeningHours(const std::vector<OpeningHours> &input, const struct tm &time);
} // util
} // osrm
+48
View File
@@ -0,0 +1,48 @@
#ifndef OSRM_TIMEZONES_HPP
#define OSRM_TIMEZONES_HPP
#include "util/log.hpp"
#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <chrono>
namespace osrm
{
namespace updater
{
// Time zone shape polygons loaded in R-tree
// local_time_t is a pair of a time zone shape polygon and the corresponding local time
// rtree_t is a lookup R-tree that maps a geographic point to an index in a local_time_t vector
using point_t = boost::geometry::model::
point<double, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree>>;
using polygon_t = boost::geometry::model::polygon<point_t>;
using box_t = boost::geometry::model::box<point_t>;
using rtree_t =
boost::geometry::index::rtree<std::pair<box_t, size_t>, boost::geometry::index::rstar<8>>;
using local_time_t = std::pair<polygon_t, struct tm>;
bool SupportsShapefiles();
class Timezoner
{
public:
Timezoner() = default;
Timezoner(std::string tz_filename, std::time_t utc_time_now);
struct tm operator()(const point_t &point) const;
private:
void LoadLocalTimesRTree(const std::string &tz_shapes_filename, std::time_t utc_time);
struct tm default_time;
rtree_t rtree;
std::vector<local_time_t> local_times;
};
}
}
#endif