mirror of
https://github.com/osm2pgsql-dev/osm2pgsql.git
synced 2026-02-02 00:04:07 +00:00
This commit introduces a new feature: Locators. A locator is initialized with one or more regions, each region has a name and a polygon or bounding box. A geometry of an OSM object can then be checked against this region list to figure out in which region(s) it is located. This check is much faster than it would be to do this inside the database after import. Locators can be used for all sorts of interesting features: * Read larger OSM file but import only data inside some area. * Annotate each OSM object with the country (or other region) it is in. This can then, for instance, be used to show special highway shields for each country. * Use the information which region the data is in for further processing, for instance setting of default values for the speed limit or using special language transliterations rules based on country. Locators are created in Lua with `define_locator()`. Bounding boxes can be added with `add_bbox()`. Polygons can be added from the database by calling `add_from_db()` and specifiying an SQL query which can return any number of rows each defining a region with the name and the (multi)polygon as columns. A locator can then be queried using `all_intersecting()` returning a list of names of all regions that intersect the specified OSM object geometry. Or the `first_intersecting()` function can be used which only returns a single region for those cases where there can be no overlapping data or where the details of objects straddling region boundaries don't matter. Several example config files are provided in the flex-config/locator directory.
137 lines
4.2 KiB
C++
137 lines
4.2 KiB
C++
/**
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*
|
|
* This file is part of osm2pgsql (https://osm2pgsql.org/).
|
|
*
|
|
* Copyright (C) 2006-2025 by the osm2pgsql developer community.
|
|
* For a full list of authors see the git log.
|
|
*/
|
|
|
|
#include <catch.hpp>
|
|
|
|
#include "locator.hpp"
|
|
|
|
TEST_CASE("Create empty locator", "[NoDB]")
|
|
{
|
|
locator_t locator;
|
|
REQUIRE(locator.name().empty());
|
|
REQUIRE(locator.empty());
|
|
REQUIRE(locator.size() == 0); // NOLINT(readability-container-size-empty)
|
|
|
|
locator.set_name("foo");
|
|
REQUIRE(locator.name() == "foo");
|
|
}
|
|
|
|
TEST_CASE("Create locator with single box and check it", "[NoDB]")
|
|
{
|
|
locator_t locator;
|
|
locator.set_name("box");
|
|
locator.add_region("in", geom::box_t{0, 0, 10, 10});
|
|
|
|
REQUIRE_FALSE(locator.empty());
|
|
REQUIRE(locator.size() == 1);
|
|
|
|
locator.build_index();
|
|
|
|
geom::geometry_t const p1{geom::point_t{0.5, 0.5}}; // in box
|
|
geom::geometry_t const p2{geom::point_t{20, 20}}; // outside box
|
|
geom::geometry_t const p3{geom::point_t{0, 0}}; // on boundary
|
|
|
|
REQUIRE(locator.first_intersecting(p1) == "in");
|
|
REQUIRE(locator.first_intersecting(p2).empty());
|
|
REQUIRE(locator.first_intersecting(p3) == "in");
|
|
|
|
auto const a1 = locator.all_intersecting(p1);
|
|
auto const a2 = locator.all_intersecting(p2);
|
|
auto const a3 = locator.all_intersecting(p3);
|
|
|
|
REQUIRE(a1.size() == 1);
|
|
REQUIRE(a1.count("in") == 1);
|
|
REQUIRE(a2.empty());
|
|
REQUIRE(a3.size() == 1);
|
|
REQUIRE(a3.count("in") == 1);
|
|
}
|
|
|
|
TEST_CASE("Create locator with multiple boxes and check it", "[NoDB]")
|
|
{
|
|
locator_t locator;
|
|
locator.set_name("box");
|
|
locator.add_region("b1", geom::box_t{0, 0, 20, 20});
|
|
locator.add_region("b2", geom::box_t{10, 10, 30, 30});
|
|
|
|
REQUIRE_FALSE(locator.empty());
|
|
REQUIRE(locator.size() == 2);
|
|
|
|
geom::geometry_t const p1{geom::point_t{1, 1}}; // in 1
|
|
geom::geometry_t const p2{geom::point_t{11, 21}}; // in 2
|
|
geom::geometry_t const p3{geom::point_t{11, 11}}; // in 1 and 2
|
|
geom::geometry_t const p4{geom::point_t{1, 40}}; // outside
|
|
|
|
REQUIRE(locator.first_intersecting(p1) == "b1");
|
|
REQUIRE(locator.first_intersecting(p2) == "b2");
|
|
REQUIRE(((locator.first_intersecting(p3) == "b1") ||
|
|
(locator.first_intersecting(p3) == "b2")));
|
|
REQUIRE(locator.first_intersecting(p4).empty());
|
|
|
|
auto const a1 = locator.all_intersecting(p1);
|
|
auto const a2 = locator.all_intersecting(p2);
|
|
auto const a3 = locator.all_intersecting(p3);
|
|
auto const a4 = locator.all_intersecting(p4);
|
|
|
|
REQUIRE(a1.size() == 1);
|
|
REQUIRE(a2.size() == 1);
|
|
REQUIRE(a3.size() == 2);
|
|
REQUIRE(a4.empty());
|
|
|
|
REQUIRE(a1.count("b1") == 1);
|
|
REQUIRE(a2.count("b2") == 1);
|
|
REQUIRE(a3.count("b1") == 1);
|
|
REQUIRE(a3.count("b2") == 1);
|
|
}
|
|
|
|
TEST_CASE("Locator with polygon regions", "[NoDB]")
|
|
{
|
|
locator_t locator;
|
|
locator.set_name("box");
|
|
locator.add_region("b1", geom::box_t{0, 0, 5, 5});
|
|
|
|
geom::point_t const c1{0, 0};
|
|
geom::point_t const c2{0, 5};
|
|
geom::point_t const c3{5, 0};
|
|
geom::point_t const c4{5, 5};
|
|
|
|
geom::polygon_t polygon1{geom::ring_t{c1, c2, c3, c1}};
|
|
geom::polygon_t polygon2{geom::ring_t{c4, c2, c3, c4}};
|
|
|
|
locator.add_region("p1", geom::geometry_t{std::move(polygon1)});
|
|
locator.add_region("p2", geom::geometry_t{std::move(polygon2)});
|
|
|
|
REQUIRE_FALSE(locator.empty());
|
|
REQUIRE(locator.size() == 3);
|
|
|
|
geom::geometry_t const p1{geom::point_t{1, 1}}; // in b1, p1
|
|
geom::geometry_t const p2{geom::point_t{4, 4}}; // in b1, p2
|
|
geom::geometry_t const p3{geom::point_t{1, 10}}; // outside
|
|
|
|
REQUIRE(((locator.first_intersecting(p1) == "b1") ||
|
|
(locator.first_intersecting(p1) == "p1")));
|
|
|
|
REQUIRE(((locator.first_intersecting(p2) == "b1") ||
|
|
(locator.first_intersecting(p2) == "p2")));
|
|
|
|
REQUIRE(locator.first_intersecting(p3).empty());
|
|
|
|
auto const a1 = locator.all_intersecting(p1);
|
|
auto const a2 = locator.all_intersecting(p2);
|
|
auto const a3 = locator.all_intersecting(p3);
|
|
|
|
REQUIRE(a1.size() == 2);
|
|
REQUIRE(a2.size() == 2);
|
|
REQUIRE(a3.empty());
|
|
|
|
REQUIRE(a1.count("b1") == 1);
|
|
REQUIRE(a1.count("p1") == 1);
|
|
REQUIRE(a2.count("b1") == 1);
|
|
REQUIRE(a2.count("p2") == 1);
|
|
}
|