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