Skip to content

Commit 943ca1a

Browse files
committed
Large refactoring of the geometry code
Pulls apart the different concerns: * geometry generation from OSM data * geometry processing (like merging and splitting linestrings) * conversion to WKB For all of this to work we switch to C++17 as minimum requirement. This also adds some code (in src/geom-boost-adaptor.hpp) that adapts our data structures to boost::geometry. This is not used yet, but can in the future be used for more complex geometry processing.
1 parent 02d7d7d commit 943ca1a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1911
-1481
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ jobs:
7777
LUAJIT_OPTION: OFF
7878
POSTGRESQL_VERSION: 10
7979
POSTGIS_VERSION: 3
80-
CPP_VERSION: 14
80+
CPP_VERSION: 17
8181
BUILD_TYPE: Debug
8282

8383
steps:
@@ -96,7 +96,7 @@ jobs:
9696
LUAJIT_OPTION: OFF
9797
POSTGRESQL_VERSION: 11
9898
POSTGIS_VERSION: 2.5
99-
CPP_VERSION: 14
99+
CPP_VERSION: 17
100100
BUILD_TYPE: Debug
101101

102102
steps:
@@ -114,7 +114,7 @@ jobs:
114114
LUAJIT_OPTION: ON
115115
POSTGRESQL_VERSION: 12
116116
POSTGIS_VERSION: 2.5
117-
CPP_VERSION: 14
117+
CPP_VERSION: 17
118118
BUILD_TYPE: Debug
119119

120120
steps:
@@ -133,7 +133,7 @@ jobs:
133133
LUAJIT_OPTION: ON
134134
POSTGRESQL_VERSION: 13
135135
POSTGIS_VERSION: 3
136-
CPP_VERSION: 14
136+
CPP_VERSION: 17
137137
BUILD_TYPE: Debug
138138

139139
steps:
@@ -151,7 +151,7 @@ jobs:
151151
LUAJIT_OPTION: OFF
152152
POSTGRESQL_VERSION: 13
153153
POSTGIS_VERSION: 3
154-
CPP_VERSION: 14
154+
CPP_VERSION: 17
155155
USE_PROJ_LIB: 6
156156
BUILD_TYPE: Debug
157157

@@ -170,7 +170,7 @@ jobs:
170170
LUAJIT_OPTION: OFF
171171
POSTGRESQL_VERSION: 13
172172
POSTGIS_VERSION: 3
173-
CPP_VERSION: 14
173+
CPP_VERSION: 17
174174
USE_PROJ_LIB: off
175175
BUILD_TYPE: Debug
176176

@@ -208,7 +208,7 @@ jobs:
208208
LUAJIT_OPTION: ON
209209
POSTGRESQL_VERSION: 13
210210
POSTGIS_VERSION: 2.5
211-
CPP_VERSION: 14
211+
CPP_VERSION: 17
212212
BUILD_TYPE: Release
213213

214214
steps:

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ if (NOT CMAKE_BUILD_TYPE)
3838
endif()
3939

