Skip to content

Commit cd127f4

Browse files
authored
Dump osm2rdf:length and osm2rdf:area as meter and m² (ad-freiburg#127)
Changes the units of osm2rdf:length to meters, and of osm2rdf:area to square meters. Meter lengths are computed by summing up the great-circle distances between line anchor points using the haversine formular. Square meter areas are computed by projecting polygon coordinates using an area-preserving projection (the Lambert cylindrical equal-area projection) and computing the area using Gauss's area formula. This simple projection assumes that the earth is a perfect sphere, but the approximation error should be negligible for typical polygons in OSM. For example, the approximation error of the area of Switzerland is below 0.3%.
1 parent 0a5a7e8 commit cd127f4

File tree

5 files changed

+54
-20
lines changed

5 files changed

+54
-20
lines changed

include/osm2rdf/osm/Constants.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121

2222
namespace osm2rdf::osm::constants {
2323

24-
static const int AREA_PRECISION = 12;
24+
static const int AREA_PRECISION = 4;
25+
static const int LENGTH_PRECISION = 2;
2526
static const int BASE10_BASE = 10;
2627
static const double BASE_SIMPLIFICATION_FACTOR = 0.001;
2728

src/osm/Area.cpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
// You should have received a copy of the GNU General Public License
1818
// along with osm2rdf. If not, see <https://www.gnu.org/licenses/>.
1919

20+
#include "osm2rdf/osm/Area.h"
21+
2022
#include <iostream>
2123
#include <limits>
2224

23-
#include "osm2rdf/osm/Area.h"
2425
#include "osm2rdf/osm/Constants.h"
2526
#include "osmium/osm/area.hpp"
2627
#include "util/geo/Geo.h"
@@ -33,7 +34,35 @@ osm2rdf::osm::Area::Area() {
3334

3435
// ____________________________________________________________________________
3536
void osm2rdf::osm::Area::finalize() noexcept {
36-
_geomArea = ::util::geo::area(_geom);
37+
// poly in area preserving projection
38+
::util::geo::DMultiPolygon lambertPoly;
39+
lambertPoly.resize(_geom.size());
40+
41+
double EARTH_RAD = 6371008.7714; // mean radius
42+
43+
for (size_t i = 0; i < _geom.size(); i++) {
44+
const auto& poly = _geom[i];
45+
lambertPoly[i].getOuter().reserve(poly.getOuter().size());
46+
for (const auto& p : poly.getOuter()) {
47+
lambertPoly[i].getOuter().push_back(
48+
::util::geo::DPoint{EARTH_RAD * (p.getX() * util::geo::RAD),
49+
EARTH_RAD * (sin(p.getY() * util::geo::RAD))});
50+
}
51+
52+
lambertPoly[i].getInners().reserve(poly.getInners().size());
53+
54+
for (const auto& inner : poly.getInners()) {
55+
lambertPoly[i].getInners().push_back({});
56+
lambertPoly[i].getInners().back().reserve(inner.size());
57+
for (const auto& p : inner) {
58+
lambertPoly[i].getInners().back().push_back(
59+
::util::geo::DPoint{EARTH_RAD * (p.getX() * util::geo::RAD),
60+
EARTH_RAD * (sin(p.getY() * util::geo::RAD))});
61+
}
62+
}
63+
}
64+
65+
_geomArea = ::util::geo::area(lambertPoly);
3766
}
3867

3968
// ____________________________________________________________________________
@@ -115,8 +144,7 @@ ::util::geo::DPolygon osm2rdf::osm::Area::convexHull() const noexcept {
115144
}
116145

117146
// ____________________________________________________________________________
118-
::util::geo::DPolygon osm2rdf::osm::Area::orientedBoundingBox()
119-
const noexcept {
147+
::util::geo::DPolygon osm2rdf::osm::Area::orientedBoundingBox() const noexcept {
120148
return ::util::geo::convexHull(::util::geo::getOrientedEnvelope(_geom));
121149
}
122150

@@ -129,8 +157,7 @@ const ::util::geo::DPoint osm2rdf::osm::Area::centroid() const noexcept {
129157
bool osm2rdf::osm::Area::operator==(
130158
const osm2rdf::osm::Area& other) const noexcept {
131159
return _id == other._id && _objId == other._objId &&
132-
_geomArea == other._geomArea &&
133-
_envelope == other._envelope &&
160+
_geomArea == other._geomArea && _envelope == other._envelope &&
134161
_geom == other._geom;
135162
}
136163

src/osm/FactHandler.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "osm2rdf/ttl/Writer.h"
3434

3535
using osm2rdf::osm::constants::AREA_PRECISION;
36+
using osm2rdf::osm::constants::LENGTH_PRECISION;
3637
using osm2rdf::osm::constants::BASE_SIMPLIFICATION_FACTOR;
3738
using osm2rdf::ttl::constants::CHANGESET_NAMESPACE;
3839
using osm2rdf::ttl::constants::DATASET_ID;
@@ -441,7 +442,8 @@ void osm2rdf::osm::FactHandler<W>::way(const osm2rdf::osm::Way& way) {
441442
}
442443

443444
_writer->writeLiteralTripleUnsafe(
444-
subj, IRI__OSM2RDF__LENGTH, std::to_string(::util::geo::len(way.geom())),
445+
subj, IRI__OSM2RDF__LENGTH,
446+
::util::formatFloat(::util::geo::latLngLen(way.geom()), LENGTH_PRECISION),
445447
_iriXSDDouble);
446448
}
447449

tests/issues/Issue24.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ TEST(Issue24, areaFromWayHasGeometryAsGeoSPARQL) {
7575
".\nosmway:21 "
7676
"osm2rdfgeom:envelope \"POLYGON((48 7.5,48.1 7.5,48.1 7.6,48 7.6,48 "
7777
"7.5))\"^^geo:wktLiteral .\nosmway:21 "
78-
"osm2rdf:area \"0.01\"^^xsd:double .\n",
78+
"osm2rdf:area \"122568687.4654\"^^xsd:double .\n",
7979
buffer.str());
8080

8181
// Cleanup
@@ -131,7 +131,7 @@ TEST(Issue24, areaFromRelationHasGeometryAsGeoSPARQL) {
131131
"osmrel:10 geo:hasGeometry osm2rdfgeom:osmrel_10 "
132132
".\nosm2rdfgeom:osmrel_10 geo:asWKT \"POLYGON((48 7.5,48 "
133133
"7.6,48.1 7.6,48.1 7.5,48 7.5))\"^^geo:wktLiteral .\nosmrel:10 "
134-
"osm2rdf:area \"0.01\"^^xsd:double .\n",
134+
"osm2rdf:area \"122568687.4654\"^^xsd:double .\n",
135135
buffer.str());
136136

137137
// Cleanup
@@ -348,7 +348,7 @@ TEST(Issue24, wayHasGeometryAsGeoSPARQL) {
348348
"osm2rdfgeom:envelope \"POLYGON((48 7.5,48.1 7.5,48.1 7.6,48 7.6,48 "
349349
"7.5))\"^^geo:wktLiteral .\nosmway:42 osm2rdfgeom:obb \"POLYGON((48.1 "
350350
"7.6,48.1 7.6,48 7.5,48 7.5,48.1 7.6))\"^^geo:wktLiteral "
351-
".\nosmway:42 osm2rdf:length \"0.141421\"^^xsd:double .\n",
351+
".\nosmway:42 osm2rdf:length \"15674.68\"^^xsd:double .\n",
352352
buffer.str());
353353

354354
// Cleanup

tests/osm/FactHandler.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ TEST(OSM_FactHandler, areaFromWay) {
9898
"7.5))\"^^geo:wktLiteral .\nosmway:21 osm2rdfgeom:envelope \"POLYGON((48 "
9999
"7.5,48.1 7.5,48.1 7.6,48 7.6,48 7.5))\"^^geo:wktLiteral .\nosmway:21 "
100100
"osm2rdfgeom:obb \"POLYGON((48.1 7.5,48.1 7.6,48 7.6,48 7.5,48.1 "
101-
"7.5))\"^^geo:wktLiteral .\nosmway:21 osm2rdf:area \"0.01\"^^xsd:double "
101+
"7.5))\"^^geo:wktLiteral .\nosmway:21 osm2rdf:area "
102+
"\"122568687.4654\"^^xsd:double "
102103
".\n",
103104
buffer.str());
104105

@@ -161,7 +162,8 @@ TEST(OSM_FactHandler, areaFromRelation) {
161162
"7.5))\"^^geo:wktLiteral .\nosmrel:10 osm2rdfgeom:envelope \"POLYGON((48 "
162163
"7.5,48.1 7.5,48.1 7.6,48 7.6,48 7.5))\"^^geo:wktLiteral .\nosmrel:10 "
163164
"osm2rdfgeom:obb \"POLYGON((48.1 7.5,48.1 7.6,48 7.6,48 7.5,48.1 "
164-
"7.5))\"^^geo:wktLiteral .\nosmrel:10 osm2rdf:area \"0.01\"^^xsd:double "
165+
"7.5))\"^^geo:wktLiteral .\nosmrel:10 osm2rdf:area "
166+
"\"122568687.4654\"^^xsd:double "
165167
".\n",
166168
buffer.str());
167169

@@ -537,7 +539,7 @@ TEST(OSM_FactHandler, way) {
537539
"7.6,48 7.5))\"^^geo:wktLiteral .\n"
538540
"osmway:42 osm2rdfgeom:obb \"POLYGON((48.1 7.6,48.1 7.6,48 7.5,48 "
539541
"7.5,48.1 7.6))\"^^geo:wktLiteral .\n"
540-
"osmway:42 osm2rdf:length \"0.141421\"^^xsd:double .\n",
542+
"osmway:42 osm2rdf:length \"15674.68\"^^xsd:double .\n",
541543
buffer.str());
542544

543545
// Cleanup
@@ -604,7 +606,7 @@ TEST(OSM_FactHandler, wayAddWayNodeOrder) {
604606
"osm2rdfgeom:envelope \"POLYGON((48 7.5,48.1 7.5,48.1 7.6,48 7.6,48 "
605607
"7.5))\"^^geo:wktLiteral .\nosmway:42 osm2rdfgeom:obb \"POLYGON((48.1 "
606608
"7.6,48.1 7.6,48 7.5,48 7.5,48.1 7.6))\"^^geo:wktLiteral .\nosmway:42 "
607-
"osm2rdf:length \"0.141421\"^^xsd:double .\n",
609+
"osm2rdf:length \"15674.68\"^^xsd:double .\n",
608610
buffer.str());
609611

610612
// Cleanup
@@ -667,14 +669,15 @@ TEST(OSM_FactHandler, wayAddWayNodeSpatialMetadataShortWay) {
667669
".\n_:0_1 osmway:member_id osmnode:2 .\n_:0_1 osmway:member_pos "
668670
"\"1\"^^xsd:integer .\n_:0_0 osmway:next_node osmnode:2 .\n_:0_0 "
669671
"osmway:next_node_distance \"15657.137001\"^^xsd:decimal .\nosmway:42 "
670-
"geo:hasGeometry osm2rdfgeom:osmway_42 .\nosm2rdfgeom:osmway_42 geo:asWKT "
672+
"geo:hasGeometry osm2rdfgeom:osmway_42 .\nosm2rdfgeom:osmway_42 "
673+
"geo:asWKT "
671674
"\"LINESTRING(48 7.5,48.1 7.6)\"^^geo:wktLiteral .\nosmway:42 "
672675
"osm2rdfgeom:convex_hull \"POLYGON((48 7.5,48.1 7.6,48 "
673676
"7.5))\"^^geo:wktLiteral .\nosmway:42 osm2rdfgeom:envelope \"POLYGON((48 "
674677
"7.5,48.1 7.5,48.1 7.6,48 7.6,48 7.5))\"^^geo:wktLiteral .\nosmway:42 "
675678
"osm2rdfgeom:obb \"POLYGON((48.1 7.6,48.1 7.6,48 7.5,48 7.5,48.1 "
676679
"7.6))\"^^geo:wktLiteral .\nosmway:42 osm2rdf:length "
677-
"\"0.141421\"^^xsd:double .\n",
680+
"\"15674.68\"^^xsd:double .\n",
678681
buffer.str());
679682

680683
// Cleanup
@@ -744,10 +747,11 @@ TEST(OSM_FactHandler, wayAddWayNodeSpatialMetadataLongerWay) {
744747
"\"3\"^^xsd:integer "
745748
".\n_:0_2 osmway:next_node osmnode:3 .\n_:0_2 osmway:next_node_distance "
746749
"\"11024.108103\"^^xsd:decimal .\nosmway:42 geo:hasGeometry "
747-
"osm2rdfgeom:osmway_42 .\nosm2rdfgeom:osmway_42 geo:asWKT \"LINESTRING(48 "
750+
"osm2rdfgeom:osmway_42 .\nosm2rdfgeom:osmway_42 geo:asWKT "
751+
"\"LINESTRING(48 "
748752
"7.5,48.1 "
749753
"7.6,48.1 7.5,48 7.5)\"^^geo:wktLiteral .\nosmway:42 osm2rdf:length "
750-
"\"0.341421\"^^xsd:double .\n",
754+
"\"37843.09\"^^xsd:double .\n",
751755
buffer.str());
752756

753757
// Cleanup
@@ -817,7 +821,7 @@ TEST(OSM_FactHandler, wayAddWayMetaData) {
817821
"osmway:42 osmway:is_closed \"false\"^^xsd:boolean .\n"
818822
"osmway:42 osmway:nodeCount \"2\"^^xsd:integer .\n"
819823
"osmway:42 osmway:uniqueNodeCount \"2\"^^xsd:integer .\n"
820-
"osmway:42 osm2rdf:length \"0.141421\"^^xsd:double .\n",
824+
"osmway:42 osm2rdf:length \"15674.68\"^^xsd:double .\n",
821825
buffer.str());
822826

823827
// Cleanup

0 commit comments

Comments
 (0)