Skip to content

Commit

Permalink
Add last location memoization in Lua context
Browse files Browse the repository at this point in the history
  • Loading branch information
oxidase committed Oct 4, 2017
1 parent 545097c commit 11e7b6e
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 67 deletions.
4 changes: 3 additions & 1 deletion include/extractor/location_dependent_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ struct LocationDependentData

bool empty() const { return rtree.empty(); }

property_t operator()(const point_t &point, const char *key) const;
std::vector<std::size_t> GetPropertyIndexes(const point_t &point) const;

property_t FindByKey(const std::vector<std::size_t> &property_indexes, const char *key) const;

private:
void loadLocationDependentData(const boost::filesystem::path &file_path,
Expand Down
7 changes: 6 additions & 1 deletion include/extractor/scripting_environment_lua.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ namespace extractor
struct LuaScriptingContext final
{
LuaScriptingContext(const LocationDependentData &location_dependent_data)
: location_dependent_data(location_dependent_data)
: location_dependent_data(location_dependent_data),
last_location_point(0., 180.) // assume (0,180) is invalid coordinate
{
}

Expand Down Expand Up @@ -52,7 +53,11 @@ struct LuaScriptingContext final

int api_version;
sol::table profile_table;

// Reference to immutable location dependent data and locations memo
const LocationDependentData &location_dependent_data;
LocationDependentData::point_t last_location_point;
std::vector<std::size_t> last_location_indexes;
};

/**
Expand Down
31 changes: 19 additions & 12 deletions src/extractor/location_dependent_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,25 +191,32 @@ void LocationDependentData::loadLocationDependentData(
}
}

LocationDependentData::property_t LocationDependentData::operator()(const point_t &point,
const char *key) const
LocationDependentData::property_t
LocationDependentData::FindByKey(const std::vector<std::size_t> &property_indexes,
const char *key) const
{
property_t result;

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];
for (auto index : property_indexes)
{
const auto &polygon_properties = properties[index];
const auto it = polygon_properties.find(key);
if (it != polygon_properties.end())
{
result = it->second;
return it->second;
}
}
return property_t{};
}

std::vector<std::size_t> LocationDependentData::GetPropertyIndexes(const point_t &point) const
{
std::vector<std::size_t> result;
auto inserter = [this, &result](const rtree_t::value_type &rtree_entry) {
const auto properties_index = polygons[rtree_entry.second].second;
result.push_back(properties_index);
};

// Search the R-tree and collect a Lua table of tags that correspond to the location
rtree.query(boost::geometry::index::satisfies(
[&result](const rtree_t::value_type &) { return result.which() == 0; }) &&
boost::geometry::index::intersects(point) &&
rtree.query(boost::geometry::index::intersects(point) &&
boost::geometry::index::satisfies([this, &point](const rtree_t::value_type &v) {

// Simple point-in-polygon algorithm adapted from
Expand Down Expand Up @@ -265,7 +272,7 @@ LocationDependentData::property_t LocationDependentData::operator()(const point_

return inside;
}),
boost::make_function_output_iterator(std::ref(setter)));
boost::make_function_output_iterator(std::ref(inserter)));

return result;
}
Expand Down
12 changes: 11 additions & 1 deletion src/extractor/scripting_environment_lua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,17 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
// at one or many locations must be provided
const auto &nodes = way.nodes();
const auto &location = nodes.back().location();
auto value = context.location_dependent_data({location.lon(), location.lat()}, key);
const LocationDependentData::point_t point{location.lon(), location.lat()};

if (!boost::geometry::equals(context.last_location_point, point))
{
context.last_location_point = point;
context.last_location_indexes =
context.location_dependent_data.GetPropertyIndexes(point);
}

auto value =
context.location_dependent_data.FindByKey(context.last_location_indexes, key);
return boost::apply_visitor(to_lua_object(context.state), value);
});

Expand Down
118 changes: 66 additions & 52 deletions unit_tests/extractor/location_dependent_data_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "extractor/location_dependent_data.hpp"

#include "../common/range_tools.hpp"

#include <boost/filesystem.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
Expand Down Expand Up @@ -51,15 +53,20 @@ BOOST_AUTO_TEST_CASE(polygon_tests)

LocationDependentData data({fixture.temporary_file});

BOOST_CHECK_EQUAL(data(point_t(0, 0), "answer").which(), 0);
BOOST_CHECK_EQUAL(boost::get<double>(data(point_t(1, 1), "answer")), 42);
BOOST_CHECK_EQUAL(boost::get<double>(data(point_t(0, 1), "answer")), 42);
BOOST_CHECK_EQUAL(boost::get<double>(data(point_t(0.5, -0.5), "answer")), 42);
BOOST_CHECK_EQUAL(boost::get<double>(data(point_t(0, -3), "answer")), 42);
BOOST_CHECK_EQUAL(boost::get<double>(data(point_t(-0.75, 0.75), "answer")), 42);
BOOST_CHECK_EQUAL(boost::get<double>(data(point_t(2, 0), "answer")), 42.);
BOOST_CHECK_EQUAL(boost::get<bool>(data(point_t(1, 7), "answer")), true);
BOOST_CHECK_EQUAL(boost::get<bool>(data(point_t(-2, 6), "answer")), true);
BOOST_CHECK(data.GetPropertyIndexes(point_t(0, 0)).empty());
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(1, 1)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(0, 1)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(0.5, -0.5)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(0, -3)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(-0.75, 0.75)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(2, 0)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(1, 7)), 1);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(-2, 6)), 1);

BOOST_CHECK_EQUAL(data.FindByKey({}, "answer").which(), 0);
BOOST_CHECK_EQUAL(data.FindByKey({0}, "foo").which(), 0);
BOOST_CHECK_EQUAL(boost::get<double>(data.FindByKey({0}, "answer")), 42);
BOOST_CHECK_EQUAL(boost::get<bool>(data.FindByKey({1}, "answer")), true);
}

BOOST_AUTO_TEST_CASE(multy_polygon_tests)
Expand All @@ -82,11 +89,11 @@ BOOST_AUTO_TEST_CASE(multy_polygon_tests)

LocationDependentData data({fixture.temporary_file});

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<double>(data(point_t(0, 0), "answer")), 42.);
BOOST_CHECK_EQUAL(boost::get<double>(data(point_t(5, 0), "answer")), 42.);
BOOST_CHECK_EQUAL(boost::get<double>(data(point_t(-5, 0), "answer")), 42.);
BOOST_CHECK(data.GetPropertyIndexes(point_t(0, 2)).empty());
BOOST_CHECK(data.GetPropertyIndexes(point_t(0, -3)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(0, 0)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(5, 0)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(-5, 0)).empty());
}

BOOST_AUTO_TEST_CASE(polygon_merging_tests)
Expand All @@ -113,19 +120,26 @@ BOOST_AUTO_TEST_CASE(polygon_merging_tests)

LocationDependentData data({fixture.temporary_file});

BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(-3, 3), "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(-3, 1), "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(-3, -3), "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(0, 3), "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(1, 0), "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(2, -3), "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(3, 0), "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(4, 3), "answer")), "b");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(6, 1), "answer")), "b");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(7, 0), "answer")), "b");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(8, 3), "answer")), "c");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(8, -1), "answer")), "c");
BOOST_CHECK_EQUAL(boost::get<std::string>(data(point_t(8, -3), "answer")), "c");
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(-3, 3)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(-3, 1)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(-3, -3)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(0, 3)), 0);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(1, 0)), 0, 1);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(2, -3)), 0, 1, 2);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(3, 0)), 0, 1, 2);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(4, 3)), 1, 2);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(6, 1)), 1, 2);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(7, 0)), 1, 2);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(8, 3)), 2);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(8, -1)), 2);
CHECK_EQUAL_RANGE(data.GetPropertyIndexes(point_t(8, -3)), 2);

BOOST_CHECK_EQUAL(boost::get<std::string>(data.FindByKey({0}, "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data.FindByKey({1}, "answer")), "b");
BOOST_CHECK_EQUAL(boost::get<std::string>(data.FindByKey({2}, "answer")), "c");
BOOST_CHECK_EQUAL(boost::get<std::string>(data.FindByKey({0, 1, 2}, "answer")), "a");
BOOST_CHECK_EQUAL(boost::get<std::string>(data.FindByKey({1, 2}, "answer")), "b");
BOOST_CHECK_EQUAL(boost::get<std::string>(data.FindByKey({2, 1, 0}, "answer")), "c");
}

BOOST_AUTO_TEST_CASE(staircase_polygon)
Expand All @@ -143,31 +157,31 @@ BOOST_AUTO_TEST_CASE(staircase_polygon)
LocationDependentData data({fixture.temporary_file});

// all corners
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_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_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_CHECK(!data.GetPropertyIndexes(point_t(0, 0)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(0, 1)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(1, 1)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(1, 2)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(2, 2)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(2, 3)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(3, 3)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(3, 0)).empty());

// at x = 1
BOOST_CHECK(data.GetPropertyIndexes(point_t(1, -0.5)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(1, 0)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(1, 0.5)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(1, 1.5)).empty());
BOOST_CHECK(data.GetPropertyIndexes(point_t(1, 2.5)).empty());
BOOST_CHECK(data.GetPropertyIndexes(point_t(3.5, 2)).empty());

// at y = 2
BOOST_CHECK(data.GetPropertyIndexes(point_t(0.5, 2)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(1, 2)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(1.5, 2)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(2, 2)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(2.5, 2)).empty());
BOOST_CHECK(!data.GetPropertyIndexes(point_t(3, 2)).empty());
BOOST_CHECK(data.GetPropertyIndexes(point_t(3.5, 2)).empty());
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 11e7b6e

Please sign in to comment.