Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/flex-lua-geom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,20 @@ int geom_centroid(lua_State *lua_state)
return 1;
}

int geom_n_points(lua_State *lua_state)
{
auto const *const input_geometry = unpack_geometry(lua_state);

try {
lua_pushinteger(lua_state,
static_cast<lua_Integer>(input_geometry->n_points()));
} catch (...) {
return luaL_error(lua_state, "Unknown error in 'n_points()'.\n");
}

return 1;
}

int geom_geometry_n(lua_State *lua_state)
{
auto const *const input_geometry = unpack_geometry(lua_state);
Expand Down Expand Up @@ -313,6 +327,7 @@ void init_geometry_class(lua_State *lua_state)
{"geometry_type", geom_geometry_type},
{"is_null", geom_is_null},
{"line_merge", geom_line_merge},
{"n_points", geom_n_points},
{"reverse", geom_reverse},
{"num_geometries", geom_num_geometries},
{"pole_of_inaccessibility", geom_pole_of_inaccessibility},
Expand Down
19 changes: 19 additions & 0 deletions src/geom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@ bool operator!=(polygon_t const &a, polygon_t const &b) noexcept
return !(a == b);
}

[[nodiscard]] std::size_t polygon_t::n_points() const
{
return m_outer.size() +
std::accumulate(m_inners.cbegin(), m_inners.cend(), std::size_t{0},
[](std::size_t sum, ring_t const &ring) {
return sum + ring.size();
});
}

[[nodiscard]] std::size_t geometry_t::n_points() const
{
return visit([](auto const &input) { return input.n_points(); });
}

std::size_t n_points(geometry_t const &geom)
{
return geom.visit([](auto const &input) { return input.n_points(); });
}

std::size_t dimension(collection_t const &geom)
{
return std::accumulate(geom.cbegin(), geom.cend(), 0ULL,
Expand Down
29 changes: 29 additions & 0 deletions src/geom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <cassert>
#include <cmath>
#include <initializer_list>
#include <numeric>
#include <type_traits>
#include <utility>
#include <variant>
Expand All @@ -39,6 +40,11 @@ class nullgeom_t
return 0;
}

[[nodiscard]] constexpr static std::size_t n_points() noexcept
{
return 0;
}

[[nodiscard]] constexpr friend bool operator==(nullgeom_t,
nullgeom_t) noexcept
{
Expand Down Expand Up @@ -69,6 +75,11 @@ class point_t
return 1;
}

[[nodiscard]] constexpr static std::size_t n_points() noexcept
{
return 1;
}

[[nodiscard]] constexpr double x() const noexcept { return m_x; }
[[nodiscard]] constexpr double y() const noexcept { return m_y; }

Expand Down Expand Up @@ -148,6 +159,11 @@ class linestring_t : public point_list_t
return 1;
}

[[nodiscard]] std::size_t n_points() const noexcept
{
return size();
}

}; // class linestring_t

class ring_t : public point_list_t
Expand Down Expand Up @@ -186,6 +202,8 @@ class polygon_t

friend bool operator!=(polygon_t const &a, polygon_t const &b) noexcept;

[[nodiscard]] std::size_t n_points() const;

private:
ring_t m_outer;
std::vector<ring_t> m_inners;
Expand Down Expand Up @@ -257,6 +275,15 @@ class multigeometry_t

void reserve(std::size_t size) { m_geometry.reserve(size); }

[[nodiscard]] std::size_t n_points() const
{
return std::accumulate(m_geometry.cbegin(), m_geometry.cend(),
std::size_t{0},
[](std::size_t sum, auto const &geom) {
return sum + geom.n_points();
});
}

private:
std::vector<GEOM> m_geometry;

Expand Down Expand Up @@ -400,6 +427,8 @@ class geometry_t
return !(a == b);
}

[[nodiscard]] std::size_t n_points() const;

private:
std::variant<nullgeom_t, point_t, linestring_t, polygon_t, multipoint_t,
multilinestring_t, multipolygon_t, collection_t>
Expand Down
10 changes: 6 additions & 4 deletions tests/bdd/flex/geometry-linestring.feature
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ Feature: Creating linestring features from way
{ column = 'sgeom', type = 'linestring', projection = 4326 },
{ column = 'mgeom', type = 'multilinestring', projection = 4326 },
{ column = 'xgeom', type = 'multilinestring', projection = 4326 },
{ column = 'npoints', type = 'int' },
})

function osm2pgsql.process_way(object)
if object.tags.highway == 'motorway' then
lines:insert({
sgeom = object:as_linestring(),
mgeom = object:as_multilinestring(),
xgeom = object:as_linestring()
xgeom = object:as_linestring(),
npoints = object:as_linestring():n_points(),
})
end
end
Expand All @@ -32,9 +34,9 @@ Feature: Creating linestring features from way
When running osm2pgsql flex

