[osmcoastline] 01/06: Add upstream patch for GDAL 2.0 support.
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Thu Dec 3 22:29:29 UTC 2015
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository osmcoastline.
commit ab6f8d7a65b2f54eadd85bc26141f0bffd67fb4d
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Thu Dec 3 22:30:27 2015 +0100
Add upstream patch for GDAL 2.0 support.
---
debian/changelog | 1 +
...h-to-gdalcpp.hpp.-Adds-support-for-GDAL-2.patch | 1726 ++++++++++++++++++++
debian/patches/series | 3 +-
3 files changed, 1729 insertions(+), 1 deletion(-)
diff --git a/debian/changelog b/debian/changelog
index de4a1a5..87b7f2f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,7 @@
osmcoastline (2.1.1-2) UNRELEASED; urgency=medium
* Add patch to support GDAL 2.0.
+ * Add upstream patch for GDAL 2.0 support.
-- Bas Couwenberg <sebastic at debian.org> Sat, 07 Nov 2015 01:06:59 +0100
diff --git a/debian/patches/0001-Switch-to-gdalcpp.hpp.-Adds-support-for-GDAL-2.patch b/debian/patches/0001-Switch-to-gdalcpp.hpp.-Adds-support-for-GDAL-2.patch
new file mode 100644
index 0000000..3bca302
--- /dev/null
+++ b/debian/patches/0001-Switch-to-gdalcpp.hpp.-Adds-support-for-GDAL-2.patch
@@ -0,0 +1,1726 @@
+From 709baa96915d2e82b2fa99788d9476cbfdf17812 Mon Sep 17 00:00:00 2001
+From: Jochen Topf <jochen at topf.org>
+Date: Tue, 24 Nov 2015 21:37:06 +0100
+Subject: Switch to gdalcpp.hpp. Adds support for GDAL 2.
+Origin: https://github.com/osmcode/osmcoastline/commit/709baa96915d2e82b2fa99788d9476cbfdf17812
+Bug: https://github.com/osmcode/osmcoastline/issues/15
+Bug-Debian: https://bugs.debian.org/802813
+
+Also lots of unique_ptr goodness.
+
+Fixes #15.
+
+--- a/.ycm_extra_conf.py
++++ b/.ycm_extra_conf.py
+@@ -29,7 +29,7 @@ flags = [
+ '-x',
+ 'c++',
+
+-# libosmium include dirs
++'-Iinclude',
+ '-I%s/../libosmium/include' % basedir,
+ '-I/usr/include/gdal',
+
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -36,6 +36,8 @@ set(AUTHOR "Jochen Topf <jochen at topf.org
+ #
+ #-----------------------------------------------------------------------------
+
++include_directories(include)
++
+ find_package(Osmium COMPONENTS io gdal)
+ include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
+
+--- /dev/null
++++ b/include/gdalcpp.hpp
+@@ -0,0 +1,406 @@
++#ifndef GDALCPP_HPP
++#define GDALCPP_HPP
++
++/*
++
++C++11 wrapper classes for GDAL/OGR.
++
++Version 1.1.1
++
++https://github.com/joto/gdalcpp
++
++Copyright 2015 Jochen Topf <jochen at topf.org>
++
++Boost Software License - Version 1.0 - August 17th, 2003
++
++Permission is hereby granted, free of charge, to any person or organization
++obtaining a copy of the software and accompanying documentation covered by
++this license (the "Software") to use, reproduce, display, distribute,
++execute, and transmit the Software, and to prepare derivative works of the
++Software, and to permit third-parties to whom the Software is furnished to
++do so, all subject to the following:
++
++The copyright notices in the Software and this entire statement, including
++the above license grant, this restriction and the following disclaimer,
++must be included in all copies of the Software, in whole or in part, and
++all derivative works of the Software, unless such copies or derivative
++works are solely in the form of machine-executable object code generated by
++a source language processor.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
++SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
++FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++DEALINGS IN THE SOFTWARE.
++
++*/
++
++#include <algorithm>
++#include <memory>
++#include <stdexcept>
++#include <string>
++#include <vector>
++
++#include <gdal_priv.h>
++#include <gdal_version.h>
++#include <ogr_api.h>
++#include <ogrsf_frmts.h>
++
++namespace gdalcpp {
++
++#if GDAL_VERSION_MAJOR >= 2
++ using gdal_driver_type = GDALDriver;
++ using gdal_dataset_type = GDALDataset;
++#else
++ using gdal_driver_type = OGRSFDriver;
++ using gdal_dataset_type = OGRDataSource;
++#endif
++
++ /**
++ * Exception thrown for all errors in this class.
++ */
++ class gdal_error : public std::runtime_error {
++
++ std::string m_driver;
++ std::string m_dataset;
++ std::string m_layer;
++ std::string m_field;
++ OGRErr m_error;
++
++ public:
++
++ gdal_error(const std::string& message,
++ OGRErr error,
++ const std::string& driver = "",
++ const std::string& dataset = "",
++ const std::string& layer = "",
++ const std::string& field = "") :
++ std::runtime_error(message),
++ m_driver(driver),
++ m_dataset(dataset),
++ m_layer(layer),
++ m_field(field),
++ m_error(error) {
++ }
++
++ const std::string& driver() const {
++ return m_driver;
++ }
++
++ const std::string& dataset() const {
++ return m_dataset;
++ }
++
++ const std::string& layer() const {
++ return m_layer;
++ }
++
++ const std::string& field() const {
++ return m_field;
++ }
++
++ OGRErr error() const {
++ return m_error;
++ }
++
++ }; // class gdal_error
++
++ namespace detail {
++
++ struct init_wrapper {
++ init_wrapper() { OGRRegisterAll(); }
++ ~init_wrapper() { OGRCleanupAll(); }
++ };
++
++ struct init_library {
++ init_library() {
++ static init_wrapper iw;
++ }
++ };
++
++ class Driver : private init_library {
++
++ gdal_driver_type* m_driver;
++
++ public:
++
++ Driver(const std::string& driver_name) :
++ init_library(),
++#if GDAL_VERSION_MAJOR >= 2
++ m_driver(GetGDALDriverManager()->GetDriverByName(driver_name.c_str())) {
++#else
++ m_driver(OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str())) {
++#endif
++ if (!m_driver) {
++ throw gdal_error(std::string("unknown driver: '") + driver_name + "'", OGRERR_NONE, driver_name);
++ }
++ }
++
++ gdal_driver_type& get() const {
++ return *m_driver;
++ }
++
++ }; // struct Driver
++
++ struct Options {
++
++ std::vector<std::string> m_options;
++ std::unique_ptr<const char*[]> m_ptrs;
++
++ Options(const std::vector<std::string>& options) :
++ m_options(options),
++ m_ptrs(new const char*[options.size()+1]) {
++ std::transform(m_options.begin(), m_options.end(), m_ptrs.get(), [&](const std::string& s) {
++ return s.data();
++ });
++ m_ptrs[options.size()] = nullptr;
++ }
++
++ char** get() const {
++ return const_cast<char**>(m_ptrs.get());
++ }
++
++ }; // struct Options
++
++ } // namespace detail
++
++ class SRS {
++
++ OGRSpatialReference m_spatial_reference;
++
++ public:
++
++ SRS() :
++ m_spatial_reference() {
++ auto result = m_spatial_reference.SetWellKnownGeogCS("WGS84");
++ if (result != OGRERR_NONE) {
++ throw gdal_error(std::string("can not initialize spatial reference system WGS84"), result);
++ }
++ }
++
++ explicit SRS(int epsg) :
++ m_spatial_reference() {
++ auto result = m_spatial_reference.importFromEPSG(epsg);
++ if (result != OGRERR_NONE) {
++ throw gdal_error(std::string("can not initialize spatial reference system for EPSG:") + std::to_string(epsg), result);
++ }
++ }
++
++ explicit SRS(const char* name) :
++ m_spatial_reference() {
++ auto result = m_spatial_reference.importFromProj4(name);
++ if (result != OGRERR_NONE) {
++ throw gdal_error(std::string("can not initialize spatial reference system '") + name + "'", result);
++ }
++ }
++
++ explicit SRS(const std::string& name) :
++ m_spatial_reference() {
++ auto result = m_spatial_reference.importFromProj4(name.c_str());
++ if (result != OGRERR_NONE) {
++ throw gdal_error(std::string("can not initialize spatial reference system '") + name + "'", result);
++ }
++ }
++
++ explicit SRS(const OGRSpatialReference& spatial_reference) :
++ m_spatial_reference(spatial_reference) {
++ }
++
++ OGRSpatialReference& get() {
++ return m_spatial_reference;
++ }
++
++ const OGRSpatialReference& get() const {
++ return m_spatial_reference;
++ }
++
++ }; // class SRS
++
++ class Dataset {
++
++ struct gdal_dataset_deleter {
++
++ void operator()(gdal_dataset_type* ds) {
++#if GDAL_VERSION_MAJOR >= 2
++ GDALClose(ds);
++#else
++ OGRDataSource::DestroyDataSource(ds);
++#endif
++ }
++
++ }; // struct gdal_dataset_deleter
++
++ std::string m_driver_name;
++ std::string m_dataset_name;
++ detail::Options m_options;
++ SRS m_srs;
++ std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset;
++
++ public:
++
++ Dataset(const std::string& driver_name, const std::string& dataset_name, const SRS& srs = SRS{}, const std::vector<std::string>& options = {}) :
++ m_driver_name(driver_name),
++ m_dataset_name(dataset_name),
++ m_options(options),
++ m_srs(srs),
++#if GDAL_VERSION_MAJOR >= 2
++ m_dataset(detail::Driver(driver_name).get().Create(dataset_name.c_str(), 0, 0, 0, GDT_Unknown, m_options.get())) {
++#else
++ m_dataset(detail::Driver(driver_name).get().CreateDataSource(dataset_name.c_str(), m_options.get())) {
++#endif
++ if (!m_dataset) {
++ throw gdal_error(std::string("failed to create dataset '") + dataset_name + "'", OGRERR_NONE, driver_name, dataset_name);
++ }
++ }
++
++ const std::string& driver_name() const {
++ return m_driver_name;
++ }
++
++ const std::string& dataset_name() const {
++ return m_dataset_name;
++ }
++
++ gdal_dataset_type& get() const {
++ return *m_dataset;
++ }
++
++ SRS& srs() {
++ return m_srs;
++ }
++
++ void exec(const char* sql) {
++ auto result = m_dataset->ExecuteSQL(sql, nullptr, nullptr);
++ if (result) {
++ m_dataset->ReleaseResultSet(result);
++ }
++ }
++
++ void exec(const std::string& sql) {
++ exec(sql.c_str());
++ }
++
++
++ Dataset& start_transaction() {
++#if GDAL_VERSION_MAJOR >= 2
++ m_dataset->StartTransaction();
++#endif
++ return *this;
++ }
++
++ Dataset& commit_transaction() {
++#if GDAL_VERSION_MAJOR >= 2
++ m_dataset->CommitTransaction();
++#endif
++ return *this;
++ }
++
++ }; // class Dataset
++
++ class Layer {
++
++ detail::Options m_options;
++ Dataset& m_dataset;
++ OGRLayer* m_layer;
++
++ public:
++
++ Layer(Dataset& dataset, const std::string& layer_name, OGRwkbGeometryType type, const std::vector<std::string>& options = {}) :
++ m_options(options),
++ m_dataset(dataset),
++ m_layer(dataset.get().CreateLayer(layer_name.c_str(), &dataset.srs().get(), type, m_options.get())) {
++ if (!m_layer) {
++ throw gdal_error(std::string("failed to create layer '") + layer_name + "'", OGRERR_NONE,
++ dataset.driver_name(), dataset.dataset_name(), layer_name);
++ }
++ }
++
++ OGRLayer& get() {
++ return *m_layer;
++ }
++
++ const OGRLayer& get() const {
++ return *m_layer;
++ }
++
++ Dataset& dataset() const {
++ return m_dataset;
++ }
++
++ const char* name() const {
++ return m_layer->GetName();
++ }
++
++ Layer& add_field(const std::string& field_name, OGRFieldType type, int width, int precision=0) {
++ OGRFieldDefn field(field_name.c_str(), type);
++ field.SetWidth(width);
++ field.SetPrecision(precision);
++
++ if (m_layer->CreateField(&field) != OGRERR_NONE) {
++ throw gdal_error(std::string("failed to create field '") + field_name + "' in layer '" + name() + "'", OGRERR_NONE,
++ m_dataset.driver_name(), m_dataset.dataset_name(), name(), field_name);
++ }
++
++ return *this;
++ }
++
++ Layer& start_transaction() {
++ OGRErr result = m_layer->StartTransaction();
++ if (result != OGRERR_NONE) {
++ throw gdal_error(std::string("starting transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
++ }
++ return *this;
++ }
++
++ Layer& commit_transaction() {
++ OGRErr result = m_layer->CommitTransaction();
++ if (result != OGRERR_NONE) {
++ throw gdal_error(std::string("committing transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
++ }
++ return *this;
++ }
++
++ }; // class Layer
++
++ class Feature {
++
++ Layer& m_layer;
++ OGRFeature m_feature;
++
++ public:
++
++ Feature(Layer& layer, std::unique_ptr<OGRGeometry>&& geometry) :
++ m_layer(layer),
++ m_feature(m_layer.get().GetLayerDefn()) {
++ OGRErr result = m_feature.SetGeometryDirectly(geometry.release());
++ if (result != OGRERR_NONE) {
++ throw gdal_error(std::string("setting feature geometry in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
++ }
++ }
++
++ void add_to_layer() {
++ OGRErr result = m_layer.get().CreateFeature(&m_feature);
++ if (result != OGRERR_NONE) {
++ throw gdal_error(std::string("creating feature in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
++ }
++ }
++
++ template <class T>
++ Feature& set_field(int n, T&& arg) {
++ m_feature.SetField(n, std::forward<T>(arg));
++ return *this;
++ }
++
++ template <class T>
++ Feature& set_field(const char* name, T&& arg) {
++ m_feature.SetField(name, std::forward<T>(arg));
++ return *this;
++ }
++
++ }; // class Feature
++
++} // namespace gdalcpp
++
++#endif // GDALCPP_HPP
+--- a/src/CMakeLists.txt
++++ b/src/CMakeLists.txt
+@@ -6,7 +6,7 @@
+ #
+ #-----------------------------------------------------------------------------
+
+-add_executable(osmcoastline osmcoastline.cpp coastline_ring.cpp coastline_ring_collection.cpp coastline_polygons.cpp output_database.cpp output_layers.cpp srs.cpp options.cpp)
++add_executable(osmcoastline osmcoastline.cpp coastline_ring.cpp coastline_ring_collection.cpp coastline_polygons.cpp output_database.cpp srs.cpp options.cpp)
+ target_link_libraries(osmcoastline ${OSMIUM_IO_LIBRARIES} ${GDAL_LIBRARIES} ${GEOS_C_LIBRARIES})
+ install(TARGETS osmcoastline DESTINATION bin)
+
+@@ -18,7 +18,7 @@ add_executable(osmcoastline_segments osm
+ target_link_libraries(osmcoastline_segments ${GDAL_LIBRARIES})
+ install(TARGETS osmcoastline_segments DESTINATION bin)
+
+-add_executable(osmcoastline_ways osmcoastline_ways.cpp osmcoastline.hpp)
++add_executable(osmcoastline_ways osmcoastline_ways.cpp return_codes.hpp)
+ target_link_libraries(osmcoastline_ways ${OSMIUM_IO_LIBRARIES} ${GDAL_LIBRARIES})
+ install(TARGETS osmcoastline_ways DESTINATION bin)
+
+--- a/src/coastline_polygons.cpp
++++ b/src/coastline_polygons.cpp
+@@ -28,8 +28,9 @@
+
+ #include "coastline_polygons.hpp"
+ #include "output_database.hpp"
+-#include "osmcoastline.hpp"
++#include "return_codes.hpp"
+ #include "srs.hpp"
++#include "util.hpp"
+
+ extern SRS srs;
+ extern bool debug;
+@@ -73,7 +74,7 @@ unsigned int CoastlinePolygons::fix_dire
+ // Workaround for bug in OGR: reverseWindingOrder sets dimensions to 3
+ polygon->getInteriorRing(i)->setCoordinateDimension(2);
+ }
+- m_output.add_error_line(static_cast<OGRLineString*>(er->clone()), "direction");
++ m_output.add_error_line(make_unique_ptr_clone<OGRLineString>(er), "direction");
+ warnings++;
+ }
+ }
+@@ -83,26 +84,26 @@ unsigned int CoastlinePolygons::fix_dire
+
+ void CoastlinePolygons::transform() {
+ for (const auto& polygon : m_polygons) {
+- srs.transform(polygon);
++ srs.transform(polygon.get());
+ }
+ }
+
+-void CoastlinePolygons::split_geometry(std::unique_ptr<OGRGeometry> geom, int level) {
++void CoastlinePolygons::split_geometry(std::unique_ptr<OGRGeometry>&& geom, int level) {
+ if (geom->getGeometryType() == wkbPolygon) {
+ geom->assignSpatialReference(srs.out());
+- split_polygon(static_cast<OGRPolygon*>(geom.release()), level);
++ split_polygon(static_cast_unique_ptr<OGRPolygon>(std::move(geom)), level);
+ } else { // wkbMultiPolygon
+- const auto mp = static_cast<OGRMultiPolygon*>(geom.get());
++ const auto mp = static_cast_unique_ptr<OGRMultiPolygon>(std::move(geom));
+ while (mp->getNumGeometries() > 0) {
+ std::unique_ptr<OGRPolygon> polygon { static_cast<OGRPolygon*>(mp->getGeometryRef(0)) };
+ mp->removeGeometry(0, false);
+ polygon->assignSpatialReference(srs.out());
+- split_polygon(polygon.release(), level);
++ split_polygon(std::move(polygon), level);
+ }
+ }
+ }
+
+-void CoastlinePolygons::split_polygon(OGRPolygon* polygon, int level) {
++void CoastlinePolygons::split_polygon(std::unique_ptr<OGRPolygon>&& polygon, int level) {
+ if (level > m_max_split_depth) {
+ m_max_split_depth = level;
+ }
+@@ -193,7 +194,7 @@ void CoastlinePolygons::split() {
+ std::swap(v, m_polygons);
+ m_polygons.reserve(v.size());
+ for (auto& polygon : v) {
+- split_polygon(polygon, 0);
++ split_polygon(std::move(polygon), 0);
+ }
+ }
+
+@@ -201,12 +202,13 @@ void CoastlinePolygons::output_land_poly
+ if (make_copy) {
+ // because adding to a layer destroys the geometry, we need to copy it if it is needed later
+ for (const auto& polygon : m_polygons) {
+- m_output.add_land_polygon(static_cast<OGRPolygon*>(polygon->clone()));
++ m_output.add_land_polygon(make_unique_ptr_clone<OGRPolygon>(polygon.get()));
+ }
+ } else {
+ for (auto& polygon : m_polygons) {
+- m_output.add_land_polygon(polygon);
++ m_output.add_land_polygon(std::move(polygon));
+ }
++ m_polygons.clear();
+ }
+ }
+
+@@ -273,7 +275,7 @@ void CoastlinePolygons::output_polygon_r
+ }
+
+ void CoastlinePolygons::output_lines(int max_points) {
+- for (OGRPolygon* polygon : m_polygons) {
++ for (const auto& polygon : m_polygons) {
+ output_polygon_ring_as_lines(max_points, polygon->getExteriorRing());
+ for (int i=0; i < polygon->getNumInteriorRings(); ++i) {
+ output_polygon_ring_as_lines(max_points, polygon->getInteriorRing(i));
+@@ -287,25 +289,27 @@ void CoastlinePolygons::split_bbox(OGREn
+ try {
+ std::unique_ptr<OGRGeometry> geom { create_rectangular_polygon(e.MinX, e.MinY, e.MaxX, e.MaxY, m_expand) };
+ assert(geom->getSpatialReference() != nullptr);
+- for (const OGRPolygon* polygon : v) {
+- OGRGeometry* diff = geom->Difference(polygon);
++ for (const auto& polygon : v) {
++ std::unique_ptr<OGRGeometry> diff { geom->Difference(polygon.get()) };
+ // for some reason there is sometimes no srs on the geometries, so we add them on
+ diff->assignSpatialReference(srs.out());
+- geom.reset(diff);
++ geom = std::move(diff);
+ }
+ if (geom) {
+ switch (geom->getGeometryType()) {
+ case wkbPolygon:
+- m_output.add_water_polygon(static_cast<OGRPolygon*>(geom.release()));
++ m_output.add_water_polygon(static_cast_unique_ptr<OGRPolygon>(std::move(geom)));
+ break;
+- case wkbMultiPolygon:
+- for (int i=static_cast<OGRMultiPolygon*>(geom.get())->getNumGeometries() - 1; i >= 0; --i) {
+- OGRPolygon* p = static_cast<OGRPolygon*>(static_cast<OGRMultiPolygon*>(geom.get())->getGeometryRef(i));
+- p->assignSpatialReference(geom->getSpatialReference());
+- static_cast<OGRMultiPolygon*>(geom.get())->removeGeometry(i, FALSE);
+- m_output.add_water_polygon(p);
++ case wkbMultiPolygon: {
++ auto mp = static_cast_unique_ptr<OGRMultiPolygon>(std::move(geom));
++ for (int i = mp->getNumGeometries() - 1; i >= 0; --i) {
++ auto p = std::unique_ptr<OGRPolygon>(static_cast<OGRPolygon*>(mp->getGeometryRef(i)));
++ p->assignSpatialReference(mp->getSpatialReference());
++ mp->removeGeometry(i, FALSE);
++ m_output.add_water_polygon(std::move(p));
++ }
++ break;
+ }
+- break;
+ case wkbGeometryCollection:
+ // XXX
+ break;
+@@ -355,7 +359,7 @@ void CoastlinePolygons::split_bbox(OGREn
+
+ polygon_vector_type v1;
+ polygon_vector_type v2;
+- for (OGRPolygon* polygon : v) {
++ for (auto& polygon : v) {
+
+ /* You might think re-computing the envelope of all those polygons
+ again and again might take a lot of time, but I benchmarked it and
+@@ -363,11 +367,11 @@ void CoastlinePolygons::split_bbox(OGREn
+ OGREnvelope e;
+ polygon->getEnvelope(&e);
+ if (e1.Intersects(e)) {
+- v1.push_back(polygon);
++ v1.push_back(std::move(polygon));
+ }
+
+ if (e2.Intersects(e)) {
+- v2.push_back(polygon);
++ v2.push_back(std::move(polygon));
+ }
+ }
+ split_bbox(e1, std::move(v1));
+@@ -379,9 +383,9 @@ void CoastlinePolygons::split_bbox(OGREn
+ unsigned int CoastlinePolygons::output_water_polygons() {
+ unsigned int warnings = 0;
+ polygon_vector_type v;
+- for (OGRPolygon* polygon : m_polygons) {
++ for (auto& polygon : m_polygons) {
+ if (polygon->IsValid()) {
+- v.push_back(polygon);
++ v.push_back(std::move(polygon));
+ } else {
+ std::cerr << "Invalid polygon, trying buffer(0).\n";
+ ++warnings;
+--- a/src/coastline_polygons.hpp
++++ b/src/coastline_polygons.hpp
+@@ -34,7 +34,7 @@ class OGRMultiPolygon;
+ class OGREnvelope;
+ class OutputDatabase;
+
+-typedef std::vector<OGRPolygon*> polygon_vector_type;
++typedef std::vector<std::unique_ptr<OGRPolygon>> polygon_vector_type;
+
+ /**
+ * A collection of land polygons created out of coastlines.
+@@ -74,8 +74,8 @@ class CoastlinePolygons {
+
+ std::unique_ptr<OGRPolygon> create_rectangular_polygon(double x1, double y1, double x2, double y2, double expand=0) const;
+
+- void split_geometry(std::unique_ptr<OGRGeometry> geom, int level);
+- void split_polygon(OGRPolygon* polygon, int level);
++ void split_geometry(std::unique_ptr<OGRGeometry>&& geom, int level);
++ void split_polygon(std::unique_ptr<OGRPolygon>&& polygon, int level);
+ void split_bbox(OGREnvelope e, polygon_vector_type&& v);
+
+ bool add_segment_to_line(OGRLineString* line, OGRPoint* point1, OGRPoint* point2);
+--- a/src/coastline_ring_collection.cpp
++++ b/src/coastline_ring_collection.cpp
+@@ -126,7 +126,16 @@ unsigned int CoastlineRingCollection::ch
+ return missing_positions;
+ }
+
+-void CoastlineRingCollection::add_polygons_to_vector(std::vector<OGRGeometry*>& vector) {
++bool is_valid_polygon(const OGRGeometry* geometry) {
++ if (geometry && geometry->getGeometryType() == wkbPolygon) {
++ const auto polygon = static_cast<const OGRPolygon*>(geometry);
++ return (polygon->getExteriorRing()->getNumPoints() > 3) && (polygon->getNumInteriorRings() == 0) && geometry->IsValid();
++ }
++ return false;
++}
++
++std::vector<OGRGeometry*> CoastlineRingCollection::add_polygons_to_vector() {
++ std::vector<OGRGeometry*> vector;
+ vector.reserve(m_list.size());
+
+ for (const auto& ring : m_list) {
+@@ -137,15 +146,17 @@ void CoastlineRingCollection::add_polygo
+ vector.push_back(p.release());
+ } else {
+ std::unique_ptr<OGRGeometry> geom { p->Buffer(0) };
+- if (geom && (geom->getGeometryType() == wkbPolygon) && (static_cast<OGRPolygon*>(geom.get())->getExteriorRing()->getNumPoints() > 3) && (static_cast<OGRPolygon*>(geom.get())->getNumInteriorRings() == 0) && geom->IsValid()) {
++ if (is_valid_polygon(geom.get())) {
+ geom->assignSpatialReference(srs.wgs84());
+- vector.push_back(static_cast<OGRPolygon*>(geom.release()));
++ vector.push_back(geom.release());
+ } else {
+ std::cerr << "Ignoring invalid polygon geometry (ring_id=" << ring->ring_id() << ").\n";
+ }
+ }
+ }
+ }
++
++ return vector;
+ }
+
+ unsigned int CoastlineRingCollection::output_rings(OutputDatabase& output) {
+@@ -154,18 +165,18 @@ unsigned int CoastlineRingCollection::ou
+ for (const auto& ring : m_list) {
+ if (ring->is_closed()) {
+ if (ring->npoints() > 3) {
+- output.add_ring(ring->ogr_polygon(m_factory, true).release(), ring->ring_id(), ring->nways(), ring->npoints(), ring->is_fixed());
++ output.add_ring(ring->ogr_polygon(m_factory, true), ring->ring_id(), ring->nways(), ring->npoints(), ring->is_fixed());
+ } else if (ring->npoints() == 1) {
+ output.add_error_point(ring->ogr_first_point(), "single_point_in_ring", ring->first_node_id());
+ warnings++;
+ } else { // ring->npoints() == 2 or 3
+- output.add_error_line(ring->ogr_linestring(m_factory, true).release(), "not_a_ring", ring->ring_id());
++ output.add_error_line(ring->ogr_linestring(m_factory, true), "not_a_ring", ring->ring_id());
+ output.add_error_point(ring->ogr_first_point(), "not_a_ring", ring->first_node_id());
+ output.add_error_point(ring->ogr_last_point(), "not_a_ring", ring->last_node_id());
+ warnings++;
+ }
+ } else {
+- output.add_error_line(ring->ogr_linestring(m_factory, true).release(), "not_closed", ring->ring_id());
++ output.add_error_line(ring->ogr_linestring(m_factory, true), "not_closed", ring->ring_id());
+ output.add_error_point(ring->ogr_first_point(), "end_point", ring->first_node_id());
+ output.add_error_point(ring->ogr_last_point(), "end_point", ring->last_node_id());
+ warnings++;
+--- a/src/coastline_ring_collection.hpp
++++ b/src/coastline_ring_collection.hpp
+@@ -105,7 +105,7 @@ public:
+
+ unsigned int check_positions(bool output_missing);
+
+- void add_polygons_to_vector(std::vector<OGRGeometry*>& vector);
++ std::vector<OGRGeometry*> add_polygons_to_vector();
+
+ unsigned int output_rings(OutputDatabase& output);
+
+--- a/src/ogr_include.hpp
++++ /dev/null
+@@ -1,42 +0,0 @@
+-#ifndef OGR_INCLUDE_HPP
+-#define OGR_INCLUDE_HPP
+-
+-#ifdef _MSC_VER
+-# pragma warning(push)
+-# pragma warning(disable : 4458)
+-# pragma warning(disable : 4251)
+-#else
+-# pragma GCC diagnostic push
+-# ifdef __clang__
+-# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+-# endif
+-# pragma GCC diagnostic ignored "-Wfloat-equal"
+-# pragma GCC diagnostic ignored "-Wold-style-cast"
+-# pragma GCC diagnostic ignored "-Wpadded"
+-# pragma GCC diagnostic ignored "-Wredundant-decls"
+-# pragma GCC diagnostic ignored "-Wshadow"
+-#endif
+-
+-/* Strictly speaking the following include would be enough here,
+- but everybody using this file will very likely need the other includes,
+- so we are adding them here, so that not everybody will need all those
+- pragmas to disable warnings. */
+-//#include <ogr_geometry.h>
+-#include <ogr_api.h>
+-#include <ogrsf_frmts.h>
+-
+-#ifdef _MSC_VER
+-# pragma warning(pop)
+-#else
+-# pragma GCC diagnostic pop
+-#endif
+-
+-struct OGRDataSourceDestroyer {
+- void operator()(OGRDataSource* ptr) {
+- if (ptr) {
+- OGRDataSource::DestroyDataSource(ptr);
+- }
+- }
+-};
+-
+-#endif // OGR_INCLUDE_HPP
+--- a/src/options.cpp
++++ b/src/options.cpp
+@@ -25,7 +25,7 @@
+ #include <cstdlib>
+ #include <getopt.h>
+
+-#include "osmcoastline.hpp"
++#include "return_codes.hpp"
+ #include "options.hpp"
+
+ Options::Options(int argc, char* argv[]) :
+--- a/src/osmcoastline.cpp
++++ b/src/osmcoastline.cpp
+@@ -27,17 +27,17 @@
+ #include <osmium/io/any_input.hpp>
+ #include <osmium/visitor.hpp>
+
+-#include "osmcoastline.hpp"
++#include "return_codes.hpp"
+ #include "coastline_ring.hpp"
+ #include "coastline_ring_collection.hpp"
+ #include "coastline_polygons.hpp"
+ #include "output_database.hpp"
+-#include "output_layers.hpp"
+
+ #include "options.hpp"
+ #include "stats.hpp"
+ #include "coastline_handlers.hpp"
+ #include "srs.hpp"
++#include "util.hpp"
+ #include "verbose_output.hpp"
+
+ // The global SRS object is used in many places to transform
+@@ -56,8 +56,7 @@ const unsigned int max_warnings = 500;
+ * This function assembles all the coastline rings into one huge multipolygon.
+ */
+ polygon_vector_type create_polygons(CoastlineRingCollection& coastline_rings, OutputDatabase& output, unsigned int* warnings, unsigned int* errors) {
+- std::vector<OGRGeometry*> all_polygons;
+- coastline_rings.add_polygons_to_vector(all_polygons);
++ std::vector<OGRGeometry*> all_polygons = coastline_rings.add_polygons_to_vector();
+
+ int is_valid;
+ const char* options[] = { "METHOD=ONLY_CCW", nullptr };
+@@ -69,8 +68,10 @@ polygon_vector_type create_polygons(Coas
+ std::cerr << "organizePolygons() done\n";
+ }
+
+- assert(mega_geometry->getGeometryType() == wkbMultiPolygon);
+- OGRMultiPolygon* mega_multipolygon = static_cast<OGRMultiPolygon*>(mega_geometry.get());
++ if (mega_geometry->getGeometryType() != wkbMultiPolygon) {
++ throw std::runtime_error("mega geometry isn't a multipolygon. Something is very wrong!");
++ }
++ OGRMultiPolygon* mega_multipolygon = static_cast<OGRMultiPolygon*>(mega_geometry.release());
+
+ polygon_vector_type polygons;
+ polygons.reserve(mega_multipolygon->getNumGeometries());
+@@ -79,13 +80,13 @@ polygon_vector_type create_polygons(Coas
+ assert(geom->getGeometryType() == wkbPolygon);
+ std::unique_ptr<OGRPolygon> p { static_cast<OGRPolygon*>(geom) };
+ if (p->IsValid()) {
+- polygons.push_back(p.release());
++ polygons.push_back(std::move(p));
+ } else {
+- output.add_error_line(static_cast<OGRLineString*>(p->getExteriorRing()->clone()), "invalid");
++ output.add_error_line(make_unique_ptr_clone<OGRLineString>(p->getExteriorRing()), "invalid");
+ std::unique_ptr<OGRGeometry> buf0 { p->Buffer(0) };
+ if (buf0 && buf0->getGeometryType() == wkbPolygon && buf0->IsValid()) {
+ buf0->assignSpatialReference(srs.wgs84());
+- polygons.emplace_back(static_cast<OGRPolygon*>(buf0.release()));
++ polygons.push_back(static_cast_unique_ptr<OGRPolygon>(std::move(buf0)));
+ (*warnings)++;
+ } else {
+ std::cerr << "Ignoring invalid polygon geometry.\n";
+@@ -95,6 +96,7 @@ polygon_vector_type create_polygons(Coas
+ }
+
+ mega_multipolygon->removeGeometry(-1, FALSE);
++ delete mega_multipolygon;
+
+ return polygons;
+ }
+@@ -183,7 +185,7 @@ int main(int argc, char *argv[]) {
+ } else {
+ vout << "Will NOT create geometry index (because you told me to using --no-index/-i).\n";
+ }
+- OutputDatabase output_database(options.output_database, options.create_index);
++ OutputDatabase output_database(options.output_database, srs, options.create_index);
+
+ // The collection of all coastline rings we will be filling and then
+ // operating on.
+--- a/src/osmcoastline.hpp
++++ /dev/null
+@@ -1,33 +0,0 @@
+-#ifndef OSMCOASTLINE_HPP
+-#define OSMCOASTLINE_HPP
+-
+-/*
+-
+- Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+-
+- This file is part of OSMCoastline.
+-
+- OSMCoastline is free software: you can redistribute it and/or modify
+- it under the terms of the GNU General Public License as published by
+- the Free Software Foundation, either version 3 of the License, or
+- (at your option) any later version.
+-
+- OSMCoastline is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- GNU General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with OSMCoastline. If not, see <http://www.gnu.org/licenses/>.
+-
+-*/
+-
+-enum return_codes {
+- return_code_ok = 0,
+- return_code_warning = 1,
+- return_code_error = 2,
+- return_code_fatal = 3,
+- return_code_cmdline = 4
+-};
+-
+-#endif // OSMCOASTLINE_HPP
+--- a/src/osmcoastline_filter.cpp
++++ b/src/osmcoastline_filter.cpp
+@@ -28,7 +28,7 @@
+ #include <osmium/handler.hpp>
+ #include <osmium/osm/entity_bits.hpp>
+
+-#include "osmcoastline.hpp"
++#include "return_codes.hpp"
+
+ void print_help() {
+ std::cout << "osmcoastline_filter [OPTIONS] OSMFILE\n"
+--- a/src/osmcoastline_segments.cpp
++++ b/src/osmcoastline_segments.cpp
+@@ -35,9 +35,9 @@
+ #include <osmium/osm/undirected_segment.hpp>
+ #include <osmium/util/memory_mapping.hpp>
+
+-#include "ogr_include.hpp"
+-#include "osmcoastline.hpp"
+-#include "srs.hpp"
++#include <gdalcpp.hpp>
++
++#include "return_codes.hpp"
+
+ typedef std::vector<osmium::UndirectedSegment> segvec;
+
+@@ -73,56 +73,22 @@ public:
+ void print_help() {
+ }
+
+-void add_segment(OGRLayer* layer, int change, const osmium::UndirectedSegment& segment) {
+- OGRFeature* feature = OGRFeature::CreateFeature(layer->GetLayerDefn());
+-
+- auto linestring = new OGRLineString();
++void add_segment(gdalcpp::Layer& layer, int change, const osmium::UndirectedSegment& segment) {
++ auto linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
+ linestring->addPoint(segment.first().lon(), segment.first().lat());
+ linestring->addPoint(segment.second().lon(), segment.second().lat());
+
+- feature->SetGeometryDirectly(linestring);
+- feature->SetField("change", change);
+-
+- if (layer->CreateFeature(feature) != OGRERR_NONE) {
+- std::cerr << "Failed to create feature on layer 'changes'.\n";
+- exit(return_code_fatal);
+- }
+-
+- OGRFeature::DestroyFeature(feature);
++ gdalcpp::Feature feature(layer, std::move(linestring));
++ feature.set_field("change", change);
++ feature.add_to_layer();
+ }
+
+ void output_ogr(const std::string& filename, const std::string& driver_name, const segvec& removed_segments, const segvec& added_segments) {
+- OGRRegisterAll();
+-
+- OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
+- if (!driver) {
+- std::cerr << driver_name << " driver not available.\n";
+- exit(return_code_fatal);
+- }
+-
+- //const char* options[] = { "SPATIALITE=yes", "OGR_SQLITE_SYNCHRONOUS=OFF", "INIT_WITH_EPSG=no", nullptr };
+- const char* options[] = { nullptr };
+- auto data_source = std::unique_ptr<OGRDataSource, OGRDataSourceDestroyer>(driver->CreateDataSource(filename.c_str(), const_cast<char**>(options)));
+- if (!data_source) {
+- std::cerr << "Creation of output file failed.\n";
+- exit(return_code_fatal);
+- }
+-
+- SRS srs;
+- auto layer = data_source->CreateLayer("changes", srs.out(), wkbLineString, const_cast<char**>(options));
+- if (!layer) {
+- std::cerr << "Creating layer 'changes' failed.\n";
+- exit(return_code_fatal);
+- }
+-
+- OGRFieldDefn field_change("change", OFTInteger);
+- field_change.SetWidth(1);
+- if (layer->CreateField(&field_change) != OGRERR_NONE ) {
+- std::cerr << "Creating field 'change' on 'changes' layer failed.\n";
+- exit(return_code_fatal);
+- }
++ gdalcpp::Dataset dataset{driver_name, filename};
+
+- layer->StartTransaction();
++ gdalcpp::Layer layer{dataset, "changes", wkbLineString};
++ layer.add_field("change", OFTInteger, 1);
++ layer.start_transaction();
+
+ for (const auto& segment : removed_segments) {
+ add_segment(layer, 0, segment);
+@@ -132,7 +98,7 @@ void output_ogr(const std::string& filen
+ add_segment(layer, 1, segment);
+ }
+
+- layer->CommitTransaction();
++ layer.commit_transaction();
+ }
+
+ int main(int argc, char *argv[]) {
+--- a/src/osmcoastline_ways.cpp
++++ b/src/osmcoastline_ways.cpp
+@@ -20,7 +20,7 @@
+ */
+
+ #include <iostream>
+-#include <set>
++#include <memory>
+ #include <string>
+
+ #include <osmium/geom/haversine.hpp>
+@@ -30,8 +30,9 @@
+ #include <osmium/io/any_input.hpp>
+ #include <osmium/visitor.hpp>
+
+-#include "ogr_include.hpp"
+-#include "osmcoastline.hpp"
++#include <gdalcpp.hpp>
++
++#include "return_codes.hpp"
+
+ typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+ typedef osmium::handler::NodeLocationsForWays<index_type, index_type> node_location_handler_type;
+@@ -40,94 +41,41 @@ class CoastlineWaysHandler : public osmi
+
+ double m_length;
+
+- std::unique_ptr<OGRDataSource, OGRDataSourceDestroyer> m_data_source;
+- OGRLayer* m_layer_ways;
++ gdalcpp::Dataset m_dataset;
++ gdalcpp::Layer m_layer_ways;
+
+ osmium::geom::OGRFactory<> m_factory;
+
+ public:
+
+ CoastlineWaysHandler(const std::string& db_filename) :
+- m_length(0.0) {
+- OGRRegisterAll();
+-
+- const char* driver_name = "SQLite";
+- OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name);
+- if (!driver) {
+- std::cerr << driver_name << " driver not available.\n";
+- exit(return_code_fatal);
+- }
+-
+- CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
+- const char* options[] = { "SPATIALITE=TRUE", nullptr };
+- m_data_source.reset(driver->CreateDataSource(db_filename.c_str(), const_cast<char**>(options)));
+- if (!m_data_source) {
+- std::cerr << "Creation of output file failed.\n";
+- exit(return_code_fatal);
+- }
+-
+- OGRSpatialReference sparef;
+- sparef.SetWellKnownGeogCS("WGS84");
+- m_layer_ways = m_data_source->CreateLayer("ways", &sparef, wkbLineString, nullptr);
+- if (!m_layer_ways) {
+- std::cerr << "Layer creation failed.\n";
+- exit(return_code_fatal);
+- }
+-
+- OGRFieldDefn field_way_id("way_id", OFTString);
+- field_way_id.SetWidth(10);
+- if (m_layer_ways->CreateField(&field_way_id) != OGRERR_NONE ) {
+- std::cerr << "Creating field 'way_id' on 'ways' layer failed.\n";
+- exit(return_code_fatal);
+- }
+-
+- OGRFieldDefn field_name("name", OFTString);
+- field_name.SetWidth(100);
+- if (m_layer_ways->CreateField(&field_name) != OGRERR_NONE ) {
+- std::cerr << "Creating field 'name' on 'ways' layer failed.\n";
+- exit(return_code_fatal);
+- }
+-
+- OGRFieldDefn field_source("source", OFTString);
+- field_source.SetWidth(255);
+- if (m_layer_ways->CreateField(&field_source) != OGRERR_NONE ) {
+- std::cerr << "Creating field 'source' on 'ways' layer failed.\n";
+- exit(return_code_fatal);
+- }
+-
+- OGRFieldDefn field_bogus("bogus", OFTString);
+- field_bogus.SetWidth(1);
+- if (m_layer_ways->CreateField(&field_bogus) != OGRERR_NONE ) {
+- std::cerr << "Creating field 'bogus' on 'ways' layer failed.\n";
+- exit(return_code_fatal);
+- }
+-
+- m_layer_ways->StartTransaction();
++ m_length(0.0),
++ m_dataset("SQLite", db_filename, gdalcpp::SRS{}, {"SPATIALITE=TRUE", "OGR_SQLITE_SYNCHRONOUS=OFF", "INIT_WITH_EPSG=no" }),
++ m_layer_ways(m_dataset, "ways", wkbLineString) {
++
++ m_layer_ways.add_field("way_id", OFTString, 10);
++ m_layer_ways.add_field("name", OFTString, 100);
++ m_layer_ways.add_field("source", OFTString, 255);
++ m_layer_ways.add_field("bogus", OFTString, 1);
++ m_layer_ways.start_transaction();
+ }
+
+ ~CoastlineWaysHandler() {
+- m_layer_ways->CommitTransaction();
++ m_layer_ways.commit_transaction();
+ }
+
+ void way(osmium::Way& way) {
+ m_length += osmium::geom::haversine::distance(way.nodes());
+ try {
+- OGRFeature* feature = OGRFeature::CreateFeature(m_layer_ways->GetLayerDefn());
+ std::unique_ptr<OGRLineString> ogrlinestring = m_factory.create_linestring(way);
+- feature->SetGeometry(ogrlinestring.get());
+- feature->SetField("way_id", std::to_string(way.id()).c_str());
+- feature->SetField("name", way.tags().get_value_by_key("name"));
+- feature->SetField("source", way.tags().get_value_by_key("source"));
++ gdalcpp::Feature feature(m_layer_ways, std::move(ogrlinestring));
++ feature.set_field("way_id", std::to_string(way.id()).c_str());
++ feature.set_field("name", way.tags().get_value_by_key("name"));
++ feature.set_field("source", way.tags().get_value_by_key("source"));
+
+ const char* coastline = way.tags().get_value_by_key("coastline");
+- feature->SetField("bogus", (coastline && !strcmp(coastline, "bogus")) ? "t" : "f");
+-
+- if (m_layer_ways->CreateFeature(feature) != OGRERR_NONE) {
+- std::cerr << "Failed to create feature.\n";
+- exit(1);
+- }
+-
+- OGRFeature::DestroyFeature(feature);
++ feature.set_field("bogus", (coastline && !std::strcmp(coastline, "bogus")) ? "t" : "f");
++ feature.add_to_layer();
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
+ }
+--- a/src/output_database.cpp
++++ b/src/output_database.cpp
+@@ -22,54 +22,49 @@
+ #include <iostream>
+ #include <sstream>
+
+-#include "ogr_include.hpp"
+-#include "osmcoastline.hpp"
+-#include "output_database.hpp"
+-#include "output_layers.hpp"
++#include <gdal_version.h>
++#include <geos_c.h>
++
+ #include "options.hpp"
++#include "output_database.hpp"
++#include "srs.hpp"
+ #include "stats.hpp"
+
+-const char* OutputDatabase::options_with_index[] = { nullptr };
+-const char* OutputDatabase::options_without_index[] = { "SPATIAL_INDEX=no", nullptr };
+-
+-OutputDatabase::~OutputDatabase() {
+- OGRCleanupAll();
+-}
+-
+-OutputDatabase::OutputDatabase(const std::string& outdb, bool with_index) :
++OutputDatabase::OutputDatabase(const std::string& outdb, SRS& srs, bool with_index) :
+ m_with_index(with_index),
+- m_data_source(),
+- m_layer_error_points(),
+- m_layer_error_lines(),
+- m_layer_rings(),
+- m_layer_land_polygons(),
+- m_layer_water_polygons(),
+- m_layer_lines() {
+- OGRRegisterAll();
+-
+- const char* driver_name = "SQLite";
+- OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name);
+- if (!driver) {
+- std::cerr << driver_name << " driver not available.\n";
+- exit(return_code_fatal);
+- }
++ m_srs(srs),
++ m_dataset("SQLite", outdb, gdalcpp::SRS(*srs.out()), { "SPATIALITE=TRUE", "OGR_SQLITE_SYNCHRONOUS=OFF", "INIT_WITH_EPSG=no" }),
++ m_layer_error_points(m_dataset, "error_points", wkbPoint, layer_options()),
++ m_layer_error_lines(m_dataset, "error_lines", wkbLineString, layer_options()),
++ m_layer_rings(m_dataset, "rings", wkbPolygon, layer_options()),
++ m_layer_land_polygons(m_dataset, "land_polygons", wkbPolygon, layer_options()),
++ m_layer_water_polygons(m_dataset, "water_polygons", wkbPolygon, layer_options()),
++ m_layer_lines(m_dataset, "lines", wkbLineString, layer_options()) {
++
++ m_layer_error_points.add_field("osm_id", OFTString, 10);
++ m_layer_error_points.add_field("error", OFTString, 16);
++ m_layer_error_points.start_transaction();
++
++ m_layer_error_lines.add_field("osm_id", OFTString, 10);
++ m_layer_error_lines.add_field("error", OFTString, 16);
++ m_layer_error_lines.start_transaction();
++
++ m_layer_rings.add_field("osm_id", OFTString, 10);
++ m_layer_rings.add_field("nways", OFTInteger, 6);
++ m_layer_rings.add_field("npoints", OFTInteger, 8);
++ m_layer_rings.add_field("fixed", OFTInteger, 1);
++ m_layer_rings.add_field("land", OFTInteger, 1);
++ m_layer_rings.add_field("valid", OFTInteger, 1);
++ m_layer_rings.start_transaction();
+
+- const char* options[] = { "SPATIALITE=yes", "OGR_SQLITE_SYNCHRONOUS=OFF", "INIT_WITH_EPSG=no", nullptr };
+- m_data_source.reset(driver->CreateDataSource(outdb.c_str(), const_cast<char**>(options)));
+- if (!m_data_source) {
+- std::cerr << "Creation of output file failed.\n";
+- exit(return_code_fatal);
+- }
++ m_layer_land_polygons.start_transaction();
+
+- m_layer_error_points.reset(new LayerErrorPoints(m_data_source.get(), layer_options()));
+- m_layer_error_lines.reset(new LayerErrorLines(m_data_source.get(), layer_options()));
+- m_layer_rings.reset(new LayerRings(m_data_source.get(), layer_options()));
+- m_layer_land_polygons.reset(new LayerPolygons(m_data_source.get(), layer_options(), "land_polygons"));
+- m_layer_water_polygons.reset(new LayerPolygons(m_data_source.get(), layer_options(), "water_polygons"));
+- m_layer_lines.reset(new LayerLines(m_data_source.get(), layer_options()));
++ m_layer_water_polygons.start_transaction();
+
+- exec("CREATE TABLE options (overlap REAL, close_distance REAL, max_points_in_polygons INTEGER, split_large_polygons INTEGER)");
+- exec("CREATE TABLE meta ("
++ m_layer_lines.start_transaction();
++
++ m_dataset.exec("CREATE TABLE options (overlap REAL, close_distance REAL, max_points_in_polygons INTEGER, split_large_polygons INTEGER)");
++ m_dataset.exec("CREATE TABLE meta ("
+ "timestamp TEXT, "
+ "runtime INTEGER, "
+ "memory_usage INTEGER, "
+@@ -99,7 +94,7 @@ void OutputDatabase::set_options(const O
+ << (options.split_large_polygons ? 1 : 0)
+ << ")";
+
+- exec(sql.str().c_str());
++ m_dataset.exec(sql.str());
+ }
+
+ void OutputDatabase::set_meta(int runtime, int memory_usage, const Stats& stats) {
+@@ -120,59 +115,124 @@ void OutputDatabase::set_meta(int runtim
+ << stats.land_polygons_after_split
+ << ")";
+
+- exec(sql.str().c_str());
++ m_dataset.exec(sql.str());
+ }
+
+ void OutputDatabase::commit() {
+- m_layer_lines->commit();
+- m_layer_water_polygons->commit();
+- m_layer_land_polygons->commit();
+- m_layer_rings->commit();
+- m_layer_error_lines->commit();
+- m_layer_error_points->commit();
+-}
+-
+-void OutputDatabase::add_error_point(std::unique_ptr<OGRPoint> point, const char* error, osmium::object_id_type id) {
+- m_layer_error_points->add(point.release(), error, id);
+-}
+-
+-void OutputDatabase::add_error_point(OGRPoint* point, const char* error, osmium::object_id_type id) {
+- m_layer_error_points->add(point, error, id);
+-}
+-
+-void OutputDatabase::add_error_line(std::unique_ptr<OGRLineString> linestring, const char* error, osmium::object_id_type id) {
+- m_layer_error_lines->add(linestring.release(), error, id);
+-}
+-
+-void OutputDatabase::add_error_line(OGRLineString* linestring, const char* error, osmium::object_id_type id) {
+- m_layer_error_lines->add(linestring, error, id);
+-}
+-
+-void OutputDatabase::add_ring(std::unique_ptr<OGRPolygon> polygon, int id, int nways, int npoints, bool fixed) {
+- layer_rings()->add(polygon.release(), id, nways, npoints, fixed, layer_error_points());
+-}
+-
+-void OutputDatabase::add_ring(OGRPolygon* polygon, int id, int nways, int npoints, bool fixed) {
+- layer_rings()->add(polygon, id, nways, npoints, fixed, layer_error_points());
+-}
+-
+-void OutputDatabase::add_land_polygon(OGRPolygon* polygon) {
+- layer_land_polygons()->add(polygon);
+-}
+-
+-void OutputDatabase::add_water_polygon(OGRPolygon* polygon) {
+- layer_water_polygons()->add(polygon);
+-}
+-
+-void OutputDatabase::add_line(std::unique_ptr<OGRLineString> linestring) {
+- layer_lines()->add(linestring.release());
+-}
+-
+-const char** OutputDatabase::layer_options() const {
+- return m_with_index ? options_with_index : options_without_index;
+-}
++ m_layer_lines.commit_transaction();
++ m_layer_water_polygons.commit_transaction();
++ m_layer_land_polygons.commit_transaction();
++ m_layer_rings.commit_transaction();
++ m_layer_error_lines.commit_transaction();
++ m_layer_error_points.commit_transaction();
++}
++
++void OutputDatabase::add_error_point(std::unique_ptr<OGRPoint>&& point, const char* error, osmium::object_id_type id) {
++ m_srs.transform(point.get());
++ gdalcpp::Feature feature(m_layer_error_points, std::move(point));
++ feature.set_field("osm_id", std::to_string(id).c_str());
++ feature.set_field("error", error);
++ feature.add_to_layer();
++}
++
++void OutputDatabase::add_error_line(std::unique_ptr<OGRLineString>&& linestring, const char* error, osmium::object_id_type id) {
++ m_srs.transform(linestring.get());
++ gdalcpp::Feature feature(m_layer_error_lines, std::move(linestring));
++ feature.set_field("osm_id", std::to_string(id).c_str());
++ feature.set_field("error", error);
++ feature.add_to_layer();
++}
++
++void OutputDatabase::add_ring(std::unique_ptr<OGRPolygon>&& polygon, int osm_id, int nways, int npoints, bool fixed) {
++ m_srs.transform(polygon.get());
++
++ bool land = polygon->getExteriorRing()->isClockwise();
++ bool valid = polygon->IsValid();
++
++ if (!valid) {
++ /*
++ When the polygon is invalid we find out what and where the problem is.
++ This code is a bit strange because older versions of the GEOS library
++ only export this information as a string. We parse the reason and
++ point coordinates (of a self-intersection-point for instance) from
++ this string and create a point in the error layer for it.
++
++ The exportToGEOS() method on OGR geometries is not documented. Let's
++ hope that it will always be available. We use the GEOSisValidReason()
++ function from the GEOS C interface to get to the reason.
++ */
++
++#if GDAL_VERSION_MAJOR == 1 && GDAL_VERSION_MINOR <= 10
++ GEOSGeom p { polygon->exportToGEOS() };
++ char* r = GEOSisValidReason(p);
++ std::string reason = r ? r : "";
++ GEOSFree(r);
++ GEOSGeom_destroy(p);
++#else
++ GEOSContextHandle_t contextHandle = OGRGeometry::createGEOSContext();
++ auto r = GEOSisValidReason(polygon->exportToGEOS(contextHandle));
++ std::string reason = r ? r : "";
++ OGRGeometry::freeGEOSContext(contextHandle);
++#endif
++
++ if (!reason.empty()) {
++ size_t left_bracket = reason.find('[');
++ size_t right_bracket = reason.find(']');
++
++ std::istringstream iss(reason.substr(left_bracket+1, right_bracket-left_bracket-1), std::istringstream::in);
++ double x;
++ double y;
++ iss >> x;
++ iss >> y;
++ reason = reason.substr(0, left_bracket);
++
++ std::unique_ptr<OGRPoint> point { new OGRPoint() };
++ point->assignSpatialReference(polygon->getSpatialReference());
++ point->setX(x);
++ point->setY(y);
++
++ if (reason == "Self-intersection") {
++ reason = "self_intersection";
++ }
++ add_error_point(std::move(point), reason.c_str(), osm_id);
++ } else {
++ std::cerr << "Did not get reason from GEOS why polygon " << osm_id << " is invalid. Could not write info to error points layer\n";
++ }
++ }
+
+-void OutputDatabase::exec(const char* sql) {
+- m_data_source->ReleaseResultSet(m_data_source->ExecuteSQL(sql, nullptr, nullptr));
++ gdalcpp::Feature feature(m_layer_rings, std::move(polygon));
++ feature.set_field("osm_id", osm_id);
++ feature.set_field("nways", nways);
++ feature.set_field("npoints", npoints);
++ feature.set_field("fixed", fixed);
++ feature.set_field("land", land);
++ feature.set_field("valid", valid);
++ feature.add_to_layer();
++}
++
++void OutputDatabase::add_land_polygon(std::unique_ptr<OGRPolygon>&& polygon) {
++ m_srs.transform(polygon.get());
++ gdalcpp::Feature feature(m_layer_land_polygons, std::move(polygon));
++ feature.add_to_layer();
++}
++
++void OutputDatabase::add_water_polygon(std::unique_ptr<OGRPolygon>&& polygon) {
++ m_srs.transform(polygon.get());
++ gdalcpp::Feature feature(m_layer_water_polygons, std::move(polygon));
++ feature.add_to_layer();
++}
++
++void OutputDatabase::add_line(std::unique_ptr<OGRLineString>&& linestring) {
++ m_srs.transform(linestring.get());
++ gdalcpp::Feature feature(m_layer_lines, std::move(linestring));
++ feature.add_to_layer();
++}
++
++std::vector<std::string> OutputDatabase::layer_options() const {
++ std::vector<std::string> options;
++ if (!m_with_index) {
++ options.emplace_back("SPATIAL_INDEX=no");
++ }
++ return options;
+ }
+
+--- a/src/output_database.hpp
++++ b/src/output_database.hpp
+@@ -24,18 +24,13 @@
+
+ #include <memory>
+ #include <string>
++#include <vector>
+
+ #include <osmium/osm/types.hpp>
+-#include <ogr_spatialref.h>
+
+-#include "ogr_include.hpp"
+-
+-class LayerErrorPoints;
+-class LayerErrorLines;
+-class LayerRings;
+-class LayerPolygons;
+-class LayerLines;
++#include <gdalcpp.hpp>
+
++class SRS;
+ class Options;
+ struct Stats;
+
+@@ -46,54 +41,50 @@ struct Stats;
+ */
+ class OutputDatabase {
+
+- static const char* options_without_index[];
+- static const char* options_with_index[];
+-
+ bool m_with_index;
+
+- std::unique_ptr<OGRDataSource, OGRDataSourceDestroyer> m_data_source;
++ SRS& m_srs;
++
++ gdalcpp::Dataset m_dataset;
++
++ // Any errors in a linestring
++ gdalcpp::Layer m_layer_error_points;
++
++ // Any errors in a point
++ gdalcpp::Layer m_layer_error_lines;
++
++ // Layer for polygon rings.
++ // Will contain polygons without holes, ie. with just an outer ring.
++ // Polygon outer rings will be oriented according to usual GIS custom with
++ // points going clockwise around the ring, ie "land" is on the right hand
++ // side of the border. This is the other way around from how it looks in
++ // OSM.
++ gdalcpp::Layer m_layer_rings;
++
++ // Completed land polygons.
++ gdalcpp::Layer m_layer_land_polygons;
+
+- std::unique_ptr<LayerErrorPoints> m_layer_error_points;
+- std::unique_ptr<LayerErrorLines> m_layer_error_lines;
+- std::unique_ptr<LayerRings> m_layer_rings;
+- std::unique_ptr<LayerPolygons> m_layer_land_polygons;
+- std::unique_ptr<LayerPolygons> m_layer_water_polygons;
+- std::unique_ptr<LayerLines> m_layer_lines;
++ // Completed water polygons.
++ gdalcpp::Layer m_layer_water_polygons;
+
+- const char** layer_options() const;
++ // Coastlines generated from completed polygons.
++ // Lines contain at most max-points points.
++ gdalcpp::Layer m_layer_lines;
+
+- /// Execute arbitrary SQL command on database
+- void exec(const char* sql);
++ std::vector<std::string> layer_options() const;
+
+ public:
+
+- OutputDatabase(const std::string& outdb, bool with_index=false);
++ OutputDatabase(const std::string& outdb, SRS& srs, bool with_index=false);
+
+- ~OutputDatabase();
++ ~OutputDatabase() noexcept = default;
+
+- void create_layer_error_points();
+- void create_layer_error_lines();
+- void create_layer_rings();
+- void create_layer_land_polygons();
+- void create_layer_water_polygons();
+- void create_layer_lines();
+-
+- LayerErrorPoints* layer_error_points() const { return m_layer_error_points.get(); }
+- LayerErrorLines* layer_error_lines() const { return m_layer_error_lines.get(); }
+- LayerRings* layer_rings() const { return m_layer_rings.get(); }
+- LayerPolygons* layer_land_polygons() const { return m_layer_land_polygons.get(); }
+- LayerPolygons* layer_water_polygons() const { return m_layer_water_polygons.get(); }
+- LayerLines* layer_lines() const { return m_layer_lines.get(); }
+-
+- void add_error_point(std::unique_ptr<OGRPoint> point, const char* error, osmium::object_id_type id=0);
+- void add_error_point(OGRPoint* point, const char* error, osmium::object_id_type id=0);
+- void add_error_line(std::unique_ptr<OGRLineString> linestring, const char* error, osmium::object_id_type id=0);
+- void add_error_line(OGRLineString* linestring, const char* error, osmium::object_id_type id=0);
+- void add_ring(std::unique_ptr<OGRPolygon> polygon, int id, int nways, int npoints, bool fixed);
+- void add_ring(OGRPolygon* polygon, int id, int nways, int npoints, bool fixed);
+- void add_land_polygon(OGRPolygon* polygon);
+- void add_water_polygon(OGRPolygon* polygon);
+- void add_line(std::unique_ptr<OGRLineString> linestring);
++ void add_error_point(std::unique_ptr<OGRPoint>&& point, const char* error, osmium::object_id_type id=0);
++ void add_error_line(std::unique_ptr<OGRLineString>&& linestring, const char* error, osmium::object_id_type id=0);
++ void add_ring(std::unique_ptr<OGRPolygon>&& polygon, int osm_id, int nways, int npoints, bool fixed);
++ void add_land_polygon(std::unique_ptr<OGRPolygon>&& polygon);
++ void add_water_polygon(std::unique_ptr<OGRPolygon>&& polygon);
++ void add_line(std::unique_ptr<OGRLineString>&& linestring);
+
+ void set_options(const Options& options);
+ void set_meta(int runtime, int memory_usage, const Stats& stats);
+--- a/src/output_layers.hpp
++++ /dev/null
+@@ -1,124 +0,0 @@
+-#ifndef OUTPUT_LAYER_HPP
+-#define OUTPUT_LAYER_HPP
+-
+-/*
+-
+- Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+-
+- This file is part of OSMCoastline.
+-
+- OSMCoastline is free software: you can redistribute it and/or modify
+- it under the terms of the GNU General Public License as published by
+- the Free Software Foundation, either version 3 of the License, or
+- (at your option) any later version.
+-
+- OSMCoastline is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- GNU General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with OSMCoastline. If not, see <http://www.gnu.org/licenses/>.
+-
+-*/
+-
+-#include <osmium/osm/types.hpp>
+-
+-#include "srs.hpp"
+-
+-extern SRS srs;
+-
+-class OGRLayer;
+-class OGRDataSource;
+-class OGRPoint;
+-class OGRLineString;
+-class OGRPolygon;
+-
+-/**
+- * Parent class for all output layers.
+- */
+-class Layer {
+-
+-protected:
+-
+- /// OGRLayer implementing this output layer.
+- OGRLayer* m_layer;
+-
+- Layer() : m_layer(nullptr) {}
+-
+-public:
+-
+- /// Commit transaction on this layer.
+- void commit();
+-
+-};
+-
+-/**
+- * Layer for any errors in one point.
+- */
+-class LayerErrorPoints : public Layer {
+-
+-public:
+-
+- LayerErrorPoints(OGRDataSource* data_source, const char** options);
+- void add(OGRPoint* point, const char* error, osmium::object_id_type id);
+-
+-};
+-
+-/**
+- * Layer for any errors in a linestring.
+- */
+-class LayerErrorLines : public Layer {
+-
+-public:
+-
+- LayerErrorLines(OGRDataSource* data_source, const char** options);
+- void add(OGRLineString* linestring, const char* error, osmium::object_id_type id);
+-
+-};
+-
+-/**
+- * Layer for polygon rings.
+- * Will contain polygons without holes, ie. with just an outer ring.
+- * Polygon outer rings will be oriented according to usual GIS custom with
+- * points going clockwise around the ring, ie "land" is on the right hand side of
+- * the border. This is the other way around from how it looks in OSM.
+- */
+-class LayerRings : public Layer {
+-
+-public:
+-
+- LayerRings(OGRDataSource* data_source, const char** options);
+- void add(OGRPolygon* polygon, int id, int nways, int npoints, bool fixed, LayerErrorPoints* layer_error_points);
+-
+-};
+-
+-/**
+- * Layer for completed polygons.
+- * Polygons can contain inner rings for large water areas such as the Caspian Sea.
+- */
+-class LayerPolygons : public Layer {
+-
+- const char* m_name;
+-
+-public:
+-
+- LayerPolygons(OGRDataSource* data_source, const char** options, const char* name);
+- void add(OGRPolygon* polygon);
+-
+-};
+-
+-/**
+- * Layer for coastlines generated from completed polygons.
+- * Lines containt at most max-points points.
+- */
+-class LayerLines : public Layer {
+-
+-public:
+-
+- LayerLines(OGRDataSource* data_source, const char** options);
+- void add(OGRLineString* lines);
+-
+-};
+-
+-#endif // OUTPUT_LAYER_HPP
+--- /dev/null
++++ b/src/return_codes.hpp
+@@ -0,0 +1,33 @@
++#ifndef OSMCOASTLINE_HPP
++#define OSMCOASTLINE_HPP
++
++/*
++
++ Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
++
++ This file is part of OSMCoastline.
++
++ OSMCoastline is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ OSMCoastline is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with OSMCoastline. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++enum return_codes {
++ return_code_ok = 0,
++ return_code_warning = 1,
++ return_code_error = 2,
++ return_code_fatal = 3,
++ return_code_cmdline = 4
++};
++
++#endif // OSMCOASTLINE_HPP
+--- /dev/null
++++ b/src/util.hpp
+@@ -0,0 +1,41 @@
++#ifndef UTIL_HPP
++#define UTIL_HPP
++
++/*
++
++ Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
++
++ This file is part of OSMCoastline.
++
++ OSMCoastline is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ OSMCoastline is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with OSMCoastline. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#include <memory>
++#include <type_traits>
++
++template <typename R, typename T>
++std::unique_ptr<R> make_unique_ptr_clone(const T* source) {
++ static_assert(std::is_convertible<T*, R*>::value, "T* must be convertible to R*");
++ return std::unique_ptr<R>(static_cast<R*>(source->clone()));
++}
++
++template <typename TDerived, typename TBase>
++std::unique_ptr<TDerived> static_cast_unique_ptr(std::unique_ptr<TBase>&& ptr) {
++ static_assert(std::is_base_of<TBase, TDerived>::value, "TDerived must be derived from TBase");
++ return std::unique_ptr<TDerived>(static_cast<TDerived*>(ptr.release()));
++}
++
++
++#endif // UTIL_HPP
diff --git a/debian/patches/series b/debian/patches/series
index 261dade..e18c720 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,2 @@
-gdal-2.0.patch
+#gdal-2.0.patch
+0001-Switch-to-gdalcpp.hpp.-Adds-support-for-GDAL-2.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osmcoastline.git
More information about the Pkg-grass-devel
mailing list