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 <[email protected]> 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 <[email protected]>") @@ -36,6 +38,8 @@ set(AUTHOR "Jochen Topf <[email protected]>") # #----------------------------------------------------------------------------- +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 <[email protected]> + +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 <[email protected]>. +Copyright (C) 2012\-2016 Jochen Topf <[email protected]>. 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 <[email protected]>" + 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>\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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>\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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>\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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>\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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. - - 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 <[email protected]>. - - 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + Copyright 2012-2016 Jochen Topf <[email protected]>. 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 <[email protected]>. + + 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 _______________________________________________ Pkg-grass-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel

