Skip to content

Commit a3d4787

Browse files
authored
Merge pull request #2477 from joto/n-points
New function n_points() to get the number of points in any geometry
2 parents f7c7a04 + 916e78b commit a3d4787

12 files changed

Lines changed: 92 additions & 4 deletions

src/flex-lua-geom.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,20 @@ int geom_centroid(lua_State *lua_state)
114114
return 1;
115115
}
116116

117+
int geom_n_points(lua_State *lua_state)
118+
{
119+
auto const *const input_geometry = unpack_geometry(lua_state);
120+
121+
try {
122+
lua_pushinteger(lua_state,
123+
static_cast<lua_Integer>(input_geometry->n_points()));
124+
} catch (...) {
125+
return luaL_error(lua_state, "Unknown error in 'n_points()'.\n");
126+
}
127+
128+
return 1;
129+
}
130+
117131
int geom_geometry_n(lua_State *lua_state)
118132
{
119133
auto const *const input_geometry = unpack_geometry(lua_state);
@@ -313,6 +327,7 @@ void init_geometry_class(lua_State *lua_state)
313327
{"geometry_type", geom_geometry_type},
314328
{"is_null", geom_is_null},
315329
{"line_merge", geom_line_merge},
330+
{"n_points", geom_n_points},
316331
{"reverse", geom_reverse},
317332
{"num_geometries", geom_num_geometries},
318333
{"pole_of_inaccessibility", geom_pole_of_inaccessibility},

src/geom.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,25 @@ bool operator!=(polygon_t const &a, polygon_t const &b) noexcept
3030
return !(a == b);
3131
}
3232

33+
[[nodiscard]] std::size_t polygon_t::n_points() const
34+
{
35+
return m_outer.size() +
36+
std::accumulate(m_inners.cbegin(), m_inners.cend(), std::size_t{0},
37+
[](std::size_t sum, ring_t const &ring) {
38+
return sum + ring.size();
39+
});
40+
}
41+
42+
[[nodiscard]] std::size_t geometry_t::n_points() const
43+
{
44+
return visit([](auto const &input) { return input.n_points(); });
45+
}
46+
47+
std::size_t n_points(geometry_t const &geom)
48+
{
49+
return geom.visit([](auto const &input) { return input.n_points(); });
50+
}
51+
3352
std::size_t dimension(collection_t const &geom)
3453
{
3554
return std::accumulate(geom.cbegin(), geom.cend(), 0ULL,

src/geom.hpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <cassert>
2525
#include <cmath>
2626
#include <initializer_list>
27+
#include <numeric>
2728
#include <type_traits>
2829
#include <utility>
2930
#include <variant>
@@ -39,6 +40,11 @@ class nullgeom_t
3940
return 0;
4041
}
4142

43+
[[nodiscard]] constexpr static std::size_t n_points() noexcept
44+
{
45+
return 0;
46+
}
47+
4248
[[nodiscard]] constexpr friend bool operator==(nullgeom_t,
4349
nullgeom_t) noexcept
4450
{
@@ -69,6 +75,11 @@ class point_t
6975
return 1;
7076
}
7177

78+
[[nodiscard]] constexpr static std::size_t n_points() noexcept
79+
{
80+
return 1;
81+
}
82+
7283
[[nodiscard]] constexpr double x() const noexcept { return m_x; }
7384
[[nodiscard]] constexpr double y() const noexcept { return m_y; }
7485

@@ -148,6 +159,11 @@ class linestring_t : public point_list_t
148159
return 1;
149160
}
150161

162+
[[nodiscard]] std::size_t n_points() const noexcept
163+
{
164+
return size();
165+
}
166+
151167
}; // class linestring_t
152168

153169
class ring_t : public point_list_t
@@ -186,6 +202,8 @@ class polygon_t
186202

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

