diff --git a/features/options/extract/lua.feature b/features/options/extract/lua.feature index 113a93228..e13dfc70d 100644 --- a/features/options/extract/lua.feature +++ b/features/options/extract/lua.feature @@ -38,9 +38,9 @@ Feature: osrm-extract lua ways:get_nodes() functions = require('testbot') function way_function(profile, way, result, relations) - location_data = way:get_location_tags() - assert(location_data) - for k, v in pairs(location_data) do print (k .. ' ' .. tostring(v)) end + for _, key in ipairs({'answer', 'boolean', 'object', 'array'}) do + print (key .. ' ' .. tostring(way:get_location_tag(key))) + end result.forward_mode = mode.driving result.forward_speed = 1 end @@ -60,7 +60,9 @@ Feature: osrm-extract lua ways:get_nodes() When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson" Then it should exit successfully And stdout should contain "answer 42" - And stdout should not contain "array" + And stdout should contain "boolean true" + And stdout should contain "array nil" + And stdout should contain "object nil" Scenario: osrm-extract location-dependent data with multi-polygons @@ -69,9 +71,7 @@ Feature: osrm-extract lua ways:get_nodes() functions = require('testbot') function way_function(profile, way, result, relations) - location_data = way:get_location_tags() - assert(location_data) - print('ISO3166-1 ' .. (location_data['ISO3166-1'] or 'none')) + print('ISO3166-1 ' .. (way:get_location_tag('ISO3166-1') or 'none')) result.forward_mode = mode.driving result.forward_speed = 1 end @@ -104,9 +104,7 @@ Feature: osrm-extract lua ways:get_nodes() functions = require('testbot') function way_function(profile, way, result, relations) - location_data = way:get_location_tags() - assert(location_data) - for k, v in pairs(location_data) do print (k .. ' ' .. tostring(v)) end + print ('answer ' .. tostring(way:get_location_tag('answer'))) result.forward_mode = mode.driving result.forward_speed = 1 end @@ -126,4 +124,3 @@ Feature: osrm-extract lua ways:get_nodes() When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson" Then it should exit successfully And stdout should contain "answer 42" - And stdout should not contain "array" diff --git a/include/extractor/location_dependent_data.hpp b/include/extractor/location_dependent_data.hpp index b9ddaecf1..8406b4fcb 100644 --- a/include/extractor/location_dependent_data.hpp +++ b/include/extractor/location_dependent_data.hpp @@ -38,7 +38,7 @@ struct LocationDependentData bool empty() const { return rtree.empty(); } - properties_t operator()(const point_t &point) const; + property_t operator()(const point_t &point, const char *key) const; private: void loadLocationDependentData(const boost::filesystem::path &file_path); diff --git a/profiles/lib/way_handlers.lua b/profiles/lib/way_handlers.lua index 8def08788..d7d780ea5 100644 --- a/profiles/lib/way_handlers.lua +++ b/profiles/lib/way_handlers.lua @@ -553,18 +553,17 @@ function WayHandlers.blocked_ways(profile,way,result,data) end function WayHandlers.driving_side(profile, way, result, data) - local driving_side = way:get_value_by_key("driving_side") + local driving_side = way:get_value_by_key('driving_side') + if driving_side == nil then + driving_side = way:get_location_tag('driving_side') + end + if driving_side == 'left' then result.is_left_hand_driving = true elseif driving_side == 'right' then result.is_left_hand_driving = false else - location_data = way:get_location_tags() - if location_data and location_data['driving_side'] then - result.is_left_hand_driving = location_data['driving_side'] == 'left' - else - result.is_left_hand_driving = profile.left_hand_driving - end + result.is_left_hand_driving = profile.left_hand_driving end end diff --git a/src/extractor/location_dependent_data.cpp b/src/extractor/location_dependent_data.cpp index 366d57004..c8e9578b0 100644 --- a/src/extractor/location_dependent_data.cpp +++ b/src/extractor/location_dependent_data.cpp @@ -195,17 +195,25 @@ void LocationDependentData::loadLocationDependentData(const boost::filesystem::p << polygons.size() << " GeoJSON polygons"; } -LocationDependentData::properties_t LocationDependentData::operator()(const point_t &point) const +LocationDependentData::property_t LocationDependentData::operator()(const point_t &point, + const char *key) const { - properties_t result; + property_t result; - auto merger = [this, &result](const rtree_t::value_type &rtree_entry) { - const auto &polygon_properties = properties[polygons[rtree_entry.second].second]; - result.insert(polygon_properties.begin(), polygon_properties.end()); + auto setter = [this, &result, &key](const rtree_t::value_type &rtree_entry) { + const auto properties_index = polygons[rtree_entry.second].second; + const auto &polygon_properties = properties[properties_index]; + const auto it = polygon_properties.find(key); + if (it != polygon_properties.end()) + { + result = it->second; + } }; // Search the R-tree and collect a Lua table of tags that correspond to the location - rtree.query(boost::geometry::index::intersects(point) && + rtree.query(boost::geometry::index::satisfies( + [&result](const rtree_t::value_type &) { return result.which() == 0; }) && + boost::geometry::index::intersects(point) && boost::geometry::index::satisfies([this, &point](const rtree_t::value_type &v) { // Simple point-in-polygon algorithm adapted from @@ -261,7 +269,7 @@ LocationDependentData::properties_t LocationDependentData::operator()(const poin return inside; }), - boost::make_function_output_iterator(std::ref(merger))); + boost::make_function_output_iterator(std::ref(setter))); return result; } diff --git a/src/extractor/scripting_environment_lua.cpp b/src/extractor/scripting_environment_lua.cpp index 564434439..d20767792 100644 --- a/src/extractor/scripting_environment_lua.cpp +++ b/src/extractor/scripting_environment_lua.cpp @@ -82,26 +82,13 @@ template double lonToDouble(T const &object) return static_cast(util::toFloating(object.lon)); } -// boost::variant visitor that inserts a key-value pair in a Lua table -struct table_setter : public boost::static_visitor<> +struct to_lua_object : public boost::static_visitor { - table_setter(sol::table &table, const std::string &key) : table(table), key(key) {} - template void operator()(const T &value) const { table.set(key, value); } - void operator()(const boost::blank &) const { /* ignore */} - - sol::table &table; - const std::string &key; + to_lua_object(sol::state &state) : state(state) {} + template auto operator()(T &v) const { return sol::make_object(state, v); } + auto operator()(boost::blank &) const { return sol::nil; } + sol::state &state; }; - -// Converts a properties map into a Lua table -sol::table toLua(sol::state &state, const LocationDependentData::properties_t &properties) -{ - auto table = sol::table(state, sol::create); - std::for_each(properties.begin(), properties.end(), [&table](const auto &property) { - boost::apply_visitor(table_setter(table, property.first), property.second); - }); - return table; -} } Sol2ScriptingEnvironment::Sol2ScriptingEnvironment( @@ -313,15 +300,15 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) &osmium::Way::version, "get_nodes", [](const osmium::Way &way) { return sol::as_table(way.nodes()); }, - "get_location_tags", - [&context](const osmium::Way &way) { + "get_location_tag", + [&context](const osmium::Way &way, const char *key) { // HEURISTIC: use a single node (last) of the way to localize the way // For more complicated scenarios a proper merging of multiple tags // at one or many locations must be provided const auto &nodes = way.nodes(); const auto &location = nodes.back().location(); - return toLua(context.state, - context.location_dependent_data({location.lon(), location.lat()})); + auto value = context.location_dependent_data({location.lon(), location.lat()}, key); + return boost::apply_visitor(to_lua_object(context.state), value); }); context.state.new_usertype( diff --git a/unit_tests/extractor/location_dependent_data_tests.cpp b/unit_tests/extractor/location_dependent_data_tests.cpp index f1d21dcb0..1749cb544 100644 --- a/unit_tests/extractor/location_dependent_data_tests.cpp +++ b/unit_tests/extractor/location_dependent_data_tests.cpp @@ -50,15 +50,15 @@ BOOST_AUTO_TEST_CASE(polygon_tests) ]})json"); LocationDependentData data(fixture.temporary_file); - BOOST_CHECK(data(point_t(0, 0)).empty()); - BOOST_CHECK(!data(point_t(1, 1)).empty()); - BOOST_CHECK(!data(point_t(0, 1)).empty()); - BOOST_CHECK(!data(point_t(0.5, -0.5)).empty()); - BOOST_CHECK(!data(point_t(0, -3)).empty()); - BOOST_CHECK(!data(point_t(-0.75, 0.75)).empty()); - BOOST_CHECK(!data(point_t(-2, 6)).empty()); - BOOST_CHECK_EQUAL(boost::get(data(point_t(2, 0))["answer"]), 42.); - BOOST_CHECK_EQUAL(boost::get(data(point_t(1, 7))["answer"]), true); + BOOST_CHECK_EQUAL(data(point_t(0, 0), "answer").which(), 0); + BOOST_CHECK_EQUAL(boost::get(data(point_t(1, 1), "answer")), 42); + BOOST_CHECK_EQUAL(boost::get(data(point_t(0, 1), "answer")), 42); + BOOST_CHECK_EQUAL(boost::get(data(point_t(0.5, -0.5), "answer")), 42); + BOOST_CHECK_EQUAL(boost::get(data(point_t(0, -3), "answer")), 42); + BOOST_CHECK_EQUAL(boost::get(data(point_t(-0.75, 0.75), "answer")), 42); + BOOST_CHECK_EQUAL(boost::get(data(point_t(2, 0), "answer")), 42.); + BOOST_CHECK_EQUAL(boost::get(data(point_t(1, 7), "answer")), true); + BOOST_CHECK_EQUAL(boost::get(data(point_t(-2, 6), "answer")), true); } BOOST_AUTO_TEST_CASE(multy_polygon_tests) @@ -80,11 +80,11 @@ BOOST_AUTO_TEST_CASE(multy_polygon_tests) ]})json"); LocationDependentData data(fixture.temporary_file); - BOOST_CHECK(data(point_t(0, 2)).empty()); - BOOST_CHECK(data(point_t(0, -3)).empty()); - BOOST_CHECK_EQUAL(boost::get(data(point_t(0, 0))["answer"]), 42.); - BOOST_CHECK_EQUAL(boost::get(data(point_t(5, 0))["answer"]), 42.); - BOOST_CHECK_EQUAL(boost::get(data(point_t(-5, 0))["answer"]), 42.); + BOOST_CHECK_EQUAL(data(point_t(0, 2), "answer").which(), 0); + BOOST_CHECK_EQUAL(data(point_t(0, -3), "answer").which(), 0); + BOOST_CHECK_EQUAL(boost::get(data(point_t(0, 0), "answer")), 42.); + BOOST_CHECK_EQUAL(boost::get(data(point_t(5, 0), "answer")), 42.); + BOOST_CHECK_EQUAL(boost::get(data(point_t(-5, 0), "answer")), 42.); } BOOST_AUTO_TEST_CASE(polygon_merging_tests) @@ -110,19 +110,19 @@ BOOST_AUTO_TEST_CASE(polygon_merging_tests) ]})json"); LocationDependentData data(fixture.temporary_file); - BOOST_CHECK_EQUAL(boost::get(data(point_t(-3, 3))["answer"]), "a"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(-3, 1))["answer"]), "a"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(-3, -3))["answer"]), "a"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(0, 3))["answer"]), "a"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(1, 0))["answer"]), "a"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(2, -3))["answer"]), "a"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(3, 0))["answer"]), "a"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(4, 3))["answer"]), "b"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(6, 1))["answer"]), "b"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(7, 0))["answer"]), "b"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(8, 3))["answer"]), "c"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(8, -1))["answer"]), "c"); - BOOST_CHECK_EQUAL(boost::get(data(point_t(8, -3))["answer"]), "c"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(-3, 3), "answer")), "a"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(-3, 1), "answer")), "a"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(-3, -3), "answer")), "a"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(0, 3), "answer")), "a"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(1, 0), "answer")), "a"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(2, -3), "answer")), "a"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(3, 0), "answer")), "a"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(4, 3), "answer")), "b"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(6, 1), "answer")), "b"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(7, 0), "answer")), "b"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(8, 3), "answer")), "c"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(8, -1), "answer")), "c"); + BOOST_CHECK_EQUAL(boost::get(data(point_t(8, -3), "answer")), "c"); } BOOST_AUTO_TEST_CASE(staircase_polygon) @@ -140,31 +140,31 @@ BOOST_AUTO_TEST_CASE(staircase_polygon) LocationDependentData data(fixture.temporary_file); // all corners - BOOST_CHECK(!data(point_t(0, 0)).empty()); - BOOST_CHECK(!data(point_t(0, 1)).empty()); - BOOST_CHECK(!data(point_t(1, 1)).empty()); - BOOST_CHECK(!data(point_t(1, 2)).empty()); - BOOST_CHECK(!data(point_t(2, 2)).empty()); - BOOST_CHECK(!data(point_t(2, 3)).empty()); - BOOST_CHECK(!data(point_t(3, 3)).empty()); - BOOST_CHECK(!data(point_t(3, 0)).empty()); + BOOST_CHECK_NE(data(point_t(0, 0), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(0, 1), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(1, 1), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(1, 2), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(2, 2), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(2, 3), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(3, 3), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(3, 0), "answer").which(), 0); - // at x = 1 - BOOST_CHECK(data(point_t(1, -0.5)).empty()); - BOOST_CHECK(!data(point_t(1, 0)).empty()); - BOOST_CHECK(!data(point_t(1, 0.5)).empty()); - BOOST_CHECK(!data(point_t(1, 1.5)).empty()); - BOOST_CHECK(data(point_t(1, 2.5)).empty()); - BOOST_CHECK(data(point_t(3.5, 2)).empty()); + // // at x = 1 + BOOST_CHECK_EQUAL(data(point_t(1, -0.5), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(1, 0), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(1, 0.5), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(1, 1.5), "answer").which(), 0); + BOOST_CHECK_EQUAL(data(point_t(1, 2.5), "answer").which(), 0); + BOOST_CHECK_EQUAL(data(point_t(3.5, 2), "answer").which(), 0); - // at y = 2 - BOOST_CHECK(data(point_t(0.5, 2)).empty()); - BOOST_CHECK(!data(point_t(1, 2)).empty()); - BOOST_CHECK(!data(point_t(1.5, 2)).empty()); - BOOST_CHECK(!data(point_t(2, 2)).empty()); - BOOST_CHECK(!data(point_t(2.5, 2)).empty()); - BOOST_CHECK(!data(point_t(3, 2)).empty()); - BOOST_CHECK(data(point_t(3.5, 2)).empty()); + // // at y = 2 + BOOST_CHECK_EQUAL(data(point_t(0.5, 2), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(1, 2), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(1.5, 2), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(2, 2), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(2.5, 2), "answer").which(), 0); + BOOST_CHECK_NE(data(point_t(3, 2), "answer").which(), 0); + BOOST_CHECK_EQUAL(data(point_t(3.5, 2), "answer").which(), 0); } BOOST_AUTO_TEST_SUITE_END()