[osmcoastline] 01/06: Imported Upstream version 2.1.2

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Thu Jan 7 07:16:37 UTC 2016


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository osmcoastline.

commit 373bcb54746eaf8d3a3af7d691c3588b90db2c60
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Thu Jan 7 07:40:03 2016 +0100

    Imported Upstream version 2.1.2
---
 .ycm_extra_conf.py                         |   2 +-
 CHANGELOG.md                               |  23 +-
 CMakeLists.txt                             |   8 +-
 README.md                                  |  15 +-
 cmake/FindOsmium.cmake                     |  13 +-
 include/gdalcpp.hpp                        | 406 +++++++++++++++++++++++++++++
 man/manpage.template                       |   2 +-
 man/osmcoastline.md                        |   3 +
 man/osmcoastline_filter.md                 |   3 +
 man/osmcoastline_readmeta.md               |   9 +
 man/osmcoastline_segments.md               |   3 +
 man/osmcoastline_ways.md                   |   9 +
 osmcoastline_readmeta                      |  16 ++
 src/CMakeLists.txt                         |   4 +-
 src/coastline_handlers.hpp                 |   2 +-
 src/coastline_polygons.cpp                 |  99 ++++---
 src/coastline_polygons.hpp                 |  15 +-
 src/coastline_ring.cpp                     |  14 +-
 src/coastline_ring.hpp                     |   2 +-
 src/coastline_ring_collection.cpp          |  27 +-
 src/coastline_ring_collection.hpp          |   4 +-
 src/ogr_include.hpp                        |  42 ---
 src/options.cpp                            |  15 +-
 src/options.hpp                            |   2 +-
 src/osmcoastline.cpp                       |  24 +-
 src/osmcoastline_filter.cpp                |  70 +++--
 src/osmcoastline_segments.cpp              |  76 ++----
 src/osmcoastline_ways.cpp                  | 115 +++-----
 src/output_database.cpp                    | 236 ++++++++++-------
 src/output_database.hpp                    |  89 +++----
 src/output_layers.cpp                      | 321 -----------------------
 src/output_layers.hpp                      | 124 ---------
 src/{osmcoastline.hpp => return_codes.hpp} |   2 +-
 src/srs.cpp                                |   2 +-
 src/srs.hpp                                |   2 +-
 src/stats.hpp                              |   2 +-
 src/util.hpp                               |  41 +++
 37 files changed, 951 insertions(+), 891 deletions(-)

diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py
index 53b3175..fdc78cb 100644
--- 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',
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c56fb4f..d1068a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,26 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 ### Fixed
 
 
+## [2.1.2] - 2016-01-05
+
+### Added
+
+- Add --help/-h and --version/-V options to all programs.
+
+### Changed
+
+- Use a better approximation for the southernmost coordinate for Mercator
+  projection.
+- Updated for newest libosmium version (2.5.2).
+- Uses gdalcpp.hpp from https://github.com/joto/gdalcpp instead of directly
+  talking to GDAL/OGR. Makes this compatible with GDAL 2.
+- Improved internal code using unique_ptr where possible.
+
+### Fixed
+
+- "Fixed" flag in rings layer now correct.
+
+
 ## [2.1.1] - 2015-08-31
 
 ### Changed
@@ -39,7 +59,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 - Added man pages
 
 
-[unreleased]: https://github.com/osmcode/osmium-tool/compare/v2.1.1...HEAD
+[unreleased]: https://github.com/osmcode/osmium-tool/compare/v2.1.2...HEAD
+[2.1.2]: https://github.com/osmcode/osmium-tool/compare/v2.1.1...v2.1.2
 [2.1.1]: https://github.com/osmcode/osmium-tool/compare/v2.1.0...v2.1.1
 [2.1.0]: https://github.com/osmcode/osmium-tool/compare/v2.0.1...v2.1.0
 [2.0.1]: https://github.com/osmcode/osmium-tool/compare/v2.0.0...v2.0.1
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c53c294..894b51a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,11 +22,13 @@ project(osmcoastline)
 
 set(OSMCOASTLINE_VERSION_MAJOR 2)
 set(OSMCOASTLINE_VERSION_MINOR 1)
-set(OSMCOASTLINE_VERSION_PATCH 1)
+set(OSMCOASTLINE_VERSION_PATCH 2)
 
 set(OSMCOASTLINE_VERSION
     ${OSMCOASTLINE_VERSION_MAJOR}.${OSMCOASTLINE_VERSION_MINOR}.${OSMCOASTLINE_VERSION_PATCH})
 
+add_definitions(-DOSMCOASTLINE_VERSION="${OSMCOASTLINE_VERSION}")
+
 set(AUTHOR "Jochen Topf <jochen at topf.org>")
 
 
@@ -36,6 +38,8 @@ set(AUTHOR "Jochen Topf <jochen at topf.org>")
 #
 #-----------------------------------------------------------------------------
 
+include_directories(include)
+
 find_package(Osmium COMPONENTS io gdal)
 include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
 