205+
[[nodiscard]] std::size_t n_points() const;
206+
189207
private:
190208
ring_t m_outer;
191209
std::vector<ring_t> m_inners;
@@ -257,6 +275,15 @@ class multigeometry_t
257275

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

278+
[[nodiscard]] std::size_t n_points() const
279+
{
280+
return std::accumulate(m_geometry.cbegin(), m_geometry.cend(),
281+
std::size_t{0},
282+
[](std::size_t sum, auto const &geom) {
283+
return sum + geom.n_points();
284+
});
285+
}
286+
260287
private:
261288
std::vector<GEOM> m_geometry;
262289

@@ -400,6 +427,8 @@ class geometry_t
400427
return !(a == b);
401428
}
402429

430+
[[nodiscard]] std::size_t n_points() const;
431+
403432
private:
404433
std::variant<nullgeom_t, point_t, linestring_t, polygon_t, multipoint_t,
405434
multilinestring_t, multipolygon_t, collection_t>

tests/bdd/flex/geometry-linestring.feature

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ Feature: Creating linestring features from way
1616
{ column = 'sgeom', type = 'linestring', projection = 4326 },
1717
{ column = 'mgeom', type = 'multilinestring', projection = 4326 },
1818
{ column = 'xgeom', type = 'multilinestring', projection = 4326 },
19+
{ column = 'npoints', type = 'int' },
1920
})
2021
2122
function osm2pgsql.process_way(object)
2223
if object.tags.highway == 'motorway' then
2324
lines:insert({
2425
sgeom = object:as_linestring(),
2526
mgeom = object:as_multilinestring(),
26-
xgeom = object:as_linestring()
27+
xgeom = object:as_linestring(),
28+
npoints = object:as_linestring():n_points(),
2729
})
2830
end
2931
end
@@ -32,9 +34,9 @@ Feature: Creating linestring features from way
3234
When running osm2pgsql flex
3335

3436
Then table osm2pgsql_test_lines contains exactly
35-
| way_id | sgeom!geo | mgeom!geo | xgeom!geo |
36-
| 20 | 1, 2, 3 | [ 1, 2, 3 ] | [ 1, 2, 3 ] |
37-
| 21 | 4, 5 | [ 4, 5 ] | [ 4, 5 ] |
37+
| way_id | sgeom!geo | mgeom!geo | xgeom!geo | npoints |
38+
| 20 | 1, 2, 3 | [ 1, 2, 3 ] | [ 1, 2, 3 ] | 3 |
39+
| 21 | 4, 5 | [ 4, 5 ] | [ 4, 5 ] | 2 |
3840

3941
Scenario:
4042
Given the grid

tests/test-geom-collections.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ TEST_CASE("geometry collection with point", "[NoDB]")
2424
c.add_geometry(geom::geometry_t{geom::point_t{1, 1}});
2525

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

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

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

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

102106
REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
107+
REQUIRE(geom.n_points() == 8);
103108
REQUIRE(dimension(geom) == 1);
104109
REQUIRE(num_geometries(geom) == 3);
105110

