Skip to content

Commit 1e3dfe5

Browse files
committed
Add linestring type
1 parent 75853d0 commit 1e3dfe5

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

src/geom.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
#include "geom.hpp"
1111

12+
#include <algorithm>
13+
#include <iterator>
14+
1215
namespace geom {
1316

1417
double distance(osmium::geom::Coordinates p1,
@@ -27,5 +30,28 @@ osmium::geom::Coordinates interpolate(osmium::geom::Coordinates p1,
2730
frac * (p1.y - p2.y) + p2.y};
2831
}
2932

33+
linestring_t::linestring_t(
34+
std::initializer_list<osmium::geom::Coordinates> coords)
35+
{
36+
std::copy(coords.begin(), coords.end(), std::back_inserter(m_coordinates));
37+
}
38+
39+
linestring_t::linestring_t(osmium::NodeRefList const &nodes,
40+
reprojection const &proj)
41+
{
42+
osmium::Location last{};
43+
for (auto const &node : nodes) {
44+
auto const loc = node.location();
45+
if (loc.valid() && loc != last) {
46+
add_point(proj.reproject(loc));
47+
last = loc;
48+
}
49+
}
50+
51+
if (size() <= 1) {
52+
m_coordinates.clear();
53+
}
54+
}
55+
3056
} // namespace geom
3157

src/geom.hpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,108 @@
1616
* Low level geometry functions and types.
1717
*/
1818

19+
#include "reprojection.hpp"
20+
1921
#include <osmium/geom/coordinates.hpp>
22+
#include <osmium/osm/node_ref_list.hpp>
23+
24+
#include <initializer_list>
25+
#include <ostream>
26+
#include <vector>
2027

2128
namespace geom {
2229

30+
/// Calculate the Euclidean distance between two coordinates
2331
double distance(osmium::geom::Coordinates p1,
2432
osmium::geom::Coordinates p2) noexcept;
2533

2634
osmium::geom::Coordinates interpolate(osmium::geom::Coordinates p1,
2735
osmium::geom::Coordinates p2,
2836
double frac) noexcept;
2937

38+
class linestring_t
39+
{
40+
public:
41+
linestring_t() = default;
42+
43+
linestring_t(std::initializer_list<osmium::geom::Coordinates> coords);
44+
45+
/**
46+
* Construct a linestring from a way node list. Nodes without location
47+
* are ignored. Consecutive nodes with the same location will only end
48+
* up once in the linestring.
49+
*
50+
* The resulting linestring will either be empty or have at least two
51+
* points in it.
52+
*
53+
* \param nodes The input nodes.
54+
* \param proj The projection used to project all coordinates.
55+
*/
56+
linestring_t(osmium::NodeRefList const &nodes, reprojection const &proj);
57+
58+
using iterator = std::vector<osmium::geom::Coordinates>::iterator;
59+
60+
using const_iterator =
61+
std::vector<osmium::geom::Coordinates>::const_iterator;
62+
63+
bool empty() const noexcept { return m_coordinates.empty(); }
64+
65+
std::size_t size() const noexcept { return m_coordinates.size(); }
66+
67+
void clear() noexcept { m_coordinates.clear(); }
68+
69+
void add_point(osmium::geom::Coordinates coordinates)
70+
{
71+
m_coordinates.emplace_back(std::move(coordinates));
72+
}
73+
74+
iterator begin() noexcept { return m_coordinates.begin(); }
75+
76+
iterator end() noexcept { return m_coordinates.end(); }
77+
78+
const_iterator begin() const noexcept { return m_coordinates.cbegin(); }
79+
80+
const_iterator end() const noexcept { return m_coordinates.cend(); }
81+
82+
const_iterator cbegin() const noexcept { return m_coordinates.cbegin(); }
83+
84+
const_iterator cend() const noexcept { return m_coordinates.cend(); }
85+
86+
osmium::geom::Coordinates &operator[](std::size_t n) noexcept
87+
{
88+
return m_coordinates[n];
89+
}
90+
91+
osmium::geom::Coordinates operator[](std::size_t n) const noexcept
92+
{
93+
return m_coordinates[n];
94+
}
95+
96+
private:
97+
std::vector<osmium::geom::Coordinates> m_coordinates;
98+
99+
}; // class linestring_t
100+
101+
/// Output a linestring in WKT format. Used for debugging.
102+
template <typename TChar, typename TTraits>
103+
std::basic_ostream<TChar, TTraits> &
104+
operator<<(std::basic_ostream<TChar, TTraits> &out, const linestring_t &line)
105+
{
106+
out << "LINESTRING(";
107+
108+
bool first = true;
109+
for (auto const coord : line) {
110+
if (first) {
111+
first = false;
112+
} else {
113+
out << ',';
114+
}
115+
out << coord.x << ' ' << coord.y;
116+
}
117+
118+
return out << ')';
119+
}
120+
30121
} // namespace geom
31122

32123
#endif // OSM2PGSQL_GEOM_HPP

tests/test-geom.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,23 @@ TEST_CASE("geom::interpolate", "[NoDB]")
4040
REQUIRE(i3.y == 10);
4141
}
4242

43+
TEST_CASE("geom::linestring_t", "[NoDB]")
44+
{
45+
geom::linestring_t ls1;
46+
47+
REQUIRE(ls1.empty());
48+
ls1.add_point(osmium::geom::Coordinates{17, 42});
49+
ls1.add_point(osmium::geom::Coordinates{-3, 22});
50+
REQUIRE(!ls1.empty());
51+
REQUIRE(ls1.size() == 2);
52+
53+
auto it = ls1.cbegin();
54+
REQUIRE(it != ls1.cend());
55+
REQUIRE(it->x == 17);
56+
++it;
57+
REQUIRE(it != ls1.cend());
58+
REQUIRE(it->y == 22);
59+
++it;
60+
REQUIRE(it == ls1.cend());
61+
}
62+

0 commit comments

Comments
 (0)