Skip to content

Commit a8f169f

Browse files
authored
Merge pull request #1777 from iboates/add_length
length for flex output
2 parents ec36916 + cf30555 commit a8f169f

11 files changed

+66
-5
lines changed

src/flex-lua-geom.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ static int geom_area(lua_State *lua_state)
6969
return 1;
7070
}
7171

72+
static int geom_length(lua_State *lua_state)
73+
{
74+
auto const *const input_geometry = unpack_geometry(lua_state);
75+
try {
76+
lua_pushnumber(lua_state, geom::length(*input_geometry));
77+
} catch (...) {
78+
return luaL_error(lua_state, "Unknown error in 'length()'.\n");
79+
}
80+
81+
return 1;
82+
}
83+
7284
static int geom_centroid(lua_State *lua_state)
7385
{
7486
auto const *const input_geometry = unpack_geometry(lua_state);
@@ -239,6 +251,7 @@ void init_geometry_class(lua_State *lua_state)
239251
lua_pushvalue(lua_state, -1);
240252
lua_setfield(lua_state, -2, "__index");
241253
luaX_add_table_func(lua_state, "area", geom_area);
254+
luaX_add_table_func(lua_state, "length", geom_length);
242255
luaX_add_table_func(lua_state, "centroid", geom_centroid);
243256
luaX_add_table_func(lua_state, "geometry_n", geom_geometry_n);
244257
luaX_add_table_func(lua_state, "geometry_type", geom_geometry_type);

src/geom-functions.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
* For a full list of authors see the git log.
88
*/
99

10-
#include "geom-boost-adaptor.hpp"
1110
#include "geom-functions.hpp"
11+
#include "geom-boost-adaptor.hpp"
1212

1313
#include <algorithm>
1414
#include <cmath>
@@ -378,6 +378,22 @@ double area(geometry_t const &geom)
378378
return std::abs(total);
379379
}
380380

381+
double length(geometry_t const &geom)
382+
{
383+
return geom.visit(overloaded{
384+
[&](geom::nullgeom_t const & /*input*/) { return 0.0; },
385+
[&](geom::collection_t const &input) {
386+
double total = 0.0;
387+
for (auto const &item : input) {
388+
total += length(item);
389+
}
390+
return total;
391+
},
392+
[&](auto const &input) {
393+
return static_cast<double>(boost::geometry::length(input));
394+
}});
395+
}
396+
381397
namespace {
382398

383399
class split_visitor
@@ -414,7 +430,7 @@ class split_visitor
414430

415431
} // anonymous namespace
416432