@@ -242,7 +246,7 @@ configure_file(
 configure_file(
     ${PROJECT_SOURCE_DIR}/osmcoastline_readmeta
     ${PROJECT_BINARY_DIR}/osmcoastline_readmeta
-    COPYONLY
+    @ONLY
 )
 install(PROGRAMS osmcoastline_readmeta DESTINATION bin)
 
diff --git a/README.md b/README.md
index 7a8c656..081808a 100644
--- a/README.md
+++ b/README.md
@@ -13,8 +13,21 @@ https://github.com/osmcode/osmcoastline
 
 ### Libosmium
 
-    http://github.com/osmcode/libosmium
+    https://github.com/osmcode/libosmium
     http://osmcode.org/libosmium
+    At least version 2.5.0 is needed.
+
+### Protozero
+
+    https://github.com/mapbox/protozero
+    Debian/Ubuntu: protozero
+    Also included in the libosmium repository.
+
+### Utfcpp
+
+    http://utfcpp.sourceforge.net/
+    Debian/Ubuntu: libutfcpp-dev
+    Also included in the libosmium repository.
 
 ### zlib (for PBF support)
 
diff --git a/cmake/FindOsmium.cmake b/cmake/FindOsmium.cmake
index b3a4c95..fba8ffb 100644
--- a/cmake/FindOsmium.cmake
+++ b/cmake/FindOsmium.cmake
@@ -62,6 +62,8 @@ find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
         /opt
 )
 
+set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}")
+
 #----------------------------------------------------------------------
 #
 #  Check for optional components
@@ -251,20 +253,15 @@ endif()
 #  Check that all required libraries are available
 #
 #----------------------------------------------------------------------
-list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
+if (OSMIUM_EXTRA_FIND_VARS)
+    list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
+endif()
 # Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if
 # all listed variables are TRUE.
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Osmium REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS})
 unset(OSMIUM_EXTRA_FIND_VARS)
 
-# Copy the results to the output variables.
-if(OSMIUM_FOUND)
-    set(OSMIUM_INCLUDE_DIRS ${OSMIUM_INCLUDE_DIR} ${OSMIUM_INCLUDE_DIRS})
-else()
-    set(OSMIUM_INCLUDE_DIRS "")
-endif()
-
 #----------------------------------------------------------------------
 #
 #  Add compiler flags
diff --git a/include/gdalcpp.hpp b/include/gdalcpp.hpp
new file mode 100644
index 0000000..1502f2f
--- /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
diff --git a/man/manpage.template b/man/manpage.template
index 2f2405d..0328c7d 100644
--- a/man/manpage.template
+++ b/man/manpage.template
@@ -15,7 +15,7 @@ $endfor$
 $if(author)$
 .SH COPYRIGHT
 .PP
-Copyright (C) 2012\-2015 Jochen Topf <jochen at topf.org>.
+Copyright (C) 2012\-2016 Jochen Topf <jochen at topf.org>.
 License GPLv3+: GNU GPL version 3 or later
 <http://gnu.org/licenses/gpl.html>.
 This is free software: you are free to change and redistribute it.
diff --git a/man/osmcoastline.md b/man/osmcoastline.md
index a115fb8..f1bc1d5 100644
--- a/man/osmcoastline.md
+++ b/man/osmcoastline.md
@@ -91,6 +91,9 @@ description of the options below and the README.md for details.
 :   Gives you detailed information on what **osmcoastline** is doing,
     including timing.
 
+-V, --version
+:   Display program version and license information.
+
 
 # NOTES
 
diff --git a/man/osmcoastline_filter.md b/man/osmcoastline_filter.md
index edc1219..e750d39 100644
--- a/man/osmcoastline_filter.md
+++ b/man/osmcoastline_filter.md
@@ -40,6 +40,9 @@ the **osmcoastline** and **osmcoastline_ways** programs work fine with it.
 -o, --output=OSMFILE
 :   Where to write output (default: none)
 
+-V, --version
+:   Display program version and license information.
+
 
 # EXAMPLES
 
diff --git a/man/osmcoastline_readmeta.md b/man/osmcoastline_readmeta.md
index e096179..0a477ab 100644
--- a/man/osmcoastline_readmeta.md
+++ b/man/osmcoastline_readmeta.md
@@ -9,6 +9,15 @@ osmcoastline_readmeta - display metadata from database create by osmcoastline
 **osmcoastline_readmeta** \[*COASTLINE-DB*\]
 
 
+# OPTIONS
+
+-h, --help
+:   Display usage information.
+
+-V, --version
+:   Display program version and license information.
+
+
 # DESCRIPTION
 
 This program displays various meta data from a database created by the
diff --git a/man/osmcoastline_segments.md b/man/osmcoastline_segments.md
index fc0ab81..cfff865 100644
--- a/man/osmcoastline_segments.md
+++ b/man/osmcoastline_segments.md
@@ -31,6 +31,9 @@ coastline changes between different runs of the **osmcoastline** program.
 -f, --format=FORMAT
 :   OGR format for writing out geometries.
 
+-V, --version
+:   Display program version and license information.
+
 
 # DIAGNOSTICS
 
diff --git a/man/osmcoastline_ways.md b/man/osmcoastline_ways.md
index 8ec3b25..e432960 100644
--- a/man/osmcoastline_ways.md
+++ b/man/osmcoastline_ways.md
@@ -9,6 +9,15 @@ osmcoastline_ways - extract coastline ways from OSM data
 **osmcoastline_ways** *INPUT-FILE* \[*OUTPUT-DB*\]
 
 
+# OPTIONS
+
+-h, --help
+:   Display usage information.
+
+-V, --version
+:   Display program version and license information.
+
+
 # DESCRIPTION
 
 **osmcoastline_ways** extracts coastline ways from OSM data and writes them
diff --git a/osmcoastline_readmeta b/osmcoastline_readmeta
index f1478b3..a12bf9e 100755
--- a/osmcoastline_readmeta
+++ b/osmcoastline_readmeta
@@ -3,8 +3,24 @@
 #  osmcoastline_readmeta [COASTLINEDB]
 #
 
+OSMCOASTLINE_VERSION=@OSMCOASTLINE_VERSION@
+
 SQLEXEC="sqlite3"
 