4040
if (NOT "${CMAKE_CXX_STANDARD}")
41-
set(CMAKE_CXX_STANDARD 14)
41+
set(CMAKE_CXX_STANDARD 17)
4242
endif()
4343
message(STATUS "Building in C++${CMAKE_CXX_STANDARD} mode")
4444
set(CMAKE_CXX_EXTENSIONS OFF)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ It also requires access to a database server running
7070
[PostGIS](https://www.postgis.net/) 2.2+.
7171

7272
Make sure you have installed the development packages for the libraries
73-
mentioned in the requirements section and a C++ compiler which supports C++14.
73+
mentioned in the requirements section and a C++ compiler which supports C++17.
7474
We officially support gcc >= 7.0 and clang >= 8.
7575

7676
To rebuild the included man page you'll need the [pandoc](https://pandoc.org/)

src/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ target_sources(osm2pgsql_lib PRIVATE
88
expire-tiles.cpp
99
gazetteer-style.cpp
1010
geom.cpp
11+
geom-from-osm.cpp
12+
geom-functions.cpp
1113
input.cpp
1214
logging.cpp
1315
middle.cpp
@@ -18,7 +20,6 @@ target_sources(osm2pgsql_lib PRIVATE
1820
options.cpp
1921
ordered-index.cpp
2022
osmdata.cpp
21-
osmium-builder.cpp
2223
output-gazetteer.cpp
2324
output-null.cpp
2425
output-pgsql.cpp
@@ -34,6 +35,7 @@ target_sources(osm2pgsql_lib PRIVATE
3435
thread-pool.cpp
3536
util.cpp
3637
wildcmp.cpp
38+
wkb.cpp
3739
)
3840

3941
if (LUA_FOUND OR LUAJIT_FOUND)

src/expire-tiles.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,10 @@ uint32_t expire_tiles::normalise_tile_x_coord(int x) const
128128
void expire_tiles::coords_to_tile(double lon, double lat, double *tilex,
129129
double *tiley)
130130
{
131-
auto const c =
132-
projection->target_to_tile(osmium::geom::Coordinates{lon, lat});
131+
auto const c = projection->target_to_tile(geom::point_t{lon, lat});
133132

134-
*tilex = map_width * (0.5 + c.x / EARTH_CIRCUMFERENCE);
135-
*tiley = map_width * (0.5 - c.y / EARTH_CIRCUMFERENCE);
133+
*tilex = map_width * (0.5 + c.x() / EARTH_CIRCUMFERENCE);
134+
*tiley = map_width * (0.5 - c.y() / EARTH_CIRCUMFERENCE);
136135
}
137136

138137
/*

src/flex-table.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
#include "db-copy-mgr.hpp"
1414
#include "flex-table-column.hpp"
15-
#include "osmium-builder.hpp"
1615
#include "pgsql.hpp"
16+
#include "reprojection.hpp"
1717
#include "thread-pool.hpp"
1818

1919
#include <osmium/osm/item_type.hpp>
@@ -232,7 +232,7 @@ class table_connection_t
232232
public:
233233
table_connection_t(flex_table_t *table,
234234
std::shared_ptr<db_copy_thread_t> const &copy_thread)
235-
: m_builder(reprojection::create_projection(table->srid())), m_table(table),
235+
: m_proj(reprojection::create_projection(table->srid())), m_table(table),
236236
m_target(std::make_shared<db_target_descr_t>(
237237
table->name(), table->id_column_names(),
238238
table->build_sql_column_list())),
@@ -268,7 +268,11 @@ class table_connection_t
268268

269269
void delete_rows_with(osmium::item_type type, osmid_t id);
270270

271-
geom::osmium_builder_t *get_builder() { return &m_builder; }
271+
reprojection const &proj() const noexcept
272+
{
273+
assert(m_proj);
274+
return *m_proj;
275+
}
272276

273277
void task_set(std::future<std::chrono::milliseconds> &&future)
274278
{
@@ -278,7 +282,7 @@ class table_connection_t
278282
void task_wait();
279283

280284
private:
281-
geom::osmium_builder_t m_builder;
285+
std::shared_ptr<reprojection> m_proj;
282286

283287
flex_table_t *m_table;
284288

src/geom-from-osm.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/**
2+
* SPDX-License-Identifier: GPL-2.0-or-later
3+
*
4+
* This file is part of osm2pgsql (https://osm2pgsql.org/).
5+
*
6+
* Copyright (C) 2006-2022 by the osm2pgsql developer community.
7+
* For a full list of authors see the git log.
8+
*/
9+
10+
#include "geom-from-osm.hpp"
11+
#include "osmtypes.hpp"
12+
13+
#include <osmium/area/geom_assembler.hpp>
14+
#include <osmium/osm/way.hpp>
15+
16+
#include <utility>
17+
18+
namespace geom {
19+
20+
geometry_t create_point(osmium::Node const &node)
21+
{
22+
return geometry_t{point_t{node.location()}};
23+
}
24+
25+
static void fill_point_list(point_list_t *list,
26+
osmium::NodeRefList const &nodes)
27+
{
28+
osmium::Location last{};
29+
30+
for (auto const &node : nodes) {
31+
auto const loc = node.location();
32+
if (loc.valid() && loc != last) {
33+
list->emplace_back(loc);
34+
last = loc;
35+
}
36+
}
37+
}
38+
39+
geometry_t create_linestring(osmium::Way const &way)
40+
{
41+
geometry_t geom{linestring_t{}};
42+
auto &line = geom.get<linestring_t>();
43+
44+
fill_point_list(&line, way.nodes());
45+
46+
// Return nullgeom_t if the line geometry is invalid
47+
if (line.size() <= 1U) {
48+
geom.reset();
49+
}
50+
51+
return geom;
52+
}
53+
54+
geometry_t create_polygon(osmium::Way const &way)
55+
{
56+
geometry_t geom{polygon_t{}};
57+
58+
// A closed way with less than 4 nodes can never be a valid polygon
59+
if (way.nodes().size() < 4U) {
60+
geom.reset();
61+
return geom;
62+
}
63+
64+
osmium::area::AssemblerConfig area_config;
65+
area_config.ignore_invalid_locations = true;
66+
osmium::area::GeomAssembler assembler{area_config};
67+
osmium::memory::Buffer area_buffer{1024};
68+
69+
if (!assembler(way, area_buffer)) {
70+
geom.reset();
71+
return geom;
72+
}
73+
74+
auto const &area = area_buffer.get<osmium::Area>(0);
75+
auto const &ring = *area.begin<osmium::OuterRing>();
76+
77+
fill_point_list(&geom.get<polygon_t>().outer(), ring);
78+
79+
return geom;
80+
}
81+
82+
geometry_t create_multilinestring(osmium::memory::Buffer const &ways)
83+
{
84+
geometry_t geom{multilinestring_t{}};
85+
auto &mls = geom.get<multilinestring_t>();
86+
87+
for (auto const &way : ways.select<osmium::Way>()) {
88+
linestring_t line;
89+
fill_point_list(&line, way.nodes());
90+
if (line.size() >= 2U) {
91+
mls.add_geometry(std::move(line));
92+
}
93+
}
94+
95+
if (mls.num_geometries() == 0) {
96+
geom.reset();
97+
}
98+
99+
return geom;
100+
}
101+
102+
static void fill_polygon(polygon_t *polygon, osmium::Area const &area,
103+
osmium::OuterRing const &outer_ring)
104+
{
105+
assert(polygon->inners().empty());
106+
107+
for (auto const &nr : outer_ring) {
108+
polygon->outer().emplace_back(nr.location());
109+
}
110+
111+
for (auto const &inner_ring : area.inner_rings(outer_ring)) {
112+
auto &ring = polygon->inners().emplace_back();
113+
for (auto const &nr : inner_ring) {
114+
ring.emplace_back(nr.location());
115+
}
116+
}
117+
}
118+
119+
geometry_t create_multipolygon(osmium::Relation const &relation,
120+
osmium::memory::Buffer const &way_buffer)
121+
{
122+
geometry_t geom{};
123+
124+
osmium::area::AssemblerConfig area_config;
125+
area_config.ignore_invalid_locations = true;
126+
osmium::area::GeomAssembler assembler{area_config};
127+
osmium::memory::Buffer area_buffer{1024};
128+
129+
if (!assembler(relation, way_buffer, area_buffer)) {
130+
return geom;
131+
}
132+
133+
auto const &area = area_buffer.get<osmium::Area>(0);
134+
135+
if (area.is_multipolygon()) {
136+
auto &multipolygon = geom.set<multipolygon_t>();
137+
138+
for (auto const &outer : area.outer_rings()) {
139+
auto &polygon = multipolygon.add_geometry();
140+
fill_polygon(&polygon, area, outer);
141+
}
142+
} else {
143+
auto &polygon = geom.set<polygon_t>();
144+
fill_polygon(&polygon, area, *area.outer_rings().begin());
145+
}
146+
147+
return geom;
148+
}
149+
150+
} // namespace geom

src/geom-from-osm.hpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#ifndef OSM2PGSQL_GEOM_FROM_OSM_HPP
2+
#define OSM2PGSQL_GEOM_FROM_OSM_HPP
3+
4+
/**
5+
* SPDX-License-Identifier: GPL-2.0-or-later
6+
*
7+
* This file is part of osm2pgsql (https://osm2pgsql.org/).
8+
*
9+
* Copyright (C) 2006-2022 by the osm2pgsql developer community.
10+
* For a full list of authors see the git log.
11+
*/
12+
13+
#include "geom.hpp"
14+
15+
#include <osmium/fwd.hpp>
16+
#include <osmium/memory/buffer.hpp>
17+
18+
/**
19+
* \file
20+
*
21+
* Functions to create geometries from OSM data.
22+
*/
23+
24+
namespace geom {
25+
26+
/**
27+
* Create a point geometry from a node.
28+
*
29+
* \param node The input node.
30+
* \returns The created geometry.
31+
*/
32+
geometry_t create_point(osmium::Node const &node);
33+
34+
/**
35+
* Create a linestring geometry from a way. Nodes without location are ignored.
36+
* Consecutive nodes with the same location will only end up once in the
37+
* linestring.
38+
*
39+
* If the resulting linestring would be invalid (< 1 nodes), a null geometry
40+
* is returned.
41+
*
42+
* \param way The input way.
43+
* \returns The created geometry.
44+
*/
45+
geometry_t create_linestring(osmium::Way const &way);
46+
47+
/**
48+
* Create a polygon geometry from a way.
49+
*
50+
* If the resulting polygon would be invalid, a null geometry is returned.
51+
*
52+
* \param way The input way.
53+
* \returns The created geometry.
54+
*/
55+
geometry_t create_polygon(osmium::Way const &way);
56+
57+
/**
58+
* Create a multilinestring geometry from a bunch of ways (usually this
59+
* would be used for member ways of a relation). The result is always a
60+
* multilinestring, even if it only contains one linestring.
61+
*
62+
* If the resulting multilinestring would be invalid, a null geometry is
63+
* returned.
64+
*
65+
* \param ways Buffer containing all the input ways.
66+
* \returns The created geometry.
67+
*/
68+
geometry_t create_multilinestring(osmium::memory::Buffer const &ways);
69+
70+
/**
71+
* Create a (multi)polygon geometry from a relation and member ways.
72+
*
73+
* If the resulting (multi)polygon would be invalid, a null geometry is
74+
* returned.
75+
*
76+
* \param relation The input relation.
77+
* \param way_buffer Buffer containing all member ways.
78+
* \returns The created geometry.
79+
*/
80+
geometry_t create_multipolygon(osmium::Relation const &relation,
81+
osmium::memory::Buffer const &way_buffer);
82+
83+
} // namespace geom
84+
85+
#endif // OSM2PGSQL_GEOM_FROM_OSM_HPP

0 commit comments

Comments
 (0)