tests/test-geom-linestrings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ TEST_CASE("line geometry", "[NoDB]")
5252
{
5353
geom::geometry_t const geom{geom::linestring_t{{1, 1}, {2, 2}}};
5454

55+
REQUIRE(geom.n_points() == 2);
5556
REQUIRE(dimension(geom) == 1);
5657
REQUIRE(num_geometries(geom) == 1);
5758
REQUIRE(area(geom) == Approx(0.0));

tests/test-geom-multilinestrings.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ TEST_CASE("create_multilinestring with single line", "[NoDB]")
3232

3333
REQUIRE(geom.is_multilinestring());
3434
REQUIRE(geometry_type(geom) == "MULTILINESTRING");
35+
REQUIRE(geom.n_points() == 2);
3536
REQUIRE(dimension(geom) == 1);
3637
REQUIRE(num_geometries(geom) == 1);
3738
REQUIRE(area(geom) == Approx(0.0));
@@ -59,6 +60,7 @@ TEST_CASE("create_multilinestring with single line and no force_multi",
5960

6061
REQUIRE(geom.is_linestring());
6162
REQUIRE(geometry_type(geom) == "LINESTRING");
63+
REQUIRE(geom.n_points() == 2);
6264
REQUIRE(num_geometries(geom) == 1);
6365
REQUIRE(area(geom) == Approx(0.0));
6466
REQUIRE(spherical_area(geom) == Approx(0.0));
@@ -132,6 +134,7 @@ TEST_CASE("create_multilinestring from two non-joined lines", "[NoDB]")
132134
geom::line_merge(geom::create_multilinestring(buffer.buffer()));
133135

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

153156
REQUIRE(geom.is_multilinestring());
154157
auto const &ml = geom.get<geom::multilinestring_t>();
158+
REQUIRE(ml.n_points() == 3);
155159
REQUIRE(ml.num_geometries() == 1);
156160
REQUIRE(ml[0] == expected);
157161
}
@@ -292,6 +296,7 @@ TEST_CASE("create_multilinestring from Y shape", "[NoDB]")
292296
REQUIRE(geom.is_multilinestring());
293297
auto const &ml = geom.get<geom::multilinestring_t>();
294298
REQUIRE(ml.num_geometries() == 2);
299+
REQUIRE(ml.n_points() == 5);
295300
REQUIRE(ml[0] == expected[0]);
296301
REQUIRE(ml[1] == expected[1]);
297302
}

tests/test-geom-multipoints.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ TEST_CASE("multipoint_t with a single point", "[NoDB]")
2929

3030
REQUIRE(geom.is_multipoint());
3131
REQUIRE(geometry_type(geom) == "MULTIPOINT");
32+
REQUIRE(geom.n_points() == 1);
3233
REQUIRE(dimension(geom) == 0);
3334
REQUIRE(num_geometries(geom) == 1);
3435
REQUIRE(area(geom) == Approx(0.0));
@@ -54,6 +55,7 @@ TEST_CASE("multipoint_t with several points", "[NoDB]")
5455

5556
REQUIRE(geom.is_multipoint());
5657
REQUIRE(geometry_type(geom) == "MULTIPOINT");
58+
REQUIRE(geom.n_points() == 3);
5759
REQUIRE(num_geometries(geom) == 3);
5860
REQUIRE(area(geom) == Approx(0.0));
5961
REQUIRE(spherical_area(geom) == Approx(0.0));
@@ -85,6 +87,7 @@ TEST_CASE("create_multipoint from OSM data", "[NoDB]")
8587

8688
REQUIRE(geometry_type(geom) == "MULTIPOINT");
8789
REQUIRE(dimension(geom) == 0);
90+
REQUIRE(geom.n_points() == 4);
8891
REQUIRE(num_geometries(geom) == 4);
8992

9093
auto const &c = geom.get<geom::multipoint_t>();

tests/test-geom-multipolygons.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ TEST_CASE("multipolygon geometry with single outer, no inner", "[NoDB]")
2626
geom::polygon_t{geom::ring_t{{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}}});
2727

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

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

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

101104
REQUIRE(geom.is_multipolygon());
105+
REQUIRE(geom.n_points() == 9);
102106
REQUIRE(geometry_type(geom) == "MULTIPOLYGON");
103107
REQUIRE(num_geometries(geom) == 2);
104108
REQUIRE(area(geom) == Approx(51.0));

tests/test-geom-null.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ TEST_CASE("null geometry", "[NoDB]")
1818
{
1919
geom::geometry_t const geom{};
2020

21+
REQUIRE(geom.n_points() == 0);
2122
REQUIRE(dimension(geom) == 0);
2223
REQUIRE(num_geometries(geom) == 0);
2324
REQUIRE(area(geom) == Approx(0.0));

0 commit comments

Comments
 (0)