417-
std::vector<geometry_t> split_multi(geometry_t&& geom, bool split_multi)
433+
std::vector<geometry_t> split_multi(geometry_t &&geom, bool split_multi)
418434
{
419435
std::vector<geometry_t> output;
420436

src/geom-functions.hpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ point_t interpolate(point_t p1, point_t p2, double frac) noexcept;
4141
* \pre \code !list.empty() \endcode
4242
*/
4343
template <typename FUNC>
44-
void for_each_segment(point_list_t const &list, FUNC&& func)
44+
void for_each_segment(point_list_t const &list, FUNC &&func)
4545
{
4646
assert(!list.empty());
4747
auto it = list.cbegin();
@@ -158,6 +158,16 @@ double area(geometry_t const &geom);
158158
*/
159159
std::vector<geometry_t> split_multi(geometry_t &&geom, bool split_multi = true);
160160

161+
/**
162+
* Calculate length of geometry.
163+
* For geometry types other than linestring or multilinestring this will always
164+
* return 0.
165+
*
166+
* \param geom Input geometry.
167+
* \returns Length.
168+
**/
169+
double length(geometry_t const &geom);
170+
161171
/**
162172
* Reverses the order of the vertices in geometry.
163173
*

tests/test-geom-collections.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ TEST_CASE("geometry collection with point", "[NoDB]")
2525
REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
2626
REQUIRE(num_geometries(geom) == 1);
2727
REQUIRE(area(geom) == Approx(0.0));
28+
REQUIRE(length(geom) == Approx(0.0));
2829
REQUIRE_THROWS(centroid(geom));
2930
REQUIRE(geometry_n(geom, 1) == geom::geometry_t{geom::point_t{1, 1}});
3031
}
@@ -41,6 +42,7 @@ TEST_CASE("geometry collection with several geometries", "[NoDB]")
4142
REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
4243
REQUIRE(num_geometries(geom) == 3);
4344
REQUIRE(area(geom) == Approx(0.0));
45+
REQUIRE(length(geom) == Approx(1.41421));
4446
REQUIRE_THROWS(centroid(geom));
4547
REQUIRE(geometry_n(geom, 1) == geom::geometry_t{geom::point_t{1, 1}});
4648
REQUIRE(geometry_n(geom, 2) ==
@@ -68,6 +70,7 @@ TEST_CASE("create_collection from OSM data", "[NoDB]")
6870
REQUIRE(c[2] == geom::geometry_t{geom::linestring_t{{10, 10}, {10, 20}}});
6971

7072
REQUIRE(area(geom) == Approx(0.0));
73+
REQUIRE(length(geom) == Approx(14.0));
7174
REQUIRE_THROWS(centroid(geom));
7275
}
7376

tests/test-geom-linestrings.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ TEST_CASE("line geometry", "[NoDB]")
4444

4545
REQUIRE(num_geometries(geom) == 1);
4646
REQUIRE(area(geom) == Approx(0.0));
47+
REQUIRE(length(geom) == Approx(1.41421));
4748
REQUIRE(geometry_type(geom) == "LINESTRING");
4849
REQUIRE(centroid(geom) == geom::geometry_t{geom::point_t{1.5, 1.5}});
4950
REQUIRE(geometry_n(geom, 1) == geom);
@@ -74,6 +75,7 @@ TEST_CASE("create_linestring from OSM data", "[NoDB]")
7475
REQUIRE(geometry_type(geom) == "LINESTRING");
7576
REQUIRE(num_geometries(geom) == 1);
7677
REQUIRE(area(geom) == Approx(0.0));
78+
REQUIRE(length(geom) == Approx(1.41421));
7779
REQUIRE(geom.get<geom::linestring_t>() ==
7880
geom::linestring_t{{1, 1}, {2, 2}});
7981
REQUIRE(centroid(geom) == geom::geometry_t{geom::point_t{1.5, 1.5}});

tests/test-geom-multilinestrings.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ TEST_CASE("create_multilinestring with single line", "[NoDB]")
3232
REQUIRE(geometry_type(geom) == "MULTILINESTRING");
3333
REQUIRE(num_geometries(geom) == 1);
3434
REQUIRE(area(geom) == Approx(0.0));
35+
REQUIRE(length(geom) == Approx(1.0));
3536
auto const &ml = geom.get<geom::multilinestring_t>();
3637
REQUIRE(ml.num_geometries() == 1);
3738
REQUIRE(ml[0] == expected);
@@ -56,6 +57,7 @@ TEST_CASE("create_multilinestring with single line and no force_multi",
5657
REQUIRE(geometry_type(geom) == "LINESTRING");
5758
REQUIRE(num_geometries(geom) == 1);
5859
REQUIRE(area(geom) == Approx(0.0));
60+
REQUIRE(length(geom) == Approx(1.0));
5961
auto const &l = geom.get<geom::linestring_t>();
6062
REQUIRE(l.num_geometries() == 1);
6163
REQUIRE(l == expected);

tests/test-geom-multipoints.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ TEST_CASE("multipoint_t with a single point", "[NoDB]")
3030
REQUIRE(geometry_type(geom) == "MULTIPOINT");
3131
REQUIRE(num_geometries(geom) == 1);
3232
REQUIRE(area(geom) == Approx(0.0));
33+
REQUIRE(length(geom) == Approx(0.0));
3334
REQUIRE(reverse(geom) == geom);
3435
REQUIRE(centroid(geom) == geom::geometry_t{std::move(point)});
3536

@@ -52,6 +53,7 @@ TEST_CASE("multipoint_t with several points", "[NoDB]")
5253
REQUIRE(geometry_type(geom) == "MULTIPOINT");
5354
REQUIRE(num_geometries(geom) == 3);
5455
REQUIRE(area(geom) == Approx(0.0));
56+
REQUIRE(length(geom) == Approx(0.0));
5557
REQUIRE(reverse(geom) == geom);
5658
REQUIRE(centroid(geom) == geom::geometry_t{geom::point_t{2, 1}});
5759

tests/test-geom-multipolygons.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ TEST_CASE("multipolygon geometry with single outer, no inner", "[NoDB]")
2626
REQUIRE(geometry_type(geom) == "MULTIPOLYGON");
2727
REQUIRE(num_geometries(geom) == 1);
2828
REQUIRE(area(geom) == Approx(1.0));
29+
REQUIRE(length(geom) == Approx(0.0));
2930
REQUIRE(centroid(geom) == geom::geometry_t{geom::point_t{0.5, 0.5}});
3031
REQUIRE(geometry_n(geom, 1) ==
3132
geom::geometry_t{geom::polygon_t{
@@ -52,6 +53,7 @@ TEST_CASE("multipolygon geometry with two polygons", "[NoDB]")
5253
REQUIRE(geometry_type(geom) == "MULTIPOLYGON");
5354
REQUIRE(num_geometries(geom) == 2);
5455
REQUIRE(area(geom) == Approx(9.0));
56+
REQUIRE(length(geom) == Approx(0.0));
5557
}
5658

5759
TEST_CASE("create_multipolygon creates simple polygon from OSM data", "[NoDB]")
@@ -67,6 +69,7 @@ TEST_CASE("create_multipolygon creates simple polygon from OSM data", "[NoDB]")
6769
REQUIRE(geometry_type(geom) == "POLYGON");
6870
REQUIRE(num_geometries(geom) == 1);
6971
REQUIRE(area(geom) == Approx(1.0));
72+
REQUIRE(length(geom) == Approx(0.0));
7073
REQUIRE(
7174
geom.get<geom::polygon_t>() ==
7275
geom::polygon_t{geom::ring_t{{1, 1}, {2, 1}, {2, 2}, {1, 2}, {1, 1}}});
@@ -87,6 +90,7 @@ TEST_CASE("create_multipolygon from OSM data", "[NoDB]")
8790
REQUIRE(geometry_type(geom) == "MULTIPOLYGON");
8891
REQUIRE(num_geometries(geom) == 2);
8992
REQUIRE(area(geom) == Approx(51.0));
93+
REQUIRE(length(geom) == Approx(0.0));
9094
}
9195

9296
TEST_CASE("create_multipolygon from OSM data without locations", "[NoDB]")
@@ -111,7 +115,8 @@ TEST_CASE("create_multipolygon from invalid OSM data (single node)", "[NoDB]")
111115
REQUIRE(geom.is_null());
112116
}
113117

114-
TEST_CASE("create_multipolygon from invalid OSM data (way node closed)", "[NoDB]")
118+
TEST_CASE("create_multipolygon from invalid OSM data (way node closed)",
119+
"[NoDB]")
115120
{
116121
test_buffer_t buffer;
117122
buffer.add_way("w20 Nn1x1y1,n2x2y2");
@@ -122,7 +127,8 @@ TEST_CASE("create_multipolygon from invalid OSM data (way node closed)", "[NoDB]
122127
REQUIRE(geom.is_null());
123128
}
124129

125-
TEST_CASE("create_multipolygon from invalid OSM data (self-intersection)", "[NoDB]")
130+
TEST_CASE("create_multipolygon from invalid OSM data (self-intersection)",
131+
"[NoDB]")
126132
{
127133
test_buffer_t buffer;
128134
buffer.add_way("w20 Nn1x1y1,n2x1y2,n3x2y1,n4x2y2");

tests/test-geom-null.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ TEST_CASE("null geometry", "[NoDB]")
1919

2020
REQUIRE(num_geometries(geom) == 0);
2121
REQUIRE(area(geom) == 0.0);
22+
REQUIRE(length(geom) == Approx(0.0));
2223
REQUIRE(geometry_type(geom) == "NULL");
2324
REQUIRE(centroid(geom).is_null());
2425
REQUIRE(geometry_n(geom, 1).is_null());

tests/test-geom-points.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ TEST_CASE("create_point from OSM data", "[NoDB]")
5252
REQUIRE(geometry_type(geom) == "POINT");
5353
REQUIRE(num_geometries(geom) == 1);
5454
REQUIRE(area(geom) == Approx(0.0));
55+
REQUIRE(length(geom) == Approx(0.0));
5556
REQUIRE(centroid(geom) == geom::geometry_t{geom::point_t{1.1, 2.2}});
5657
REQUIRE(geometry_n(geom, 1) == geom);
5758
REQUIRE(reverse(geom) == geom);

0 commit comments

Comments
 (0)