[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