Then table osm2pgsql_test_lines contains exactly
| way_id | sgeom!geo | mgeom!geo | xgeom!geo |
| 20 | 1, 2, 3 | [ 1, 2, 3 ] | [ 1, 2, 3 ] |
| 21 | 4, 5 | [ 4, 5 ] | [ 4, 5 ] |
| way_id | sgeom!geo | mgeom!geo | xgeom!geo | npoints |
| 20 | 1, 2, 3 | [ 1, 2, 3 ] | [ 1, 2, 3 ] | 3 |
| 21 | 4, 5 | [ 4, 5 ] | [ 4, 5 ] | 2 |

Scenario:
Given the grid
Expand Down
5 changes: 5 additions & 0 deletions tests/test-geom-collections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ TEST_CASE("geometry collection with point", "[NoDB]")
c.add_geometry(geom::geometry_t{geom::point_t{1, 1}});

REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
REQUIRE(geom.n_points() == 1);
REQUIRE(dimension(geom) == 0);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(0.0));
Expand All @@ -46,6 +47,7 @@ TEST_CASE("geometry collection with multipoint", "[NoDB]")
c.add_geometry(std::move(mpgeom));

REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
REQUIRE(geom.n_points() == 4);
REQUIRE(dimension(geom) == 0);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(0.0));
Expand All @@ -62,6 +64,7 @@ TEST_CASE("geometry collection with several geometries", "[NoDB]")
c.add_geometry(geom::geometry_t{geom::point_t{2, 2}});

REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
REQUIRE(geom.n_points() == 4);
REQUIRE(dimension(geom) == 1);
REQUIRE(num_geometries(geom) == 3);
REQUIRE(area(geom) == Approx(0.0));
Expand All @@ -83,6 +86,7 @@ TEST_CASE("geometry collection with polygon", "[NoDB]")
geom::polygon_t{geom::ring_t{{1, 1}, {1, 2}, {2, 2}, {2, 1}, {1, 1}}}});

REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
REQUIRE(geom.n_points() == 6);
REQUIRE(num_geometries(geom) == 2);
REQUIRE(area(geom) == Approx(1.0));
REQUIRE(length(geom) == Approx(0.0));
Expand All @@ -100,6 +104,7 @@ TEST_CASE("create_collection from OSM data", "[NoDB]")
auto const geom = geom::create_collection(buffer.buffer());

REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
REQUIRE(geom.n_points() == 8);
REQUIRE(dimension(geom) == 1);
REQUIRE(num_geometries(geom) == 3);

Expand Down
1 change: 1 addition & 0 deletions tests/test-geom-linestrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ TEST_CASE("line geometry", "[NoDB]")
{
geom::geometry_t const geom{geom::linestring_t{{1, 1}, {2, 2}}};

REQUIRE(geom.n_points() == 2);
REQUIRE(dimension(geom) == 1);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(0.0));
Expand Down
5 changes: 5 additions & 0 deletions tests/test-geom-multilinestrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ TEST_CASE("create_multilinestring with single line", "[NoDB]")

REQUIRE(geom.is_multilinestring());
REQUIRE(geometry_type(geom) == "MULTILINESTRING");
REQUIRE(geom.n_points() == 2);
REQUIRE(dimension(geom) == 1);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(0.0));
Expand Down Expand Up @@ -59,6 +60,7 @@ TEST_CASE("create_multilinestring with single line and no force_multi",

REQUIRE(geom.is_linestring());
REQUIRE(geometry_type(geom) == "LINESTRING");
REQUIRE(geom.n_points() == 2);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(0.0));
REQUIRE(spherical_area(geom) == Approx(0.0));
Expand Down Expand Up @@ -132,6 +134,7 @@ TEST_CASE("create_multilinestring from two non-joined lines", "[NoDB]")
geom::line_merge(geom::create_multilinestring(buffer.buffer()));

REQUIRE(geom.is_multilinestring());
REQUIRE(geom.n_points() == 4);
REQUIRE(dimension(geom) == 1);
auto const &ml = geom.get<geom::multilinestring_t>();
REQUIRE(ml.num_geometries() == 2);
Expand All @@ -152,6 +155,7 @@ TEST_CASE("create_multilinestring from two lines end to end", "[NoDB]")

REQUIRE(geom.is_multilinestring());
auto const &ml = geom.get<geom::multilinestring_t>();
REQUIRE(ml.n_points() == 3);
REQUIRE(ml.num_geometries() == 1);
REQUIRE(ml[0] == expected);
}
Expand Down Expand Up @@ -292,6 +296,7 @@ TEST_CASE("create_multilinestring from Y shape", "[NoDB]")
REQUIRE(geom.is_multilinestring());
auto const &ml = geom.get<geom::multilinestring_t>();
REQUIRE(ml.num_geometries() == 2);
REQUIRE(ml.n_points() == 5);
REQUIRE(ml[0] == expected[0]);
REQUIRE(ml[1] == expected[1]);
}
Expand Down
3 changes: 3 additions & 0 deletions tests/test-geom-multipoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ TEST_CASE("multipoint_t with a single point", "[NoDB]")