+if [ "x$1" = "x--help" -o "x$1" = "x-h" ]; then
+    echo "Usage: osmcoastline_readmeta [COASTLINEDB]"
+    exit 0
+fi
+
+if [ "x$1" = "x--version" -o "x$1" = "x-V" ]; then
+    echo "osmcoastline_readmeta version $OSMCOASTLINE_VERSION"
+    echo "Copyright (C) 2012-2016  Jochen Topf <jochen at topf.org>"
+    echo "License: GNU GENERAL PUBLIC LICENSE Version 3 <http://gnu.org/licenses/gpl.html>."
+    echo "This is free software: you are free to change and redistribute it."
+    echo "There is NO WARRANTY, to the extent permitted by law.";
+    exit 0
+fi
+
 if [ "x$1" = "x" ]; then
     DBFILE=testdata.db
 else
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 907dd1c..ce62288 100644
--- 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 osmcoastline_segments.cpp srs.cpp)
 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)
 
diff --git a/src/coastline_handlers.hpp b/src/coastline_handlers.hpp
index 2eeca6f..449b2d4 100644
--- a/src/coastline_handlers.hpp
+++ b/src/coastline_handlers.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
diff --git a/src/coastline_polygons.cpp b/src/coastline_polygons.cpp
index 8094327..255e7b8 100644
--- a/src/coastline_polygons.cpp
+++ b/src/coastline_polygons.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -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_direction() {
                 // 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_direction() {
 
 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;
     }
@@ -190,10 +191,11 @@ void CoastlinePolygons::split_polygon(OGRPolygon* polygon, int level) {
 
 void CoastlinePolygons::split() {
     polygon_vector_type v;
-    std::swap(v, m_polygons);
+    using std::swap;
+    swap(v, m_polygons);
     m_polygons.reserve(v.size());
     for (auto& polygon : v) {
-        split_polygon(polygon, 0);
+        split_polygon(std::move(polygon), 0);
     }
 }
 
@@ -201,16 +203,17 @@ void CoastlinePolygons::output_land_polygons(bool make_copy) {
     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();
     }
 }
 