REQUIRE(geom.is_multipoint());
REQUIRE(geometry_type(geom) == "MULTIPOINT");
REQUIRE(geom.n_points() == 1);
REQUIRE(dimension(geom) == 0);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(0.0));
Expand All @@ -54,6 +55,7 @@ TEST_CASE("multipoint_t with several points", "[NoDB]")

REQUIRE(geom.is_multipoint());
REQUIRE(geometry_type(geom) == "MULTIPOINT");
REQUIRE(geom.n_points() == 3);
REQUIRE(num_geometries(geom) == 3);
REQUIRE(area(geom) == Approx(0.0));
REQUIRE(spherical_area(geom) == Approx(0.0));
Expand Down Expand Up @@ -85,6 +87,7 @@ TEST_CASE("create_multipoint from OSM data", "[NoDB]")

REQUIRE(geometry_type(geom) == "MULTIPOINT");
REQUIRE(dimension(geom) == 0);
REQUIRE(geom.n_points() == 4);
REQUIRE(num_geometries(geom) == 4);

auto const &c = geom.get<geom::multipoint_t>();
Expand Down
4 changes: 4 additions & 0 deletions tests/test-geom-multipolygons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ TEST_CASE("multipolygon geometry with single outer, no inner", "[NoDB]")
geom::polygon_t{geom::ring_t{{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}}});

REQUIRE(geometry_type(geom) == "MULTIPOLYGON");
REQUIRE(geom.n_points() == 5);
REQUIRE(dimension(geom) == 2);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(1.0));
Expand Down Expand Up @@ -56,6 +57,7 @@ TEST_CASE("multipolygon geometry with two polygons", "[NoDB]")
mp.add_geometry(std::move(polygon));

REQUIRE(geometry_type(geom) == "MULTIPOLYGON");
REQUIRE(geom.n_points() == 15);
REQUIRE(dimension(geom) == 2);
REQUIRE(num_geometries(geom) == 2);
REQUIRE(area(geom) == Approx(9.0));
Expand All @@ -76,6 +78,7 @@ TEST_CASE("create_multipolygon creates simple polygon from OSM data", "[NoDB]")

REQUIRE(geom.is_polygon());
REQUIRE(geometry_type(geom) == "POLYGON");
REQUIRE(geom.n_points() == 5);
REQUIRE(dimension(geom) == 2);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(1.0));
Expand All @@ -99,6 +102,7 @@ TEST_CASE("create_multipolygon from OSM data", "[NoDB]")
geom::create_multipolygon(relation, buffer.buffer(), &area_buffer);

REQUIRE(geom.is_multipolygon());
REQUIRE(geom.n_points() == 9);
REQUIRE(geometry_type(geom) == "MULTIPOLYGON");
REQUIRE(num_geometries(geom) == 2);
REQUIRE(area(geom) == Approx(51.0));
Expand Down
1 change: 1 addition & 0 deletions tests/test-geom-null.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ TEST_CASE("null geometry", "[NoDB]")
{
geom::geometry_t const geom{};

REQUIRE(geom.n_points() == 0);
REQUIRE(dimension(geom) == 0);
REQUIRE(num_geometries(geom) == 0);
REQUIRE(area(geom) == Approx(0.0));
Expand Down
1 change: 1 addition & 0 deletions tests/test-geom-points.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ TEST_CASE("create_point from OSM data", "[NoDB]")

REQUIRE(geom.is_point());
REQUIRE(geometry_type(geom) == "POINT");
REQUIRE(geom.n_points() == 1);
REQUIRE(dimension(geom) == 0);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(0.0));
Expand Down
3 changes: 3 additions & 0 deletions tests/test-geom-polygons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ TEST_CASE("polygon geometry without inner", "[NoDB]")
geom::geometry_t const geom{
geom::polygon_t{geom::ring_t{{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}}}};

REQUIRE(geom.n_points() == 5);
REQUIRE(dimension(geom) == 2);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(1.0));
Expand All @@ -38,6 +39,7 @@ TEST_CASE("polygon geometry without inner (reverse)", "[NoDB]")
geom::geometry_t const geom{
geom::polygon_t{geom::ring_t{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}}};

REQUIRE(geom.n_points() == 5);
REQUIRE(dimension(geom) == 2);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(1.0));
Expand All @@ -62,6 +64,7 @@ TEST_CASE("geom::polygon_t", "[NoDB]")
REQUIRE(polygon.inners().size() == 1);

geom::geometry_t const geom{std::move(polygon)};
REQUIRE(geom.n_points() == 10);
REQUIRE(dimension(geom) == 2);
REQUIRE(num_geometries(geom) == 1);
REQUIRE(area(geom) == Approx(8.0));
Expand Down
Loading