-bool CoastlinePolygons::add_segment_to_line(OGRLineString* line, OGRPoint* point1, OGRPoint* point2) {
+bool CoastlinePolygons::add_segment_to_line(OGRLineString* line, OGRPoint* point1, OGRPoint* point2) const {
     // segments along southern edge of the map are not added to line output
     if (point1->getY() < srs.min_y() && point2->getY() < srs.min_y()) {
         if (debug) {
@@ -235,9 +238,15 @@ bool CoastlinePolygons::add_segment_to_line(OGRLineString* line, OGRPoint* point
     return true;
 }
 
+void CoastlinePolygons::add_line_to_output(std::unique_ptr<OGRLineString> line, OGRSpatialReference* srs) const {
+    line->setCoordinateDimension(2);
+    line->assignSpatialReference(srs);
+    m_output.add_line(std::move(line));
+}
+
 // Add a coastline ring as LineString to output. Segments in this line that are
 // near the southern edge of the map or near the antimeridian are suppressed.
-void CoastlinePolygons::output_polygon_ring_as_lines(int max_points, OGRLinearRing* ring) {
+void CoastlinePolygons::output_polygon_ring_as_lines(int max_points, const OGRLinearRing* ring) const {
     int num = ring->getNumPoints();
     assert(num > 2);
 
@@ -253,11 +262,10 @@ void CoastlinePolygons::output_polygon_ring_as_lines(int max_points, OGRLinearRi
 
         if (line->getNumPoints() >= max_points || !added) {
             if (line->getNumPoints() >= 2) {
-                line->setCoordinateDimension(2);
-                line->assignSpatialReference(ring->getSpatialReference());
                 std::unique_ptr<OGRLineString> new_line { new OGRLineString };
-                std::swap(line, new_line);
-                m_output.add_line(std::move(new_line));
+                using std::swap;
+                swap(line, new_line);
+                add_line_to_output(std::move(new_line), ring->getSpatialReference());
             }
         }
 
@@ -266,14 +274,12 @@ void CoastlinePolygons::output_polygon_ring_as_lines(int max_points, OGRLinearRi
     }
 
     if (line->getNumPoints() >= 2) {
-        line->setCoordinateDimension(2);
-        line->assignSpatialReference(ring->getSpatialReference());
-        m_output.add_line(std::move(line));
+        add_line_to_output(std::move(line), ring->getSpatialReference());
     }
 }
 
-void CoastlinePolygons::output_lines(int max_points) {
-    for (OGRPolygon* polygon : m_polygons) {
+void CoastlinePolygons::output_lines(int max_points) const {
+    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 +293,27 @@ void CoastlinePolygons::split_bbox(OGREnvelope e, polygon_vector_type&& v) {
         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,19 +363,24 @@ void CoastlinePolygons::split_bbox(OGREnvelope e, polygon_vector_type&& v) {
 
         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
             it has no measurable impact. */
             OGREnvelope e;
             polygon->getEnvelope(&e);
-            if (e1.Intersects(e)) {
-                v1.push_back(polygon);
-            }
 
-            if (e2.Intersects(e)) {
-                v2.push_back(polygon);
+            bool e1_intersects_e = e1.Intersects(e);
+            bool e2_intersects_e = e2.Intersects(e);
+
+            if (e1_intersects_e && e2_intersects_e) {
+                v1.emplace_back(static_cast<OGRPolygon*>(polygon->clone()));
+                v2.push_back(std::move(polygon));
+            } else if (e1_intersects_e) {
+                v1.push_back(std::move(polygon));
+            } else if (e2_intersects_e) {
+                v2.push_back(std::move(polygon));
             }
         }
         split_bbox(e1, std::move(v1));
@@ -379,9 +392,9 @@ void CoastlinePolygons::split_bbox(OGREnvelope e, polygon_vector_type&& v) {
 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;
diff --git a/src/coastline_polygons.hpp b/src/coastline_polygons.hpp
index 7d7e8a4..9296248 100644
--- a/src/coastline_polygons.hpp
+++ b/src/coastline_polygons.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -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,12 +74,13 @@ 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);
-    void output_polygon_ring_as_lines(int max_points, OGRLinearRing* ring);
+    void add_line_to_output(std::unique_ptr<OGRLineString> line, OGRSpatialReference* srs) const;
+    bool add_segment_to_line(OGRLineString* line, OGRPoint* point1, OGRPoint* point2) const;
+    void output_polygon_ring_as_lines(int max_points, const OGRLinearRing* ring) const;
 
 public:
 
@@ -120,7 +121,7 @@ public:
     unsigned int output_water_polygons();
 
     /// Write all coastlines to the output database (as lines).
-    void output_lines(int max_points);
+    void output_lines(int max_points) const;
 
 };
 
diff --git a/src/coastline_ring.cpp b/src/coastline_ring.cpp
index 8a078a1..ef4057f 100644
--- a/src/coastline_ring.cpp
+++ b/src/coastline_ring.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -90,18 +90,18 @@ void CoastlineRing::close_ring() {
 }
 
 void CoastlineRing::close_antarctica_ring(int epsg) {
-    double min = epsg == 4326 ? -90.0 : -85.0511;
+    double min = epsg == 4326 ? -90.0 : -85.0511288;
 
-    for (double lat = -78.0; lat > min; --lat) {
-        m_way_node_list.emplace_back(0, osmium::Location(-179.99999, static_cast<double>(lat)));
+    for (int lat = -78; lat > int(min); --lat) {
+        m_way_node_list.emplace_back(0, osmium::Location(-179.99999, double(lat)));
     }
 
     for (int lon = -180; lon < 180; ++lon) {
-        m_way_node_list.emplace_back(0, osmium::Location(static_cast<double>(lon), min));
+        m_way_node_list.emplace_back(0, osmium::Location(double(lon), min));
     }
 
-    for (double lat = min; lat < -78.0; ++lat) {
-        m_way_node_list.emplace_back(0, osmium::Location(179.99999, static_cast<double>(lat)));
+    for (int lat = int(min); lat < -78; ++lat) {
+        m_way_node_list.emplace_back(0, osmium::Location(179.99999, double(lat)));
     }
 
     m_way_node_list.push_back(m_way_node_list.front());
diff --git a/src/coastline_ring.hpp b/src/coastline_ring.hpp
index e930b7a..48d7c86 100644
--- a/src/coastline_ring.hpp
+++ b/src/coastline_ring.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
diff --git a/src/coastline_ring_collection.cpp b/src/coastline_ring_collection.cpp
index 3101514..56b0c43 100644
--- a/src/coastline_ring_collection.cpp
+++ b/src/coastline_ring_collection.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -126,7 +126,16 @@ unsigned int CoastlineRingCollection::check_positions(bool output_missing) {
     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_polygons_to_vector(std::vector<OGRGeometry*>&
                 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::output_rings(OutputDatabase& output) {
     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++;
@@ -409,7 +420,7 @@ unsigned int CoastlineRingCollection::output_questionable(const CoastlinePolygon
 
     // go through all the polygons that have been created before and mark the outer rings
     for (const auto& polygon : polygons) {
-        OGRLinearRing* exterior_ring = polygon->getExteriorRing();
+        const OGRLinearRing* exterior_ring = polygon->getExteriorRing();
         osmium::Location pos(exterior_ring->getX(0), exterior_ring->getY(0));
         std::vector<pos_ring_ptr_t>::iterator rings_it = lower_bound(rings.begin(), rings.end(), std::make_pair<osmium::Location, CoastlineRing*>(std::move(pos), nullptr));
         if (rings_it != rings.end()) {
diff --git a/src/coastline_ring_collection.hpp b/src/coastline_ring_collection.hpp
index 21e6f7e..bef8eb1 100644
--- a/src/coastline_ring_collection.hpp
+++ b/src/coastline_ring_collection.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -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);
 
diff --git a/src/ogr_include.hpp b/src/ogr_include.hpp
deleted file mode 100644
index d372d6a..0000000
--- 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
diff --git a/src/options.cpp b/src/options.cpp
index 7c11a24..fd51edd 100644
--- a/src/options.cpp
+++ b/src/options.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -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[]) :
@@ -62,11 +62,12 @@ Options::Options(int argc, char* argv[]) :
         {"srs",             required_argument, 0, 's'},
         {"write-segments",  required_argument, 0, 'S'},
         {"verbose",               no_argument, 0, 'v'},
+        {"version",               no_argument, 0, 'V'},
         {0, 0, 0, 0}
     };
 
     while (1) {
-        int c = getopt_long(argc, argv, "b:c:idhlm:o:p:rfs:S:v", long_options, 0);
+        int c = getopt_long(argc, argv, "b:c:idhlm:o:p:rfs:S:vV", long_options, 0);
         if (c == -1)
             break;
 
@@ -131,6 +132,13 @@ Options::Options(int argc, char* argv[]) :
             case 'v':
                 verbose = true;
                 break;
+            case 'V':
+                std::cout << "osmcoastline version " OSMCOASTLINE_VERSION "\n"
+                          << "Copyright (C) 2012-2016  Jochen Topf <jochen at topf.org>\n"
+                          << "License: GNU GENERAL PUBLIC LICENSE Version 3 <http://gnu.org/licenses/gpl.html>.\n"
+                          << "This is free software: you are free to change and redistribute it.\n"
+                          << "There is NO WARRANTY, to the extent permitted by law.\n";
+                exit(return_code_ok);
             default:
                 exit(return_code_cmdline);
         }
@@ -197,6 +205,7 @@ void Options::print_help() const {
               << "  -s, --srs=EPSGCODE         - Set SRS (4326 for WGS84 (default) or 3857)\n"
               << "  -S, --write-segments=FILE  - Write segments to given file\n"
               << "  -v, --verbose              - Verbose output\n"
+              << "  -V, --version              - Show version and exit\n"
               << "\n";
 }
 
diff --git a/src/options.hpp b/src/options.hpp
index f6d8dc6..57e04dc 100644
--- a/src/options.hpp
+++ b/src/options.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
diff --git a/src/osmcoastline.cpp b/src/osmcoastline.cpp
index 5f8adcf..262b81b 100644
--- a/src/osmcoastline.cpp
+++ b/src/osmcoastline.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -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(CoastlineRingCollection& coastline_rings, Ou
         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(CoastlineRingCollection& coastline_rings, Ou
         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(CoastlineRingCollection& coastline_rings, Ou
     }
 
     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.
diff --git a/src/osmcoastline_filter.cpp b/src/osmcoastline_filter.cpp
index a89bfec..9a3f951 100644
--- a/src/osmcoastline_filter.cpp
+++ b/src/osmcoastline_filter.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -19,22 +19,26 @@
 
 */
 
+#include <algorithm>
 #include <iostream>
 #include <set>
 #include <getopt.h>
 
 #include <osmium/io/any_input.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/io/output_iterator.hpp>
 #include <osmium/io/pbf_output.hpp>
 #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"
               << "\nOptions:\n"
               << "  -h, --help           - This help message\n"
               << "  -o, --output=OSMFILE - Where to write output (default: none)\n"
+              << "  -V, --version        - Show version and exit\n"
               << "\n";
 }
 
@@ -44,11 +48,12 @@ int main(int argc, char* argv[]) {
     static struct option long_options[] = {
         {"help",         no_argument, 0, 'h'},
         {"output", required_argument, 0, 'o'},
+        {"version",      no_argument, 0, 'V'},
         {0, 0, 0, 0}
     };
 
     while (1) {
-        int c = getopt_long(argc, argv, "ho:", long_options, 0);
+        int c = getopt_long(argc, argv, "ho:V", long_options, 0);
         if (c == -1)
             break;
 
@@ -59,6 +64,13 @@ int main(int argc, char* argv[]) {
             case 'o':
                 output_filename = optarg;
                 break;
+            case 'V':
+                std::cout << "osmcoastline_filter version " OSMCOASTLINE_VERSION "\n"
+                          << "Copyright (C) 2012-2016  Jochen Topf <jochen at topf.org>\n"
+                          << "License: GNU GENERAL PUBLIC LICENSE Version 3 <http://gnu.org/licenses/gpl.html>.\n"
+                          << "This is free software: you are free to change and redistribute it.\n"
+                          << "There is NO WARRANTY, to the extent permitted by law.\n";
+                exit(return_code_ok);
             default:
                 exit(return_code_fatal);
         }
@@ -82,55 +94,39 @@ int main(int argc, char* argv[]) {
 
     try {
         osmium::io::Writer writer(output_filename, header);
+        auto output_it = osmium::io::make_output_iterator(writer);
 
-        std::set<osmium::object_id_type> ids;
-        osmium::memory::Buffer output_buffer(10240);
+        std::vector<osmium::object_id_type> ids;
 
         {
             osmium::io::Reader reader(infile, osmium::osm_entity_bits::way);
-            while (auto input_buffer = reader.read()) {
-                for (auto it = input_buffer.begin<const osmium::Way>(); it != input_buffer.end<const osmium::Way>(); ++it) {
-                    const char* natural = it->get_value_by_key("natural");
-                    if (natural && !strcmp(natural, "coastline")) {
-                        output_buffer.add_item(*it);
-                        output_buffer.commit();
-                        if (output_buffer.committed() >= 10240) {
-                            osmium::memory::Buffer new_buffer(10240);
-                            std::swap(output_buffer, new_buffer);
-                            writer(std::move(new_buffer));
-                        }
-                        for (const auto& nr : it->nodes()) {
-                            ids.insert(nr.ref());
-                        }
+            auto ways = osmium::io::make_input_iterator_range<const osmium::Way>(reader);
+            for (const osmium::Way& way : ways) {
+                const char* natural = way.get_value_by_key("natural");
+                if (natural && !strcmp(natural, "coastline")) {
+                    *output_it++ = way;
+                    for (const auto& nr : way.nodes()) {
+                        ids.push_back(nr.ref());
                     }
                 }
             }
             reader.close();
         }
 
+        std::sort(ids.begin(), ids.end());
+        auto last = std::unique(ids.begin(), ids.end());
+
         {
             osmium::io::Reader reader(infile, osmium::osm_entity_bits::node);
-            while (auto input_buffer = reader.read()) {
-                for (auto it = input_buffer.begin<const osmium::Node>(); it != input_buffer.end<const osmium::Node>(); ++it) {
-                    const char* natural = it->get_value_by_key("natural");
-                    if ((ids.find(it->id()) != ids.end()) || (natural && !strcmp(natural, "coastline"))) {
-                        output_buffer.add_item(*it);
-                        output_buffer.commit();
-                        if (output_buffer.committed() >= 10240) {
-                            osmium::memory::Buffer new_buffer(10240);
-                            std::swap(output_buffer, new_buffer);
-                            writer(std::move(new_buffer));
-                        }
-                    }
-                }
-            }
+            auto nodes = osmium::io::make_input_iterator_range<const osmium::Node>(reader);
+            std::copy_if(nodes.cbegin(), nodes.cend(), output_it, [&ids, &last](const osmium::Node& node){
+                const char* natural = node.get_value_by_key("natural");
+                return std::binary_search(ids.begin(), last, node.id()) ||
+                       (natural && !strcmp(natural, "coastline"));
+            });
             reader.close();
         }
 
-        if (output_buffer.committed() > 0) {
-            writer(std::move(output_buffer));
-        }
-
         writer.close();
     } catch (osmium::io_error& e) {
         std::cerr << "io error: " << e.what() << "'\n";
diff --git a/src/osmcoastline_segments.cpp b/src/osmcoastline_segments.cpp
index 1702960..9dd74c5 100644
--- a/src/osmcoastline_segments.cpp
+++ b/src/osmcoastline_segments.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -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();
+    gdalcpp::Dataset dataset{driver_name, filename};
 
-    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);
-    }
-
-    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& filename, const std::string& driver_name, con
         add_segment(layer, 1, segment);
     }
 
-    layer->CommitTransaction();
+    layer.commit_transaction();
 }
 
 int main(int argc, char *argv[]) {
@@ -145,11 +111,12 @@ int main(int argc, char *argv[]) {
         {"format", required_argument, 0, 'f'},
         {"geom",   required_argument, 0, 'g'},
         {"help",         no_argument, 0, 'h'},
+        {"version",      no_argument, 0, 'V'},
         {0, 0, 0, 0}
     };
 
     while (1) {
-        int c = getopt_long(argc, argv, "df:g:h", long_options, 0);
+        int c = getopt_long(argc, argv, "df:g:hV", long_options, 0);
         if (c == -1)
             break;
 
@@ -168,6 +135,13 @@ int main(int argc, char *argv[]) {
                 print_help();
                 exit(return_code_ok);
             }
+            case 'V':
+                std::cout << "osmcoastline_segments version " OSMCOASTLINE_VERSION "\n"
+                          << "Copyright (C) 2012-2016  Jochen Topf <jochen at topf.org>\n"
+                          << "License: GNU GENERAL PUBLIC LICENSE Version 3 <http://gnu.org/licenses/gpl.html>.\n"
+                          << "This is free software: you are free to change and redistribute it.\n"
+                          << "There is NO WARRANTY, to the extent permitted by law.\n";
+                exit(return_code_ok);
             default:
                 break;
         }
@@ -185,8 +159,8 @@ int main(int argc, char *argv[]) {
         InputFile file1(argv[optind]);
         InputFile file2(argv[optind+1]);
 
-        osmium::util::TypedMemoryMapping<osmium::UndirectedSegment> m1(file1.size() / sizeof(osmium::UndirectedSegment), false, file1.fd());
-        osmium::util::TypedMemoryMapping<osmium::UndirectedSegment> m2(file2.size() / sizeof(osmium::UndirectedSegment), false, file2.fd());
+        osmium::util::TypedMemoryMapping<osmium::UndirectedSegment> m1(file1.size() / sizeof(osmium::UndirectedSegment), osmium::util::MemoryMapping::mapping_mode::readonly, file1.fd());
+        osmium::util::TypedMemoryMapping<osmium::UndirectedSegment> m2(file2.size() / sizeof(osmium::UndirectedSegment), osmium::util::MemoryMapping::mapping_mode::readonly, file2.fd());
 
         std::set_difference(m1.cbegin(), m1.cend(), m2.cbegin(), m2.cend(), std::back_inserter(removed_segments));
         std::set_difference(m2.cbegin(), m2.cend(), m1.cbegin(), m1.cend(), std::back_inserter(added_segments));
diff --git a/src/osmcoastline_ways.cpp b/src/osmcoastline_ways.cpp
index 6dcfe89..cd38493 100644
--- a/src/osmcoastline_ways.cpp
+++ b/src/osmcoastline_ways.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -19,8 +19,9 @@
 
 */
 
+#include <cstring>
 #include <iostream>
-#include <set>
+#include <memory>
 #include <string>
 
 #include <osmium/geom/haversine.hpp>
@@ -30,8 +31,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 +42,41 @@ class CoastlineWaysHandler : public osmium::handler::Handler {
 
     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";
         }
@@ -140,6 +89,22 @@ public:
 };
 
 int main(int argc, char* argv[]) {
+    if (argc >= 2) {
+        if (!std::strcmp(argv[1], "--help") || !std::strcmp(argv[1], "-h")) {
+            std::cout << "Usage: osmcoastline_ways OSMFILE [WAYSDB]\n";
+            exit(return_code_ok);
+        }
+
+        if (!std::strcmp(argv[1], "--version") || !std::strcmp(argv[1], "-V")) {
+            std::cout << "osmcoastline_ways version " OSMCOASTLINE_VERSION "\n"
+                      << "Copyright (C) 2012-2016  Jochen Topf <jochen at topf.org>\n"
+                      << "License: GNU GENERAL PUBLIC LICENSE Version 3 <http://gnu.org/licenses/gpl.html>.\n"
+                      << "This is free software: you are free to change and redistribute it.\n"
+                      << "There is NO WARRANTY, to the extent permitted by law.\n";
+            exit(return_code_ok);
+        }
+    }
+
     if (argc != 2 && argc != 3) {
         std::cerr << "Usage: osmcoastline_ways OSMFILE [WAYSDB]\n";
         exit(return_code_cmdline);
diff --git a/src/output_database.cpp b/src/output_database.cpp
index 87116d3..b1b385a 100644
--- a/src/output_database.cpp
+++ b/src/output_database.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -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);
-    }
-
-    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_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()));
-
-    exec("CREATE TABLE options (overlap REAL, close_distance REAL, max_points_in_polygons INTEGER, split_large_polygons INTEGER)");
-    exec("CREATE TABLE meta ("
+    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();
+
+    m_layer_land_polygons.start_transaction();
+
+    m_layer_water_polygons.start_transaction();
+
+    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 Options& options) {
         << (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 runtime, int memory_usage, const Stats& stats)
         << 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());
-}
+    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::add_land_polygon(OGRPolygon* polygon) {
-    layer_land_polygons()->add(polygon);
+    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_water_polygon(OGRPolygon* polygon) {
-    layer_water_polygons()->add(polygon);
+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_line(std::unique_ptr<OGRLineString> linestring) {
-    layer_lines()->add(linestring.release());
+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();
 }
 
-const char** OutputDatabase::layer_options() const {
-    return m_with_index ? options_with_index : options_without_index;
+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();
 }
 
-void OutputDatabase::exec(const char* sql) {
-    m_data_source->ReleaseResultSet(m_data_source->ExecuteSQL(sql, nullptr, nullptr));
+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;
 }
 
diff --git a/src/output_database.hpp b/src/output_database.hpp
index 2c19dbb..4dac320 100644
--- a/src/output_database.hpp
+++ b/src/output_database.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
@@ -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;
 
-    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;
+    // 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;
 
-    const char** layer_options() const;
+    // Completed land polygons.
+    gdalcpp::Layer m_layer_land_polygons;
 
-    /// Execute arbitrary SQL command on database
-    void exec(const char* sql);
+    // Completed water polygons.
+    gdalcpp::Layer m_layer_water_polygons;
+
+    // Coastlines generated from completed polygons.
+    // Lines contain at most max-points points.
+    gdalcpp::Layer m_layer_lines;
+
+    std::vector<std::string> layer_options() const;
 
 public:
 
-    OutputDatabase(const std::string& outdb, bool with_index=false);
-
-    ~OutputDatabase();
-
-    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);
+    OutputDatabase(const std::string& outdb, SRS& srs, bool with_index=false);
+
+    ~OutputDatabase() noexcept = default;
+
+    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);
diff --git a/src/output_layers.cpp b/src/output_layers.cpp
deleted file mode 100644
index 969eea2..0000000
--- a/src/output_layers.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
-
-  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 <cassert>
-#include <iostream>
-#include <sstream>
-#include <stdexcept>
-#include <string>
-
-#include <gdal_version.h>
-#include <geos_c.h>
-
-#include <osmium/osm/types.hpp>
-
-#include "ogr_include.hpp"
-#include "osmcoastline.hpp"
-#include "output_layers.hpp"
-#include "srs.hpp"
-
-extern SRS srs;
-
-/***************************************************************/
-
-void Layer::commit() {
-    if (m_layer->CommitTransaction() != OGRERR_NONE) {
-        throw std::runtime_error("Layer commit failed");
-    }
-}
-
-/***************************************************************/
-
-LayerErrorPoints::LayerErrorPoints(OGRDataSource* data_source, const char** options) :
-    Layer() {
-    m_layer = data_source->CreateLayer("error_points", srs.out(), wkbPoint, const_cast<char**>(options));
-    if (!m_layer) {
-        std::cerr << "Creating layer 'error_points' failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_osm_id("osm_id", OFTString);
-    field_osm_id.SetWidth(10);
-    if (m_layer->CreateField(&field_osm_id) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'osm_id' on 'error_points' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_error("error", OFTString);
-    field_error.SetWidth(16);
-    if (m_layer->CreateField(&field_error) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'error' on 'error_points' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    m_layer->StartTransaction();
-}
-
-void LayerErrorPoints::add(OGRPoint* point, const char* error, osmium::object_id_type osm_id) {
-    srs.transform(point);
-
-    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
-
-    feature->SetGeometryDirectly(point);
-    feature->SetField("osm_id", std::to_string(osm_id).c_str());
-    feature->SetField("error", error);
-
-    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
-        std::cerr << "Failed to create feature on layer 'error_points'.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFeature::DestroyFeature(feature);
-}
-
-/***************************************************************/
-
-LayerErrorLines::LayerErrorLines(OGRDataSource* data_source, const char** options) :
-    Layer() {
-    m_layer = data_source->CreateLayer("error_lines", srs.out(), wkbLineString, const_cast<char**>(options));
-    if (!m_layer) {
-        std::cerr << "Creating layer 'error_lines' failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_osm_id("osm_id", OFTString);
-    field_osm_id.SetWidth(10);
-    if (m_layer->CreateField(&field_osm_id) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'osm_id' on 'error_lines' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_error("error", OFTString);
-    field_error.SetWidth(16);
-    if (m_layer->CreateField(&field_error) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'error' on 'error_lines' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    m_layer->StartTransaction();
-}
-
-void LayerErrorLines::add(OGRLineString* linestring, const char* error, osmium::object_id_type osm_id) {
-    srs.transform(linestring);
-
-    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
-
-    feature->SetGeometryDirectly(linestring);
-    feature->SetField("osm_id", std::to_string(osm_id).c_str());
-    feature->SetField("error", error);
-
-    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
-        std::cerr << "Failed to create feature on layer 'error_lines'.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFeature::DestroyFeature(feature);
-}
-
-/***************************************************************/
-
-LayerRings::LayerRings(OGRDataSource* data_source, const char** options) :
-    Layer() {
-    m_layer = data_source->CreateLayer("rings", srs.out(), wkbPolygon, const_cast<char**>(options));
-    if (!m_layer) {
-        std::cerr << "Creating layer 'rings' failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_osm_id("osm_id", OFTString);
-    field_osm_id.SetWidth(10);
-    if (m_layer->CreateField(&field_osm_id) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'osm_id' on 'rings' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_nways("nways", OFTInteger);
-    field_nways.SetWidth(6);
-    if (m_layer->CreateField(&field_nways) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'nways' on 'rings' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_npoints("npoints", OFTInteger);
-    field_npoints.SetWidth(8);
-    if (m_layer->CreateField(&field_npoints) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'npoints' on 'rings' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_fixed("fixed", OFTInteger);
-    field_fixed.SetWidth(1);
-    if (m_layer->CreateField(&field_fixed) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'fixed' on 'rings' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_land("land", OFTInteger);
-    field_land.SetWidth(1);
-    if (m_layer->CreateField(&field_land) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'land' on 'rings' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFieldDefn field_valid("valid", OFTInteger);
-    field_valid.SetWidth(1);
-    if (m_layer->CreateField(&field_valid) != OGRERR_NONE ) {
-        std::cerr << "Creating field 'valid' on 'rings' layer failed.\n";
-        exit(return_code_fatal);
-    }
-
-    m_layer->StartTransaction();
-}
-
-void LayerRings::add(OGRPolygon* polygon, int osm_id, int nways, int npoints, bool fixed, LayerErrorPoints* layer_error_points) {
-    srs.transform(polygon);
-
-    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
-
-    feature->SetGeometryDirectly(polygon);
-    feature->SetField("osm_id", osm_id);
-    feature->SetField("nways", nways);
-    feature->SetField("npoints", npoints);
-    feature->SetField("fixed", fixed ? 0 : 1);
-
-    if (polygon->getExteriorRing()->isClockwise()) {
-        feature->SetField("land", 1);
-    } else {
-        feature->SetField("land", 0);
-    }
-
-    if (polygon->IsValid()) {
-        feature->SetField("valid", 1);
-    } else {
-        /*
-           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;
-        GEOSFree(r);
-        GEOSGeom_destroy(p);
-#else
-        GEOSContextHandle_t contextHandle = OGRGeometry::createGEOSContext();
-        std::string reason = GEOSisValidReason(polygon->exportToGEOS(contextHandle));
-        OGRGeometry::freeGEOSContext(contextHandle);
-#endif
-        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";
-        }
-        layer_error_points->add(point.release(), reason.c_str(), osm_id);
-
-        feature->SetField("valid", 0);
-    }
-
-    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
-        std::cerr << "Failed to create feature in layer 'rings'.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFeature::DestroyFeature(feature);
-}
-
-/***************************************************************/
-
-LayerPolygons::LayerPolygons(OGRDataSource* data_source, const char** options, const char* name) :
-    Layer(),
-    m_name(name) {
-    m_layer = data_source->CreateLayer(name, srs.out(), wkbPolygon, const_cast<char**>(options));
-    if (!m_layer) {
-        std::cerr << "Creating layer '" << name << "' failed.\n";
-        exit(return_code_fatal);
-    }
-
-    m_layer->StartTransaction();
-}
-
-void LayerPolygons::add(OGRPolygon* polygon) {
-    srs.transform(polygon);
-
-    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
-
-    feature->SetGeometryDirectly(polygon);
-
-    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
-        std::cerr << "Failed to create feature in layer '" << m_name << "'.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFeature::DestroyFeature(feature);
-}
-
-/***************************************************************/
-
-LayerLines::LayerLines(OGRDataSource* data_source, const char** options) :
-    Layer() {
-    m_layer = data_source->CreateLayer("lines", srs.out(), wkbLineString, const_cast<char**>(options));
-    if (!m_layer) {
-        std::cerr << "Creating layer 'lines' failed.\n";
-        exit(return_code_fatal);
-    }
-
-    m_layer->StartTransaction();
-}
-
-void LayerLines::add(OGRLineString* linestring) {
-    srs.transform(linestring);
-
-    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
-
-    feature->SetGeometryDirectly(linestring);
-
-    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
-        std::cerr << "Failed to create feature in layer 'lines'.\n";
-        exit(return_code_fatal);
-    }
-
-    OGRFeature::DestroyFeature(feature);
-}
-
diff --git a/src/output_layers.hpp b/src/output_layers.hpp
deleted file mode 100644
index 9c5b314..0000000
--- 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
diff --git a/src/osmcoastline.hpp b/src/return_codes.hpp
similarity index 94%
rename from src/osmcoastline.hpp
rename to src/return_codes.hpp
index 27abac2..6ae4cb1 100644
--- a/src/osmcoastline.hpp
+++ b/src/return_codes.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
diff --git a/src/srs.cpp b/src/srs.cpp
index 11d5d39..78a5809 100644
--- a/src/srs.cpp
+++ b/src/srs.cpp
@@ -1,6 +1,6 @@
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
diff --git a/src/srs.hpp b/src/srs.hpp
index ff4e530..5ce32b7 100644
--- a/src/srs.hpp
+++ b/src/srs.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
diff --git a/src/stats.hpp b/src/stats.hpp
index 052c9d6..9284a59 100644
--- a/src/stats.hpp
+++ b/src/stats.hpp
@@ -3,7 +3,7 @@
 
 /*
 
-  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+  Copyright 2012-2016 Jochen Topf <jochen at topf.org>.
 
   This file is part of OSMCoastline.
 
diff --git a/src/util.hpp b/src/util.hpp
new file mode 100644
index 0000000..c16b658
--- /dev/null
+++ b/src/util.hpp
@@ -0,0 +1,41 @@
+#ifndef UTIL_HPP
+#define UTIL_HPP
+
+/*
+
+  Copyright 2012-2016 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

-- 
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