[osmcoastline] 01/02: Imported Upstream version 0.0~20150306-1f2b90a

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Mar 6 17:10:27 UTC 2015


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

sebastic pushed a commit to branch master
in repository osmcoastline.

commit 085ba3a6ca0a00650d98ac56bbed6de137cdabc8
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Mar 6 17:05:25 2015 +0100

    Imported Upstream version 0.0~20150306-1f2b90a
---
 .gitignore                                    |    2 +
 .ycm_extra_conf.py                            |   41 +
 CMakeLists.txt                                |  217 +++
 COPYING                                       |  674 +++++++
 README.md                                     |  271 +++
 TODO                                          |   10 +
 cmake/FindOSMPBF.cmake                        |   50 +
 cmake/FindOsmium.cmake                        |  340 ++++
 coastline.map                                 |   24 +
 coastline_handlers.hpp                        |  108 ++
 coastline_polygons.cpp                        |  399 +++++
 coastline_polygons.hpp                        |  125 ++
 coastline_ring.cpp                            |  166 ++
 coastline_ring.hpp                            |  248 +++
 coastline_ring_collection.cpp                 |  423 +++++
 coastline_ring_collection.hpp                 |  133 ++
 coastline_sources.qgs                         |  329 ++++
 coastline_sqlite.qgs                          |  821 +++++++++
 doc/CMakeLists.txt                            |   35 +
 doc/Doxyfile.in                               | 2312 +++++++++++++++++++++++++
 doc/header.html                               |   56 +
 ogr_include.hpp                               |   42 +
 options.cpp                                   |  197 +++
 options.hpp                                   |  110 ++
 osmcoastline.cpp                              |  324 ++++
 osmcoastline.hpp                              |   33 +
 osmcoastline_filter.cpp                       |  142 ++
 osmcoastline_readmeta.sh                      |   85 +
 osmcoastline_ways.cpp                         |  165 ++
 output_database.cpp                           |  179 ++
 output_database.hpp                           |  105 ++
 output_layers.cpp                             |  326 ++++
 output_layers.hpp                             |  124 ++
 render_image.sh                               |   34 +
 runtest.sh.in                                 |    8 +
 simplify.sql                                  |   21 +
 simplify_and_split/README                     |   95 +
 simplify_and_split/create_water_polygons.sql  |   38 +
 simplify_and_split/setup_bbox_tiles.sql       |   27 +
 simplify_and_split/setup_tables.sql           |   55 +
 simplify_and_split/simplify_land_polygons.sql |   28 +
 simplify_and_split/split_land_polygons.sql    |   49 +
 simplify_and_split/split_tiles.sql            |   23 +
 srs.cpp                                       |   70 +
 srs.hpp                                       |   88 +
 stats.hpp                                     |   36 +
 taginfo.json                                  |   30 +
 testdata.osm                                  |  735 ++++++++
 verbose_output.hpp                            |   48 +
 49 files changed, 10001 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5013903
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.swp
+.ycm_extra_conf.pyc
diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py
new file mode 100644
index 0000000..f2f1e01
--- /dev/null
+++ b/.ycm_extra_conf.py
@@ -0,0 +1,41 @@
+#-----------------------------------------------------------------------------
+#
+#  Configuration for YouCompleteMe Vim plugin
+#
+#  http://valloric.github.io/YouCompleteMe/
+#
+#-----------------------------------------------------------------------------
+
+# some default flags
+# for more information install clang-3.2-doc package and
+# check UsersManual.html
+flags = [
+'-Werror',
+'-Wall',
+'-Wextra',
+'-pedantic',
+'-Wno-return-type',
+'-Wno-unused-parameter',
+'-Wno-unused-variable',
+
+'-std=c++11',
+
+# '-x' and 'c++' also required
+# use 'c' for C projects
+'-x',
+'c++',
+
+# libosmium include dirs
+'-I../libosmium/include',
+'-I/usr/include/gdal',
+
+]
+
+# youcompleteme is calling this function to get flags
+# You can also set database for flags. Check: JSONCompilationDatabase.html in
+# clang-3.2-doc package
+def FlagsForFile( filename ):
+  return {
+    'flags': flags,
+    'do_cache': True
+  }
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..1bdea83
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,217 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake Config
+#
+#  OSMCoastline
+#
+#-----------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+
+#-----------------------------------------------------------------------------
+#
+#  Project version
+#
+#-----------------------------------------------------------------------------
+
+project(osmcoastline)
+
+set(OSMCOASTLINE_VERSION_MAJOR 2)
+set(OSMCOASTLINE_VERSION_MINOR 0)
+set(OSMCOASTLINE_VERSION_PATCH 0)
+
+set(OSMCOASTLINE_VERSION
+    ${OSMCOASTLINE_VERSION_MAJOR}.${OSMCOASTLINE_VERSION_MINOR}.${OSMCOASTLINE_VERSION_PATCH})
+
+
+#-----------------------------------------------------------------------------
+#
+#  Find external dependencies
+#
+#-----------------------------------------------------------------------------
+
+find_package(Osmium COMPONENTS io gdal)
+include_directories(${OSMIUM_INCLUDE_DIRS})
+
+if(MSVC)
+    find_path(GETOPT_INCLUDE_DIR getopt.h)
+    find_library(GETOPT_LIBRARY NAMES wingetopt)
+    if(GETOPT_INCLUDE_DIR AND GETOPT_LIBRARY)
+        include_directories(${GETOPT_INCLUDE_DIR})
+        list(APPEND OSMIUM_LIBRARIES ${GETOPT_LIBRARY})
+    else()
+        set(GETOPT_MISSING 1)
+    endif()
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Decide which C++ version to use (Minimum/default: C++11).
+#
+#-----------------------------------------------------------------------------
+if(NOT MSVC)
+    if(NOT USE_CPP_VERSION)
+        set(USE_CPP_VERSION c++11)
+    endif()
+    message(STATUS "Use C++ version: ${USE_CPP_VERSION}")
+    # following only available from cmake 2.8.12:
+    #   add_compile_options(-std=${USE_CPP_VERSION})
+    # so using this instead:
+    add_definitions(-std=${USE_CPP_VERSION})
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Compiler and Linker flags
+#
+#-----------------------------------------------------------------------------
+if(MSVC)
+    set(USUAL_COMPILE_OPTIONS "/Ox")
+else()
+    set(USUAL_COMPILE_OPTIONS "-O3 -g")
+endif()
+
+if(WIN32)
+    add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32
+                    -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -D_WIN32_IE=0x0600)
+endif()
+
+set(CMAKE_CXX_FLAGS_DEV "${USUAL_COMPILE_OPTIONS}"
+    CACHE STRING "Flags used by the compiler during developer builds."
+    FORCE)
+
+set(CMAKE_EXE_LINKER_FLAGS_DEV ""
+    CACHE STRING "Flags used by the linker during developer builds."
+    FORCE)
+mark_as_advanced(
+    CMAKE_CXX_FLAGS_DEV
+    CMAKE_EXE_LINKER_FLAGS_DEV
+)
+
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${USUAL_COMPILE_OPTIONS}"
+    CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds."
+    FORCE)
+
+
+#-----------------------------------------------------------------------------
+#
+#  Build Type
+#
+#-----------------------------------------------------------------------------
+set(CMAKE_CONFIGURATION_TYPES "Debug Release RelWithDebInfo MinSizeRel Dev")
+
+# In 'Dev' mode: compile with very strict warnings and turn them into errors.
+if(CMAKE_BUILD_TYPE STREQUAL "Dev")
+    if(NOT MSVC)
+        add_definitions(-Werror -fno-omit-frame-pointer)
+    endif()
+    add_definitions(${OSMIUM_WARNING_OPTIONS})
+endif()
+
+# Force RelWithDebInfo build type if none was given
+if(CMAKE_BUILD_TYPE)
+    set(build_type ${CMAKE_BUILD_TYPE})
+else()
+    set(build_type "RelWithDebInfo")
+endif()
+
+set(CMAKE_BUILD_TYPE ${build_type}
+    CACHE STRING
+    "Choose the type of build, options are: ${CMAKE_CONFIGURATION_TYPES}."
+    FORCE)
+
+
+#-----------------------------------------------------------------------------
+#
+#  Optional "cppcheck" target that checks C++ code
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for cppcheck")
+find_program(CPPCHECK cppcheck)
+
+if(CPPCHECK)
+    message(STATUS "Looking for cppcheck - found")
+    set(CPPCHECK_OPTIONS --enable=all)
+
+    # cpp doesn't find system includes for some reason, suppress that report
+    set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem)
+
+    file(GLOB ALL_CODE *.cpp)
+
+    set(CPPCHECK_FILES ${ALL_CODE})
+
+    add_custom_target(cppcheck
+        ${CPPCHECK}
+        --std=c++11 ${CPPCHECK_OPTIONS}
+        ${CPPCHECK_FILES}
+    )
+else()
+    message(STATUS "Looking for cppcheck - not found")
+    message(STATUS "  Build target 'cppcheck' will not be available.")
+endif(CPPCHECK)
+
+
+#-----------------------------------------------------------------------------
+
+find_library(GEOS_C_LIBRARIES NAMES geos_c)
+
+add_definitions(${OSMIUM_WARNING_OPTIONS})
+
+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)
+target_link_libraries(osmcoastline ${OSMIUM_IO_LIBRARIES} ${GDAL_LIBRARIES} ${GEOS_C_LIBRARIES})
+
+add_executable(osmcoastline_filter osmcoastline_filter.cpp)
+target_link_libraries(osmcoastline_filter ${OSMIUM_IO_LIBRARIES})
+
+add_executable(osmcoastline_ways osmcoastline_ways.cpp osmcoastline.hpp)
+target_link_libraries(osmcoastline_ways ${OSMIUM_IO_LIBRARIES} ${GDAL_LIBRARIES})
+
+configure_file(
+    ${PROJECT_SOURCE_DIR}/runtest.sh.in
+    ${PROJECT_BINARY_DIR}/runtest.sh
+)
+
+configure_file(
+    ${PROJECT_SOURCE_DIR}/coastline_sqlite.qgs
+    ${PROJECT_BINARY_DIR}/coastline_sqlite.qgs
+)
+
+configure_file(
+    ${PROJECT_SOURCE_DIR}/coastline_sources.qgs
+    ${PROJECT_BINARY_DIR}/coastline_sources.qgs
+)
+
+
+#-----------------------------------------------------------------------------
+#
+#  Documentation
+#
+#-----------------------------------------------------------------------------
+
+add_subdirectory(doc)
+
+
+#-----------------------------------------------------------------------------
+#
+#  Packaging
+#
+#-----------------------------------------------------------------------------
+
+set(CPACK_PACKAGE_VERSION_MAJOR ${OSMCOASTLINE_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${OSMCOASTLINE_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${OSMCOASTLINE_VERSION_PATCH})
+
+if(WIN32)
+    set(CPACK_GENERATOR ZIP)
+else()
+    set(CPACK_GENERATOR TGZ)
+endif()
+
+include(CPack)
+
+
+#-----------------------------------------------------------------------------
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program 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.
+
+    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3584893
--- /dev/null
+++ b/README.md
@@ -0,0 +1,271 @@
+
+# OSMCoastline
+
+OSMCoastline extracts the coastline from an OSM planet file and assembles all
+the pieces into polygons for use in map renderers etc.
+
+http://wiki.openstreetmap.org/wiki/OSMCoastline
+
+https://github.com/osmcode/osmcoastline
+
+
+## Prerequisites
+
+### Libosmium
+
+    http://github.com/osmcode/libosmium
+    http://osmcode.org/libosmium
+
+### zlib (for PBF support)
+
+    http://www.zlib.net/
+    Debian/Ubuntu: zlib1g-dev
+
+### GDAL (for OGR support)
+
+    http://gdal.org/
+    Debian/Ubuntu: libgdal1-dev
+    (Must be built with Spatialite and GEOS support which is true for
+    Debian/Ubuntu packages. You need GDAL 1.7.0 or greater, consider using
+    https://wiki.ubuntu.com/UbuntuGIS when using Ubuntu to get newer
+    versions of GIS libraries.)
+
+### GEOS
+
+    http://trac.osgeo.org/geos/
+    Debian/Ubuntu: libgeos-dev
+
+### Sqlite/Spatialite
+
+    http://www.gaia-gis.it/gaia-sins/
+    Debian/Ubuntu: sqlite3
+
+
+## Building
+
+You'll need all the prerequisites including `libosmium` installed.
+
+OSMCoastline uses CMake for building:
+
+    mkdir build
+    cd build
+    cmake ..
+    make
+
+Call `make doc` to build the Doxygen API documentation which will be available
+in the `doc/html` directory.
+
+
+## Testing
+
+Run the script `runtest.sh` from the directory you built the program in. It
+will read the supplied `testdata.osm` and create output in the `testdata.db`
+spatialite database.
+
+It is normal for this program to create errors and warnings, because it is
+testing a rather broken input file. You will get messages such as "Closing
+ring between node -84 and node -74" and "Warning 1: Self-intersection
+at or near point 7.48488 53.8169". At the end it should print:
+
+    There were 35 warnings.
+    There were 1 errors.
+
+You can use the supplied `coastline_sqlite.qgs` QGIS project file to open the
+output with QGIS.
+
+Call `runtest.sh -v` to run the tests under Valgrind.
+
+
+## Running
+
+Note that you might want to run `osmcoastline_filter` first, see below under
+**Filtering**.
+
+Run: `osmcoastline -o DBFILE PLANET-FILE`
+
+For example: `osmcoastline -o coastline.db planet.osm.pbf`
+
+This will create a spatialite database named `DBFILE` and write several tables
+with the output into it.
+
+Use `--verbose` to see whats going on. Start with `--help` to see other
+options.
+
+
+## Output
+
+The output is a spatialite database with the following tables. All tables are
+always created but depending on the command line options only some of them
+might contain anything.
+
+* `error_lines` Lines that have errors (for instance not closed rings or
+  self-intersections).
+
+* `error_points` Problematic points such as intersections.
+
+* `rings` Coastline rings as linestrings. The table is not populated by default,
+  because this is only needed for finding errors in the coastline. Use the
+  command line option `--output-rings` to populate this table.
+
+* `land_polygons` Finished assembled land polygons. Depending on `--max-points`
+  option this will contain complete or split polygons. Only filled if the
+  option `--output-polygons=land` (thats the default) or `=both` has been given.
+
+* `water_polygons` Finished assembled water polygons. Only filled if option
+  `--output-polygons=water` or `=both` has been given.
+
+* `lines` Coastlines as linestrings. Depending on `--max-points` option this
+  will contain complete or split linestrings. Only filled if the option
+  `--output-lines` has been given.
+
+By default all output is in WGS84. You can use the option `--srs=3857` to
+create output in "Google Mercator". (Other projections are currently not
+supported.)
+
+OSMCoastline always creates only this one database. If you need shapefiles
+use ogr2ogr to convert the data:
+
+    ogr2ogr -f "ESRI Shapefile" land_polygons.shp coastline.db land_polygons
+
+By default geometry indexes are created for all tables. This makes the database
+larger, but faster to use. You can use the option `--no-index` to suppress
+this, for instance if you never use the data directly anyway but want to
+transform it into something else.
+
+Coastlines and polygons are never simplified, but contain the full detail.
+See `simplify.sql` for a way to simplify polygons. See the `simplify_and_split`
+directory for some more ways of doing this.
+
+The database tables `options` and `meta` contain the command line options
+used to create the database and some metadata. You can use the script
+`osmcoastline_readmeta.sh` to look at them.
+
+
+## Steps
+
+OSMCoastline runs in several steps, each can optionally create some output.
+In most cases you will only be interested in the end result but preliminary
+results are supplied for debugging or other special uses.
+
+**Step 1**: Filter out all nodes and ways tagged `natural=coastline` and all
+            nodes needed by those ways. (This can also be done with the
+            `osmcoastline_filter` program, see below)
+
+**Step 2**: Assemble all coastline ways into rings. Rings that are not closed
+            in the OSM data will be closed depending on the `--close-distance`
+            option.
+
+**Step 3**: Assemble polygons from the rings, possibly including holes for
+            water areas.
+
+**Step 4**: Split up large polygons into smaller ones. The options
+            `--max-points` and `--bbox-overlap` are used here.
+
+**Step 5**: Create water polygons as the "inverse" of the land polygons.
+
+The errors encountered in each step are written to the `error_points` and
+`error_lines` tables.
+
+
+## Options
+
+    -c, --close-distance=DISTANCE
+
+OSMCoastline assembles ways tagged `natural=coastline` into rings. Sometimes
+there is a gap in the coastline in the OSM data. OSMCoastline will close this
+gap if it is smaller than DISTANCE. Use 0 to disable this feature.
+
+    -b, --bbox-overlap=OVERLAP
+
+Polygons that are too large are split into two halves (recursively if need be).
+Where the polygons touch the OVERLAP is added, because two polygons just
+touching often lead to rendering problems. The value is given in the units used
+for the projection (for WGS84 (4326) this is in degrees, for Mercator (3857)
+this is in meters). If this is set too small you might get rendering artefacts
+where polygons touch. The larger you set this the larger the output polygons
+will be. The best values depend on the map scale or zoom level you are
+preparing the data for. Disable the overlap by setting it to 0. Default is
+0.0001 for WGS84 and 10 for Mercator.
+
+    -m, --max-points=NUM
+
+Set this to 0 to prevent splitting of large polygons and linestrings. If set to
+any other positive integer OSMCoastline will try to split polygons/linestrings
+to not have more than this many points. Depending on the overlap defined with
+-b and the shape of the polygons it is sometimes not possible to get the
+polygons small enough. OSMCoastline will warn you on stderr if this is the
+case. Default is 1000.
+
+    -s, --srs=EPSGCODE
+
+Set spatial reference system/projection. Use 4326 for WGS84 or 3857 for "Google
+Mercator". If you want to use the data for the usual tiled web maps, 3857 is
+probably right. For other uses, especially if you want to re-project to some
+other projection, 4326 is probably right. Other projections are curently not
+supported. Default is 4326.
+
+    -v, --verbose
+
+Gives you detailed information on what osmcoastline is doing, including timing.
+
+Run `osmcoastline --help` to see all options.
+
+
+## Return codes
+
+`osmcoastline` uses the following return codes:
+
+    0 - OK
+    1 - Warning
+    2 - Error
+    3 - Fatal error (output file could not be opened etc.)
+    4 - Error parsing command line arguments
+
+The difference between warnings and errors is somewhat muddy. Warnings are
+geometry problems that have either been fixed automatically or seem to be
+small. Errors are larger problems that couldn't be fixed. If there were errors
+you probably do not want to use the generated data but fix the OSM data first.
+If there were warnings the data might be okay, but there still could be data
+missing or geometry problems such as self-intersections in the coastline. But
+the classification of problems into warnings and errors is difficult, so to be
+on the safe side you might only want to use the data if there are no warnings
+and no errors at all.
+
+
+## Antarctica
+
+OSMCoastline has special code for the coastline of Antarctica. This is the only
+coastline that can remain open. The coastline starts somewhere around 180°
+East, 77° South and ends around 180° West and 77° South. OSMCoastline will find
+those open ends and connect them by adding several "nodes" forming a proper
+polygon. Depending on the output projection (EPSG:4326 or EPSG:3857) this
+polygon will either go to the South Pole or to the 85.0511° line.
+
+
+## Filtering
+
+The program `osmcoastline_filter` can be used to filter from an OSM planet file
+all nodes and ways needed for building the coastlines and writing them out in
+OSM format. This file will be a lot smaller (less than 1%) than the original
+planet file, but it contains everything needed to assemble the coastline
+polygons.
+
+If you are playing around or want to run `osmcoastline` several times with
+different parameters, run `osmcoastline_filter` once first and use its output
+as the input for `osmcoastline`.
+
+Run it as follows: `osmcoastline_filter -o OUTFILE.osm.pbf INFILE.osm.pbf`
+
+`osmcoastline_filter` can read PBF and XML files, but write only PBF files. PBF
+files are much smaller and faster to read and write.
+
+
+## License
+
+OSMCoastline is available under the GNU GPL version 3 or later.
+
+
+## Authors
+
+Jochen Topf (jochen at topf.org)
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..b2c743f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,10 @@
+
+OSMCoastline TODO
+=================
+
+* write out statistics to meta table
+* make fixing of direction optional?
+    * only when there are no warnings?
+* determine best defaults for bbox overlap, max-points and close distance
+* Magic number 100 in split_bbox?
+
diff --git a/cmake/FindOSMPBF.cmake b/cmake/FindOSMPBF.cmake
new file mode 100644
index 0000000..deeebd8
--- /dev/null
+++ b/cmake/FindOSMPBF.cmake
@@ -0,0 +1,50 @@
+#
+# Locate OSMPBF library
+#
+# This module defines
+#  OSMPBF_FOUND        - if false, do not try to link to OSMPBF
+#  OSMPBF_LIBRARIES    - full library path name
+#  OSMPBF_INCLUDE_DIRS - where to find OSMPBF.hpp
+#
+# Note that the expected include convention is
+#  #include <osmpbf/osmpbf.h>
+# and not
+#  #include <osmpbf.h>
+#
+
+find_path(OSMPBF_INCLUDE_DIR osmpbf/osmpbf.h
+    HINTS $ENV{OSMPBF_DIR}
+    PATH_SUFFIXES include
+    PATHS
+        ~/Library/Frameworks
+        /Library/Frameworks
+        /usr/local
+        /usr
+        /opt/local # DarwinPorts
+        /opt
+)
+
+find_library(OSMPBF_LIBRARY
+    NAMES osmpbf
+    HINTS $ENV{OSMPBF_DIR}
+    PATH_SUFFIXES lib64 lib
+    PATHS
+        ~/Library/Frameworks
+        /Library/Frameworks
+        /usr/local
+        /usr
+        /opt/local
+        /opt
+)
+
+# Handle the QUIETLY and REQUIRED arguments and set OSMPBF_FOUND to TRUE if
+# all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OSMPBF DEFAULT_MSG OSMPBF_LIBRARY OSMPBF_INCLUDE_DIR)
+
+# Copy the results to the output variables.
+if(OSMPBF_FOUND)
+    set(OSMPBF_INCLUDE_DIRS ${OSMPBF_INCLUDE_DIR})
+    set(OSMPBF_LIBRARIES ${OSMPBF_LIBRARY})
+endif()
+
diff --git a/cmake/FindOsmium.cmake b/cmake/FindOsmium.cmake
new file mode 100644
index 0000000..1de41a0
--- /dev/null
+++ b/cmake/FindOsmium.cmake
@@ -0,0 +1,340 @@
+#----------------------------------------------------------------------
+#
+#  FindOsmium.cmake
+#
+#  Find the Libosmium headers and, optionally, several components needed for
+#  different Libosmium functions.
+#
+#----------------------------------------------------------------------
+#
+#  Usage:
+#
+#    Copy this file somewhere into your project directory, where cmake can
+#    find it. Usually this will be a directory called "cmake" which you can
+#    add to the CMake module search path with the following line in your
+#    CMakeLists.txt:
+#
+#      list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+#
+#    Then add the following in your CMakeLists.txt:
+#
+#      find_package(Osmium REQUIRED COMPONENTS <XXX>)
+#      include_directories(${OSMIUM_INCLUDE_DIRS})
+#
+#    For the <XXX> substitute a space separated list of one or more of the
+#    following components:
+#
+#      pbf        - include libraries needed for PBF input and output
+#      xml        - include libraries needed for XML input and output
+#      io         - include libraries needed for any type of input/output
+#      geos       - include if you want to use any of the GEOS functions
+#      gdal       - include if you want to use any of the OGR functions
+#      proj       - include if you want to use any of the Proj.4 functions
+#      sparsehash - include if you use the sparsehash index
+#
+#    You can check for success with something like this:
+#
+#      if(NOT OSMIUM_FOUND)
+#          message(WARNING "Libosmium not found!\n")
+#      endif()
+#
+#----------------------------------------------------------------------
+#
+#  Variables:
+#
+#    OSMIUM_FOUND         - True if Osmium found.
+#    OSMIUM_INCLUDE_DIRS  - Where to find include files.
+#    OSMIUM_XML_LIBRARIES - Libraries needed for XML I/O.
+#    OSMIUM_PBF_LIBRARIES - Libraries needed for PBF I/O.
+#    OSMIUM_IO_LIBRARIES  - Libraries needed for XML or PBF I/O.
+#    OSMIUM_LIBRARIES     - All libraries Osmium uses somewhere.
+#
+#----------------------------------------------------------------------
+
+# Look for the header file.
+find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
+    PATH_SUFFIXES include
+    PATHS
+        ../libosmium
+        ../../libosmium
+        libosmium
+        ~/Library/Frameworks
+        /Library/Frameworks
+        /usr/local
+        /usr/
+        /opt/local # DarwinPorts
+        /opt
+)
+
+# 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)
+
+# Copy the results to the output variables.
+if(OSMIUM_FOUND)
+    set(OSMIUM_INCLUDE_DIRS ${OSMIUM_INCLUDE_DIR})
+else()
+    set(OSMIUM_INCLUDE_DIRS "")
+endif()
+
+if(Osmium_FIND_REQUIRED AND NOT OSMIUM_FOUND)
+    message(FATAL_ERROR "Can not find libosmium headers, please install them or configure the paths")
+endif()
+
+#----------------------------------------------------------------------
+#
+#  Check for optional components
+#
+#----------------------------------------------------------------------
+if(Osmium_FIND_COMPONENTS)
+    foreach(_component ${Osmium_FIND_COMPONENTS})
+        string(TOUPPER ${_component} _component_uppercase)
+        set(Osmium_USE_${_component_uppercase} TRUE)
+    endforeach()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'io' is an alias for 'pbf' and 'xml'
+if(Osmium_USE_IO)
+    set(Osmium_USE_PBF TRUE)
+    set(Osmium_USE_XML TRUE)
+endif()
+
+#----------------------------------------------------------------------
+# Component 'ogr' is an alias for 'gdal'
+if(Osmium_USE_OGR)
+    set(Osmium_USE_GDAL TRUE)
+endif()
+
+#----------------------------------------------------------------------
+# Component 'pbf'
+if(Osmium_USE_PBF)
+    find_package(OSMPBF)
+    find_package(Protobuf)
+    find_package(ZLIB)
+    find_package(Threads)
+
+    if(OSMPBF_FOUND AND PROTOBUF_FOUND AND ZLIB_FOUND AND Threads_FOUND)
+        list(APPEND OSMIUM_PBF_LIBRARIES
+            ${OSMPBF_LIBRARIES}
+            ${PROTOBUF_LITE_LIBRARY}
+            ${ZLIB_LIBRARIES}
+            ${CMAKE_THREAD_LIBS_INIT}
+        )
+        if(WIN32)
+            list(APPEND OSMIUM_PBF_LIBRARIES ws2_32)
+        endif()
+        list(APPEND OSMIUM_INCLUDE_DIRS
+            ${OSMPBF_INCLUDE_DIRS}
+            ${PROTOBUF_INCLUDE_DIR}
+            ${ZLIB_INCLUDE_DIR}
+        )
+    else()
+        set(_missing_libraries 1)
+        message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'xml'
+if(Osmium_USE_XML)
+    find_package(EXPAT)
+    find_package(BZip2)
+    find_package(ZLIB)
+    find_package(Threads)
+
+    if(EXPAT_FOUND AND BZIP2_FOUND AND ZLIB_FOUND AND Threads_FOUND)
+        list(APPEND OSMIUM_XML_LIBRARIES
+            ${EXPAT_LIBRARIES}
+            ${BZIP2_LIBRARIES}
+            ${ZLIB_LIBRARIES}
+            ${CMAKE_THREAD_LIBS_INIT}
+        )
+        list(APPEND OSMIUM_INCLUDE_DIRS
+            ${EXPAT_INCLUDE_DIR}
+            ${BZIP2_INCLUDE_DIR}
+            ${ZLIB_INCLUDE_DIR}
+        )
+    else()
+        set(_missing_libraries 1)
+        message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+list(APPEND OSMIUM_IO_LIBRARIES
+    ${OSMIUM_PBF_LIBRARIES}
+    ${OSMIUM_XML_LIBRARIES}
+)
+
+list(APPEND OSMIUM_LIBRARIES
+    ${OSMIUM_IO_LIBRARIES}
+)
+
+#----------------------------------------------------------------------
+# Component 'geos'
+if(Osmium_USE_GEOS)
+    find_path(GEOS_INCLUDE_DIR geos/geom.h)
+    find_library(GEOS_LIBRARY NAMES geos)
+
+    if(GEOS_INCLUDE_DIR AND GEOS_LIBRARY)
+        SET(GEOS_FOUND 1)
+        list(APPEND OSMIUM_LIBRARIES ${GEOS_LIBRARY})
+        list(APPEND OSMIUM_INCLUDE_DIRS ${GEOS_INCLUDE_DIR})
+    else()
+        set(_missing_libraries 1)
+        message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'gdal' (alias 'ogr')
+if(Osmium_USE_GDAL)
+    find_package(GDAL)
+
+    if(GDAL_FOUND)
+        list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES})
+        list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS})
+    else()
+        set(_missing_libraries 1)
+        message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'proj'
+if(Osmium_USE_PROJ)
+    find_path(PROJ_INCLUDE_DIR proj_api.h)
+    find_library(PROJ_LIBRARY NAMES proj)
+
+    if(PROJ_INCLUDE_DIR AND PROJ_LIBRARY)
+        set(PROJ_FOUND 1)
+        list(APPEND OSMIUM_LIBRARIES ${PROJ_LIBRARY})
+        list(APPEND OSMIUM_INCLUDE_DIRS ${PROJ_INCLUDE_DIR})
+    else()
+        set(_missing_libraries 1)
+        message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'sparsehash'
+if(Osmium_USE_SPARSEHASH)
+    find_path(SPARSEHASH_INCLUDE_DIR google/sparsetable)
+
+    if(SPARSEHASH_INCLUDE_DIR)
+        # Find size of sparsetable::size_type. This does not work on older
+        # CMake versions because they can do this check only in C, not in C++.
+        include(CheckTypeSize)
+        set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR})
+        set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable")
+        check_type_size("google::sparsetable<int>::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX)
+        set(CMAKE_EXTRA_INCLUDE_FILES)
+        set(CMAKE_REQUIRED_INCLUDES)
+
+        # Falling back to checking size_t if google::sparsetable<int>::size_type
+        # could not be checked.
+        if(SPARSETABLE_SIZE_TYPE STREQUAL "")
+            check_type_size("void*" VOID_PTR_SIZE)
+            set(SPARSETABLE_SIZE_TYPE ${VOID_PTR_SIZE})
+        endif()
+
+        # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise
+        # OSM object IDs will not fit.
+        if(SPARSETABLE_SIZE_TYPE GREATER 7)
+            set(SPARSEHASH_FOUND 1)
+            add_definitions(-DOSMIUM_WITH_SPARSEHASH=${SPARSEHASH_FOUND})
+            list(APPEND OSMIUM_INCLUDE_DIRS ${SPARSEHASH_INCLUDE_DIR})
+        else()
+            message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).")
+        endif()
+    else()
+        set(_missing_libraries 1)
+        message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+
+list(REMOVE_DUPLICATES OSMIUM_INCLUDE_DIRS)
+
+if(OSMIUM_XML_LIBRARIES)
+    list(REMOVE_DUPLICATES OSMIUM_XML_LIBRARIES)
+endif()
+
+if(OSMIUM_PBF_LIBRARIES)
+    list(REMOVE_DUPLICATES OSMIUM_PBF_LIBRARIES)
+endif()
+
+if(OSMIUM_IO_LIBRARIES)
+    list(REMOVE_DUPLICATES OSMIUM_IO_LIBRARIES)
+endif()
+
+if(OSMIUM_LIBRARIES)
+    list(REMOVE_DUPLICATES OSMIUM_LIBRARIES)
+endif()
+
+#----------------------------------------------------------------------
+#
+#  Check that all required libraries are available
+#
+#----------------------------------------------------------------------
+if(Osmium_FIND_REQUIRED AND _missing_libraries)
+    message(FATAL_ERROR "Required library or libraries missing. Aborting.")
+endif()
+
+#----------------------------------------------------------------------
+#
+#  Add compiler flags
+#
+#----------------------------------------------------------------------
+add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64)
+
+if(MSVC)
+    add_definitions(-wd4996)
+
+    # Disable warning C4068: "unknown pragma" because we want it to ignore
+    # pragmas for other compilers.
+    add_definitions(-wd4068)
+
+    # Disable warning C4715: "not all control paths return a value" because
+    # it generates too many false positives.
+    add_definitions(-wd4715)
+
+    # Disable warning C4351: new behavior: elements of array '...' will be
+    # default initialized. The new behaviour is correct and we don't support
+    # old compilers anyway.
+    add_definitions(-wd4351)
+
+    add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+if(APPLE)
+# following only available from cmake 2.8.12:
+#   add_compile_options(-stdlib=libc++)
+# so using this instead:
+    add_definitions(-stdlib=libc++)
+    set(LDFLAGS ${LDFLAGS} -stdlib=libc++)
+endif()
+
+#----------------------------------------------------------------------
+
+# This is a set of recommended warning options that can be added when compiling
+# libosmium code.
+if(MSVC)
+    set(OSMIUM_WARNING_OPTIONS "/W3 /wd4514" CACHE STRING "Recommended warning options for libosmium")
+else()
+    set(OSMIUM_WARNING_OPTIONS "-Wall -Wextra -pedantic -Wredundant-decls -Wdisabled-optimization -Wctor-dtor-privacy -Wnon-virtual-dtor -Woverloaded-virtual -Wsign-promo -Wold-style-cast -Wno-return-type" CACHE STRING "Recommended warning options for libosmium")
+endif()
+
+set(OSMIUM_DRACONIC_CLANG_OPTIONS "-Wdocumentation -Wunused-exception-parameter -Wmissing-declarations -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-unused-macros -Wno-exit-time-destructors -Wno-global-constructors -Wno-padded -Wno-switch-enum -Wno-missing-prototypes -Wno-weak-vtables -Wno-cast-align -Wno-float-equal")
+
+if(Osmium_DEBUG)
+    message(STATUS "OSMIUM_XML_LIBRARIES=" ${OSMIUM_XML_LIBRARIES})
+    message(STATUS "OSMIUM_PBF_LIBRARIES=" ${OSMIUM_PBF_LIBRARIES})
+    message(STATUS "OSMIUM_IO_LIBRARIES=" ${OSMIUM_IO_LIBRARIES})
+    message(STATUS "OSMIUM_LIBRARIES=" ${OSMIUM_LIBRARIES})
+    message(STATUS "OSMIUM_INCLUDE_DIRS=" ${OSMIUM_INCLUDE_DIRS})
+endif()
+
diff --git a/coastline.map b/coastline.map
new file mode 100644
index 0000000..e9b91f6
--- /dev/null
+++ b/coastline.map
@@ -0,0 +1,24 @@
+#
+#  Mapserver configuration
+#
+#  For rendering using this file see render_image.sh.
+#
+MAP
+    NAME coastline
+    IMAGECOLOR 255 255 255
+
+    LAYER
+        NAME polygons
+        TYPE POLYGON
+        STATUS ON
+        CONNECTIONTYPE OGR
+        CONNECTION "coastline-mapserver.db"
+        DATA "land_polygons"
+        CLASS
+            STYLE
+                COLOR 0 0 0
+            END
+        END
+    END
+
+END
diff --git a/coastline_handlers.hpp b/coastline_handlers.hpp
new file mode 100644
index 0000000..f6a9d24
--- /dev/null
+++ b/coastline_handlers.hpp
@@ -0,0 +1,108 @@
+#ifndef COASTLINE_HANDLERS_HPP
+#define COASTLINE_HANDLERS_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <osmium/handler.hpp>
+#include <osmium/geom/ogr.hpp>
+
+#include "coastline_ring_collection.hpp"
+#include "output_database.hpp"
+
+/**
+ * Osmium handler for the first pass over the input file in which
+ * all ways tagged with 'natural=coastline' are read and CoastlineRings
+ * are created.
+ */
+class CoastlineHandlerPass1 : public osmium::handler::Handler {
+
+    CoastlineRingCollection& m_coastline_rings;
+
+public:
+
+    CoastlineHandlerPass1(CoastlineRingCollection& coastline_rings) :
+        m_coastline_rings(coastline_rings)
+    {
+    }
+
+    void way(const osmium::Way& way) {
+        // We are only interested in ways tagged with natural=coastline.
+        const char* natural = way.tags().get_value_by_key("natural");
+        if (natural && !strcmp(natural, "coastline")) {
+            const char* bogus = way.tags().get_value_by_key("coastline");
+            if (bogus && !strcmp(bogus, "bogus")) {
+                return; // ignore bogus coastline in Antarctica
+            }
+            m_coastline_rings.add_way(way);
+        }
+    }
+
+};
+
+/**
+ * Osmium handler for the second pass over the input file in which
+ * node coordinates are added to the CoastlineRings.
+ */
+class CoastlineHandlerPass2 : public osmium::handler::Handler {
+
+    CoastlineRingCollection& m_coastline_rings;
+
+    /**
+     * Multimap for a mapping from node ID to all places where the
+     * position of this node should be written to. Those places
+     * are in the CoastlineRings created from the ways. This map
+     * is set up first thing when the handler is instantiated and
+     * thereafter used for each node coming in.
+     */
+    posmap_type m_posmap;
+    OutputDatabase& m_output;
+    osmium::geom::OGRFactory<> m_factory;
+
+public:
+
+    CoastlineHandlerPass2(CoastlineRingCollection& coastline_rings, OutputDatabase& output) :
+        m_coastline_rings(coastline_rings),
+        m_posmap(),
+        m_output(output)
+    {
+        m_coastline_rings.setup_positions(m_posmap);
+    }
+
+    void node(const osmium::Node& node) {
+        const char* natural = node.tags().get_value_by_key("natural");
+        if (natural && !strcmp(natural, "coastline")) {
+            try {
+                m_output.add_error_point(m_factory.create_point(node), "tagged_node", node.id());
+            } catch (osmium::geometry_error&) {
+                std::cerr << "Ignoring illegal geometry for node " << node.id() << ".\n";
+            }
+        }
+
+        std::pair<posmap_type::iterator, posmap_type::iterator> ret = m_posmap.equal_range(node.id());
+        for (auto it=ret.first; it != ret.second; ++it) {
+            *(it->second) = node.location();
+        }
+    }
+
+};
+
+#endif // COASTLINE_HANDLERS_HPP
diff --git a/coastline_polygons.cpp b/coastline_polygons.cpp
new file mode 100644
index 0000000..8f472a7
--- /dev/null
+++ b/coastline_polygons.cpp
@@ -0,0 +1,399 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include <vector>
+
+#include <ogr_geometry.h>
+
+#include "coastline_polygons.hpp"
+#include "output_database.hpp"
+#include "osmcoastline.hpp"
+#include "srs.hpp"
+
+extern SRS srs;
+extern bool debug;
+
+std::unique_ptr<OGRPolygon> CoastlinePolygons::create_rectangular_polygon(double x1, double y1, double x2, double y2, double expand) const {
+    OGREnvelope e;
+
+    e.MinX = x1 - expand;
+    e.MaxX = x2 + expand;
+    e.MinY = y1 - expand;
+    e.MaxY = y2 + expand;
+
+    // make sure we are inside the bounds for the output SRS
+    e.Intersect(srs.max_extent());
+
+    std::unique_ptr<OGRLinearRing> ring { new OGRLinearRing() };
+    ring->addPoint(e.MinX, e.MinY);
+    ring->addPoint(e.MinX, e.MaxY);
+    ring->addPoint(e.MaxX, e.MaxY);
+    ring->addPoint(e.MaxX, e.MinY);
+    ring->closeRings();
+
+    std::unique_ptr<OGRPolygon> polygon { new OGRPolygon() };
+    polygon->addRingDirectly(ring.release());
+    polygon->assignSpatialReference(srs.out());
+
+    return polygon;
+}
+
+unsigned int CoastlinePolygons::fix_direction() {
+    unsigned int warnings = 0;
+
+    for (const auto& polygon : m_polygons) {
+        OGRLinearRing* er = polygon->getExteriorRing();
+        if (!er->isClockwise()) {
+            er->reverseWindingOrder();
+            // Workaround for bug in OGR: reverseWindingOrder sets dimensions to 3
+            er->setCoordinateDimension(2);
+            for (int i=0; i < polygon->getNumInteriorRings(); ++i) {
+                polygon->getInteriorRing(i)->reverseWindingOrder();
+                // 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");
+            warnings++;
+        }
+    }
+
+    return warnings;
+}
+
+void CoastlinePolygons::transform() {
+    for (const auto& polygon : m_polygons) {
+        srs.transform(polygon);
+    }
+}
+
+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);
+    } else { // wkbMultiPolygon
+        const auto mp = static_cast<OGRMultiPolygon*>(geom.get());
+        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);
+        }
+    }
+}
+
+void CoastlinePolygons::split_polygon(OGRPolygon* polygon, int level) {
+    if (level > m_max_split_depth) {
+        m_max_split_depth = level;
+    }
+
+    int num_points = polygon->getExteriorRing()->getNumPoints();
+    if (num_points <= m_max_points_in_polygon) {
+        // do not split the polygon if it is small enough
+        m_polygons.push_back(std::move(polygon));
+    } else {
+        OGREnvelope envelope;
+        polygon->getEnvelope(&envelope);
+        if (debug) {
+            std::cerr << "DEBUG: split_polygon(): depth="
+                      << level
+                      << " envelope=("
+                      << envelope.MinX << ", " << envelope.MinY
+                      << "),("
+                      << envelope.MaxX << ", " << envelope.MaxY
+                      << ") num_points="
+                      << num_points
+                      << "\n";
+        }
+
+        // These polygons will contain the bounding box of each half of the "polygon" polygon.
+        std::unique_ptr<OGRPolygon> b1;
+        std::unique_ptr<OGRPolygon> b2;
+
+        if (envelope.MaxX - envelope.MinX < envelope.MaxY-envelope.MinY) {
+            if (m_expand >= (envelope.MaxY - envelope.MinY) / 4) {
+                std::cerr << "Not splitting polygon with " << num_points << " points on outer ring. It would not get smaller because --bbox-overlap/-b is set to high.\n";
+                m_polygons.push_back(std::move(polygon));
+                return;
+            }
+
+            // split vertically
+            double MidY = (envelope.MaxY+envelope.MinY) / 2;
+
+            b1 = create_rectangular_polygon(envelope.MinX, envelope.MinY, envelope.MaxX, MidY, m_expand);
+            b2 = create_rectangular_polygon(envelope.MinX, MidY, envelope.MaxX, envelope.MaxY, m_expand);
+        } else {
+            if (m_expand >= (envelope.MaxX - envelope.MinX) / 4) {
+                std::cerr << "Not splitting polygon with " << num_points << " points on outer ring. It would not get smaller because --bbox-overlap/-b is set to high.\n";
+                m_polygons.push_back(std::move(polygon));
+                return;
+            }
+
+            // split horizontally
+            double MidX = (envelope.MaxX+envelope.MinX) / 2;
+
+            b1 = create_rectangular_polygon(envelope.MinX, envelope.MinY, MidX, envelope.MaxY, m_expand);
+            b2 = create_rectangular_polygon(MidX, envelope.MinY, envelope.MaxX, envelope.MaxY, m_expand);
+        }
+
+        // Use intersection with bbox polygons to split polygon into two halfes
+        std::unique_ptr<OGRGeometry> geom1 { polygon->Intersection(b1.get()) };
+        std::unique_ptr<OGRGeometry> geom2 { polygon->Intersection(b2.get()) };
+
+        if (geom1 && (geom1->getGeometryType() == wkbPolygon || geom1->getGeometryType() == wkbMultiPolygon) &&
+            geom2 && (geom2->getGeometryType() == wkbPolygon || geom2->getGeometryType() == wkbMultiPolygon)) {
+            // split was successful, go on recursively
+            split_geometry(std::move(geom1), level+1);
+            split_geometry(std::move(geom2), level+1);
+        } else {
+            // split was not successful, output some debugging info and keep polygon before split
+            std::cerr << "Polygon split at depth " << level << " was not successful. Keeping un-split polygon.\n";
+            m_polygons.push_back(std::move(polygon));
+            if (debug) {
+                std::cerr << "DEBUG geom1=" << geom1.get() << " geom2=" << geom2.get() << "\n";
+                if (geom1) {
+                    std::cerr << "DEBUG geom1 type=" << geom1->getGeometryName() << "\n";
+                    if (geom1->getGeometryType() == wkbGeometryCollection) {
+                        std::cerr << "DEBUG   numGeometries=" << static_cast<OGRGeometryCollection*>(geom1.get())->getNumGeometries() << "\n";
+                    }
+                }
+                if (geom2) {
+                    std::cerr << "DEBUG geom2 type=" << geom2->getGeometryName() << "\n";
+                    if (geom2->getGeometryType() == wkbGeometryCollection) {
+                        std::cerr << "DEBUG   numGeometries=" << static_cast<OGRGeometryCollection*>(geom2.get())->getNumGeometries() << "\n";
+                    }
+                }
+            }
+        }
+    }
+}
+
+void CoastlinePolygons::split() {
+    polygon_vector_type v;
+    std::swap(v, m_polygons);
+    m_polygons.reserve(v.size());
+    for (auto& polygon : v) {
+        split_polygon(polygon, 0);
+    }
+}
+
+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()));
+        }
+    } else {
+        for (auto& polygon : m_polygons) {
+            m_output.add_land_polygon(polygon);
+        }
+    }
+}
+
+bool CoastlinePolygons::add_segment_to_line(OGRLineString* line, OGRPoint* point1, OGRPoint* point2) {
+    // 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) {
+            std::cerr << "Suppressing segment (" << point1->getX() << " " << point1->getY() << ", " << point2->getX() << " " << point2->getY() << ") near southern edge of map.\n";
+        }
+        return false;
+    }
+
+    // segments along antimeridian are not added to line output
+    if ((point1->getX() > srs.max_x() && point2->getX() > srs.max_x()) ||
+        (point1->getX() < srs.min_x() && point2->getX() < srs.min_x())) {
+        if (debug) {
+            std::cerr << "Suppressing segment (" << point1->getX() << " " << point1->getY() << ", " << point2->getX() << " " << point2->getY() << ") near antimeridian.\n";
+        }
+        return false;
+    }
+
+    if (line->getNumPoints() == 0) {
+        line->addPoint(point1);
+    }
+    line->addPoint(point2);
+    return true;
+}
+
+// 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) {
+    int num = ring->getNumPoints();
+    assert(num > 2);
+
+    std::unique_ptr<OGRPoint> point1 { new OGRPoint };
+    std::unique_ptr<OGRPoint> point2 { new OGRPoint };
+    std::unique_ptr<OGRLineString> line { new OGRLineString };
+
+    ring->getPoint(0, point1.get());
+    for (int i=1; i < num; ++i) {
+        ring->getPoint(i, point2.get());
+
+        bool added = add_segment_to_line(line.get(), point1.get(), point2.get());
+
+        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));
+            }
+        }
+
+        point1->setX(point2->getX());
+        point1->setY(point2->getY());
+    }
+
+    if (line->getNumPoints() >= 2) {
+        line->setCoordinateDimension(2);
+        line->assignSpatialReference(ring->getSpatialReference());
+        m_output.add_line(std::move(line));
+    }
+}
+
+void CoastlinePolygons::output_lines(int max_points) {
+    for (OGRPolygon* 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));
+        }
+    }
+}
+
+void CoastlinePolygons::split_bbox(OGREnvelope e, polygon_vector_type&& v) {
+//    std::cerr << "envelope = (" << e.MinX << ", " << e.MinY << "), (" << e.MaxX << ", " << e.MaxY << ") v.size()=" << v.size() << "\n";
+    if (v.size() < 100) {
+        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 some reason there is sometimes no srs on the geometries, so we add them on
+                diff->assignSpatialReference(srs.out());
+                geom.reset(diff);
+            }
+            if (geom) {
+                switch (geom->getGeometryType()) {
+                    case wkbPolygon:
+                        m_output.add_water_polygon(static_cast<OGRPolygon*>(geom.release()));
+                        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);
+                        }
+                        break;
+                    case wkbGeometryCollection:
+                        // XXX
+                        break;
+                    default:
+                        std::cerr << "IGNORING envelope = (" << e.MinX << ", " << e.MinY << "), (" << e.MaxX << ", " << e.MaxY << ") type=" << geom->getGeometryName() << "\n";
+                        // ignore XXX
+                        break;
+                }
+            }
+        } catch(...) {
+            std::cerr << "ignoring exception\n";
+        }
+    } else {
+
+        OGREnvelope e1;
+        OGREnvelope e2;
+
+        if (e.MaxX - e.MinX < e.MaxY-e.MinY) {
+            // split vertically
+            double MidY = (e.MaxY+e.MinY) / 2;
+
+            e1.MinX = e.MinX;
+            e1.MinY = e.MinY;
+            e1.MaxX = e.MaxX;
+            e1.MaxY = MidY;
+
+            e2.MinX = e.MinX;
+            e2.MinY = MidY;
+            e2.MaxX = e.MaxX;
+            e2.MaxY = e.MaxY;
+
+        } else {
+            // split horizontally
+            double MidX = (e.MaxX+e.MinX) / 2;
+
+            e1.MinX = e.MinX;
+            e1.MinY = e.MinY;
+            e1.MaxX = MidX;
+            e1.MaxY = e.MaxY;
+
+            e2.MinX = MidX;
+            e2.MinY = e.MinY;
+            e2.MaxX = e.MaxX;
+            e2.MaxY = e.MaxY;
+
+        }
+
+        polygon_vector_type v1;
+        polygon_vector_type v2;
+        for (OGRPolygon* 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);
+            }
+        }
+        split_bbox(e1, std::move(v1));
+        split_bbox(e2, std::move(v2));
+    }
+}
+
+
+unsigned int CoastlinePolygons::output_water_polygons() {
+    unsigned int warnings = 0;
+    polygon_vector_type v;
+    for (OGRPolygon* polygon : m_polygons) {
+        if (polygon->IsValid()) {
+            v.push_back(polygon);
+        } else {
+            std::cerr << "Invalid polygon, trying buffer(0).\n";
+            ++warnings;
+            OGRGeometry* buffered_polygon = polygon->Buffer(0);
+            if (buffered_polygon && buffered_polygon->getGeometryType() == wkbPolygon) {
+                v.emplace_back(static_cast<OGRPolygon*>(buffered_polygon));
+            } else {
+                std::cerr << "Buffer(0) failed, ignoring this polygon. Output data might be invalid!\n";
+            }
+        }
+    }
+    split_bbox(srs.max_extent(), std::move(v));
+    return warnings;
+}
+
diff --git a/coastline_polygons.hpp b/coastline_polygons.hpp
new file mode 100644
index 0000000..8b39b39
--- /dev/null
+++ b/coastline_polygons.hpp
@@ -0,0 +1,125 @@
+#ifndef COASTLINE_POLYGONS_HPP
+#define COASTLINE_POLYGONS_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <memory>
+#include <vector>
+
+class OGRGeometry;
+class OGRLinearRing;
+class OGRLineString;
+class OGRPoint;
+class OGRPolygon;
+class OGRMultiPolygon;
+class OGREnvelope;
+class OutputDatabase;
+
+typedef std::vector<OGRPolygon*> polygon_vector_type;
+
+/**
+ * A collection of land polygons created out of coastlines.
+ * Contains operations for SRS transformation, splitting up of large polygons
+ * and converting to water polygons.
+ */
+class CoastlinePolygons {
+
+    /// Output database
+    OutputDatabase& m_output;
+
+    /**
+     * When splitting polygons we want them to overlap slightly to avoid
+     * rendering artefacts. This is the amount each geometry is expanded
+     * in each direction.
+     */
+    double m_expand;
+
+    /**
+     * When splitting polygons they are split until they have less than
+     * this amount of points in them.
+     */
+    int m_max_points_in_polygon;
+
+    /**
+     * Vector of polygons we want to operate on. This is initialized in
+     * the constructor from the polygons created from coastline rings.
+     * After that the different methods on this class will convert the
+     * polygons and always leave the result in this vector again.
+     */
+    polygon_vector_type m_polygons;
+
+    /**
+     * Max depth after recursive splitting.
+     */
+    int m_max_split_depth;
+
+    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_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);
+
+public:
+
+    CoastlinePolygons(polygon_vector_type&& polygons, OutputDatabase& output, double expand, unsigned int max_points_in_polygon) :
+        m_output(output),
+        m_expand(expand),
+        m_max_points_in_polygon(max_points_in_polygon),
+        m_polygons(std::move(polygons)),
+        m_max_split_depth(0) {
+    }
+
+    /// Number of polygons
+    int num_polygons() const { return m_polygons.size(); }
+
+    polygon_vector_type::const_iterator begin() const {
+        return m_polygons.begin();
+    }
+
+    polygon_vector_type::const_iterator end() const {
+        return m_polygons.end();
+    }
+
+    /// Turn polygons with wrong winding order around.
+    unsigned int fix_direction();
+
+    /// Transform all polygons to output SRS.
+    void transform();
+
+    /// Split up all polygons.
+    void split();
+
+    /// Write all land polygons to the output database.
+    void output_land_polygons(bool make_copy);
+
+    /// Write all water polygons to the output database.
+    unsigned int output_water_polygons();
+
+    /// Write all coastlines to the output database (as lines).
+    void output_lines(int max_points);
+
+};
+
+#endif // COASTLINE_POLYGONS_HPP
diff --git a/coastline_ring.cpp b/coastline_ring.cpp
new file mode 100644
index 0000000..8a078a1
--- /dev/null
+++ b/coastline_ring.cpp
@@ -0,0 +1,166 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <iostream>
+
+#include <osmium/geom/ogr.hpp>
+
+#include "coastline_ring.hpp"
+
+void CoastlineRing::setup_positions(posmap_type& posmap) {
+    for (auto& wn : m_way_node_list) {
+        posmap.insert(std::make_pair(wn.ref(), &(wn.location())));
+    }
+}
+
+unsigned int CoastlineRing::check_positions(bool output_missing) {
+    unsigned int missing_positions = 0;
+
+    for (const auto& wn : m_way_node_list) {
+        if (!wn.location()) {
+            ++missing_positions;
+            if (output_missing) {
+                std::cerr << "Missing position of node " << wn.ref() << "\n";
+            }
+        }
+    }
+
+    return missing_positions;
+}
+
+void CoastlineRing::add_at_front(const osmium::Way& way) {
+    assert(first_node_id() == way.nodes().back().ref());
+    m_way_node_list.insert(m_way_node_list.begin(), way.nodes().begin(), way.nodes().end()-1);
+
+    update_ring_id(way.id());
+    m_nways++;
+}
+
+void CoastlineRing::add_at_end(const osmium::Way& way) {
+    assert(last_node_id() == way.nodes().front().ref());
+    m_way_node_list.insert(m_way_node_list.end(), way.nodes().begin()+1, way.nodes().end());
+
+    update_ring_id(way.id());
+    m_nways++;
+}
+
+void CoastlineRing::join(const CoastlineRing& other) {
+    assert(last_node_id() == other.first_node_id());
+    m_way_node_list.insert(m_way_node_list.end(), other.m_way_node_list.begin()+1, other.m_way_node_list.end());
+
+    update_ring_id(other.ring_id());
+    m_nways += other.m_nways;
+}
+
+void CoastlineRing::join_over_gap(const CoastlineRing& other) {
+    if (last_position() != other.first_position()) {
+        m_way_node_list.push_back(other.m_way_node_list.front());
+    }
+
+    m_way_node_list.insert(m_way_node_list.end(), other.m_way_node_list.begin()+1, other.m_way_node_list.end());
+
+    update_ring_id(other.ring_id());
+    m_nways += other.m_nways;
+    m_fixed = true;
+}
+
+void CoastlineRing::close_ring() {
+    if (first_position() != last_position()) {
+        m_way_node_list.push_back(m_way_node_list.front());
+    }
+    m_fixed = true;
+}
+
+void CoastlineRing::close_antarctica_ring(int epsg) {
+    double min = epsg == 4326 ? -90.0 : -85.0511;
+
+    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 lon = -180; lon < 180; ++lon) {
+        m_way_node_list.emplace_back(0, osmium::Location(static_cast<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)));
+    }
+
+    m_way_node_list.push_back(m_way_node_list.front());
+    m_fixed = true;
+}
+
+std::unique_ptr<OGRPolygon> CoastlineRing::ogr_polygon(osmium::geom::OGRFactory<>& geom_factory, bool reverse) const {
+    geom_factory.polygon_start();
+    size_t num_points = 0;
+    if (reverse) {
+        num_points = geom_factory.fill_polygon(m_way_node_list.crbegin(), m_way_node_list.crend());
+    } else {
+        num_points = geom_factory.fill_polygon(m_way_node_list.cbegin(), m_way_node_list.cend());
+    }
+    return geom_factory.polygon_finish(num_points);
+}
+
+std::unique_ptr<OGRLineString> CoastlineRing::ogr_linestring(osmium::geom::OGRFactory<>& geom_factory, bool reverse) const {
+    geom_factory.linestring_start();
+    size_t num_points = 0;
+    if (reverse) {
+        num_points = geom_factory.fill_linestring(m_way_node_list.crbegin(), m_way_node_list.crend());
+    } else {
+        num_points = geom_factory.fill_linestring(m_way_node_list.cbegin(), m_way_node_list.cend());
+    }
+    return geom_factory.linestring_finish(num_points);
+}
+
+std::unique_ptr<OGRPoint> CoastlineRing::ogr_first_point() const {
+    const osmium::NodeRef& node_ref = m_way_node_list.front();
+    return std::unique_ptr<OGRPoint>(new OGRPoint(node_ref.lon(), node_ref.lat()));
+}
+
+std::unique_ptr<OGRPoint> CoastlineRing::ogr_last_point() const {
+    const osmium::NodeRef& node_ref = m_way_node_list.back();
+    return std::unique_ptr<OGRPoint>(new OGRPoint(node_ref.lon(), node_ref.lat()));
+}
+
+// Pythagoras doesn't work on a round earth but that is ok here, we only need a
+// rough measure anyway
+double CoastlineRing::distance_to_start_position(osmium::Location pos) const {
+    osmium::Location p = m_way_node_list.front().location();
+    return (pos.lon() - p.lon()) * (pos.lon() - p.lon()) + (pos.lat() - p.lat()) * (pos.lat() - p.lat());
+}
+
+void CoastlineRing::add_segments_to_vector(std::vector<osmium::UndirectedSegment>& segments) const {
+    if (m_way_node_list.size() > 1) {
+        for (auto it = m_way_node_list.begin(); it != m_way_node_list.end()-1; ++it) {
+            segments.emplace_back(it->location(), (it+1)->location());
+        }
+    }
+}
+
+std::ostream& operator<<(std::ostream& out, CoastlineRing& cp) {
+    out << "CoastlineRing(ring_id=" << cp.ring_id() << ", nways=" << cp.nways() << ", npoints=" << cp.npoints() << ", first_node_id=" << cp.first_node_id() << ", last_node_id=" << cp.last_node_id();
+    if (cp.is_closed()) {
+        out << " [CLOSED]";
+    }
+    out << ")";
+    return out;
+}
+
diff --git a/coastline_ring.hpp b/coastline_ring.hpp
new file mode 100644
index 0000000..80f3c29
--- /dev/null
+++ b/coastline_ring.hpp
@@ -0,0 +1,248 @@
+#ifndef COASTLINE_RING_HPP
+#define COASTLINE_RING_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <map>
+#include <memory>
+
+#include <osmium/geom/ogr.hpp>
+#include <osmium/osm/undirected_segment.hpp>
+#include <osmium/osm/way.hpp>
+
+class OGRPoint;
+class OGRLineString;
+class OGRPolygon;
+
+typedef std::multimap<osmium::object_id_type, osmium::Location*> posmap_type;
+
+/**
+ * The CoastlineRing class models a (possibly unfinished) ring of
+ * coastline, ie. a closed list of points.
+ *
+ * CoastlineRing objects are created from a way. If the way is
+ * already closed we are done. If not, more ways will be added
+ * later until the ring is closed.
+ *
+ * The CoastlineRing keeps track of all the node IDs needed for
+ * the ring.
+ *
+ * To get a unique ID for the coastline ring, the minimum way
+ * ID is also kept.
+ *
+ * By definition coastlines in OSM are tagged as natural=coastline
+ * and the land is always to the *left* of the way, the water to
+ * the right. So a ring around an island is going counter-clockwise.
+ * In normal GIS use, outer rings of polygons are often expected
+ * to be clockwise, and inner rings are count-clockwise. So, if we
+ * are describing land polygons, the OSM convention is just the
+ * opposite of the GIS convention. Because of this the methods
+ * on CoastlineRing that create OGR geometries will actually turn
+ * the rings around.
+ */
+class CoastlineRing {
+
+    std::vector<osmium::NodeRef> m_way_node_list;
+
+    /**
+     * Smallest ID of all the ways making up the ring. Can be used as somewhat
+     * stable unique ID for the ring.
+     */
+    osmium::object_id_type m_ring_id;
+
+    /**
+     * The number of ways making up this ring. This is not actually needed for
+     * anything, but kept to create statistics.
+     */
+    unsigned int m_nways;
+
+    /// Ring was fixed because of missing/wrong OSM data.
+    bool m_fixed;
+
+    /// Is this an outer ring?
+    bool m_outer;
+
+public:
+
+    /**
+     * Create CoastlineRing from a way.
+     */
+    CoastlineRing(const osmium::Way& way) :
+        m_way_node_list(),
+        m_ring_id(way.id()),
+        m_nways(1),
+        m_fixed(false),
+        m_outer(false)
+    {
+        m_way_node_list.reserve(way.is_closed() ? way.nodes().size() : 1000);
+        m_way_node_list.insert(m_way_node_list.begin(), way.nodes().begin(), way.nodes().end());
+    }
+
+    bool is_outer() const {
+        return m_outer;
+    }
+
+    void set_outer() {
+        m_outer = true;
+    }
+
+    /// ID of first node in the ring.
+    osmium::object_id_type first_node_id() const { return m_way_node_list.front().ref(); }
+
+    /// ID of last node in the ring.
+    osmium::object_id_type last_node_id() const { return m_way_node_list.back().ref(); }
+
+    /// Position of the first node in the ring.
+    osmium::Location first_position() const { return m_way_node_list.front().location(); }
+
+    /// Position of the last node in the ring.
+    osmium::Location last_position() const { return m_way_node_list.back().location(); }
+
+    /// Return ID of this ring (defined as smallest ID of the ways making up the ring).
+    osmium::object_id_type ring_id() const { return m_ring_id; }
+
+    /**
+     * Set ring ID. The ring will only get the new ID if it is smaller than the
+     * old one.
+     */
+    void update_ring_id(osmium::object_id_type new_id) {
+        if (new_id < m_ring_id) {
+            m_ring_id = new_id;
+        }
+    }
+
+    /// Returns the number of ways making up this ring.
+    unsigned int nways() const { return m_nways; }
+
+    /// Returns the number of points in this ring.
+    unsigned int npoints() const { return m_way_node_list.size(); }
+
+    /// Returns true if the ring is closed.
+    bool is_closed() const { return first_node_id() == last_node_id(); }
+
+    /// Was this ring fixed because of missing/wrong OSM data?
+    bool is_fixed() const { return m_fixed; }
+
+    /**
+     * When there are two different nodes with the same position
+     * a situation can arise where a CoastlineRing looks not closed
+     * when looking at the node IDs but looks closed then looking
+     * at the positions. To "fix" this we change the node ID of the
+     * last node in the ring to be the same as the first. This
+     * method does this.
+     */
+    void fake_close() {
+        m_way_node_list.back().set_ref(first_node_id());
+    }
+
+    /**
+     * Add pointers to the node positions to the given posmap. The
+     * posmap can than later be used to directly put the positions
+     * into the right place.
+     */
+    void setup_positions(posmap_type& posmap);
+
+    /**
+     * Check whether all positions for the ways are there. This
+     * can happen if the input data is missing a node needed for a
+     * way. The function returns the number of missing positions.
+     */
+    unsigned int check_positions(bool output_missing);
+
+    /// Add a new way to the front of this ring.
+    void add_at_front(const osmium::Way& way);
+
+    /// Add a new way to the end of this ring.
+    void add_at_end(const osmium::Way& way);
+
+    /**
+     * Join the other ring to this one. The first node ID of the
+     * other ring must be the same as the last node ID of this
+     * ring.
+     * The other ring can be destroyed afterwards.
+     */
+    void join(const CoastlineRing& other);
+
+    /**
+     * Join the other ring to this one, possibly over a gap.
+     * The other ring can be destroyed afterwards.
+     */
+    void join_over_gap(const CoastlineRing& other);
+
+    /**
+     * Close ring by adding the first node to the end. If the
+     * ring is already closed it is not changed.
+     */
+    void close_ring();
+
+    /**
+     * Close Antarctica ring by adding some nodes.
+     */
+    void close_antarctica_ring(int epsg);
+
+    /**
+     * Create OGRPolygon for this ring.
+     *
+     * Caller takes ownership of the created object.
+     *
+     * @param geom_factory Geometry factory that should be used to build the geometry.
+     * @param reverse Reverse the ring when creating the geometry.
+     */
+    std::unique_ptr<OGRPolygon> ogr_polygon(osmium::geom::OGRFactory<>& geom_factory, bool reverse) const;
+
+    /**
+     * Create OGRLineString for this ring.
+     *
+     * Caller takes ownership of the created object.
+     *
+     * @param geom_factory Geometry factory that should be used to build the geometry.
+     * @param reverse Reverse the ring when creating the geometry.
+     */
+    std::unique_ptr<OGRLineString> ogr_linestring(osmium::geom::OGRFactory<>& geom_factory, bool reverse) const;
+
+    /**
+     * Create OGRPoint for the first point in this ring.
+     *
+     * Caller takes ownership of created object.
+     */
+    std::unique_ptr<OGRPoint> ogr_first_point() const;
+
+    /**
+     * Create OGRPoint for the last point in this ring.
+     loca*
+     * Caller takes ownership of created object.
+     */
+    std::unique_ptr<OGRPoint> ogr_last_point() const;
+
+    double distance_to_start_position(osmium::Location pos) const;
+
+    void add_segments_to_vector(std::vector<osmium::UndirectedSegment>& segments) const;
+
+    friend std::ostream& operator<<(std::ostream& out, const CoastlineRing& cp);
+
+};
+
+inline bool operator<(const CoastlineRing& lhs, const CoastlineRing& rhs) {
+    return lhs.first_position() < rhs.first_position();
+}
+
+#endif // COASTLINE_RING_HPP
diff --git a/coastline_ring_collection.cpp b/coastline_ring_collection.cpp
new file mode 100644
index 0000000..5cc5823
--- /dev/null
+++ b/coastline_ring_collection.cpp
@@ -0,0 +1,423 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <iostream>
+#include <memory>
+
+#include <ogr_geometry.h>
+
+#include "coastline_polygons.hpp"
+#include "coastline_ring_collection.hpp"
+#include "output_database.hpp"
+#include "srs.hpp"
+
+extern SRS srs;
+extern bool debug;
+
+CoastlineRingCollection::CoastlineRingCollection() :
+    m_list(),
+    m_start_nodes(),
+    m_end_nodes(),
+    m_ways(0),
+    m_rings_from_single_way(0),
+    m_fixed_rings(0) {
+}
+
+/**
+ * If a way is not closed adding it to the coastline collection is a bit
+ * complicated.
+ * We'll check if there is an existing CoastlineRing that our way connects
+ * to and add it to that ring. If there is none, we'll create a new
+ * CoastlineRing for it and add that to the collection.
+ */
+void CoastlineRingCollection::add_partial_ring(const osmium::Way& way) {
+    idmap_type::iterator mprev = m_end_nodes.find(way.nodes().front().ref());
+    idmap_type::iterator mnext = m_start_nodes.find(way.nodes().back().ref());
+
+    // There is no CoastlineRing yet where this way could fit. So we
+    // create one and add it to the collection.
+    if (mprev == m_end_nodes.end() &&
+        mnext == m_start_nodes.end()) {
+        coastline_rings_list_t::iterator added = m_list.insert(m_list.end(), std::make_shared<CoastlineRing>(way));
+        m_start_nodes[way.nodes().front().ref()] = added;
+        m_end_nodes[way.nodes().back().ref()] = added;
+        return;
+    }
+
+    // We found a CoastlineRing where we can add the way at the end.
+    if (mprev != m_end_nodes.end()) {
+        coastline_rings_list_t::iterator prev = mprev->second;
+        (*prev)->add_at_end(way);
+        m_end_nodes.erase(mprev);
+
+        if ((*prev)->is_closed()) {
+            m_start_nodes.erase(m_start_nodes.find((*prev)->first_node_id()));
+            return;
+        }
+
+        // We also found a CoastlineRing where we could have added the
+        // way at the front. This means that the way together with the
+        // ring at front and the ring at back are now a complete ring.
+        if (mnext != m_start_nodes.end()) {
+            coastline_rings_list_t::iterator next = mnext->second;
+            (*prev)->join(**next);
+            m_start_nodes.erase(mnext);
+            if ((*prev)->is_closed()) {
+                idmap_type::iterator x = m_start_nodes.find((*prev)->first_node_id());
+                if (x != m_start_nodes.end()) {
+                    m_start_nodes.erase(x);
+                }
+                x = m_end_nodes.find((*prev)->last_node_id());
+                if (x != m_end_nodes.end()) {
+                    m_end_nodes.erase(x);
+                }
+            }
+            m_list.erase(next);
+        }
+
+        m_end_nodes[(*prev)->last_node_id()] = prev;
+        return;
+    }
+
+    // We found a CoastlineRing where we can add the way at the front.
+    if (mnext != m_start_nodes.end()) {
+        coastline_rings_list_t::iterator next = mnext->second;
+        (*next)->add_at_front(way);
+        m_start_nodes.erase(mnext);
+        if ((*next)->is_closed()) {
+            m_end_nodes.erase(m_end_nodes.find((*next)->last_node_id()));
+            return;
+        }
+        m_start_nodes[(*next)->first_node_id()] = next;
+    }
+}
+
+void CoastlineRingCollection::setup_positions(posmap_type& posmap) {
+    for (const auto& ring : m_list) {
+        ring->setup_positions(posmap);
+    }
+}
+
+unsigned int CoastlineRingCollection::check_positions(bool output_missing) {
+    unsigned int missing_positions = 0;
+
+    for (const auto& ring : m_list) {
+        missing_positions += ring->check_positions(output_missing);
+    }
+
+    return missing_positions;
+}
+
+void CoastlineRingCollection::add_polygons_to_vector(std::vector<OGRGeometry*>& vector) {
+    vector.reserve(m_list.size());
+
+    for (const auto& ring : m_list) {
+        if (ring->is_closed() && ring->npoints() > 3) { // everything that doesn't match here is bad beyond repair and reported elsewhere
+            std::unique_ptr<OGRPolygon> p = ring->ogr_polygon(m_factory, true);
+            if (p->IsValid()) {
+                p->assignSpatialReference(srs.wgs84());
+                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()) {
+                    geom->assignSpatialReference(srs.wgs84());
+                    vector.push_back(static_cast<OGRPolygon*>(geom.release()));
+                } else {
+                    std::cerr << "Ignoring invalid polygon geometry (ring_id=" << ring->ring_id() << ").\n";
+                }
+            }
+        }
+    }
+}
+
+unsigned int CoastlineRingCollection::output_rings(OutputDatabase& output) {
+    unsigned int warnings = 0;
+
+    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());
+            } 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_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_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++;
+        }
+    }
+
+    return warnings;
+}
+
+osmium::Location intersection(const osmium::Segment& s1, const osmium::Segment&s2) {
+    if (s1.first()  == s2.first()  ||
+        s1.first()  == s2.second() ||
+        s1.second() == s2.first()  ||
+        s1.second() == s2.second()) {
+        return osmium::Location();
+    }
+
+    double denom = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) -
+                   ((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat()));
+
+    if (denom != 0) {
+        double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) -
+                        ((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon()));
+
+        double nume_b = ((s1.second().lon() - s1.first().lon())*(s1.first().lat() - s2.first().lat())) -
+                        ((s1.second().lat() - s1.first().lat())*(s1.first().lon() - s2.first().lon()));
+
+        if ((denom > 0 && nume_a >= 0 && nume_a <= denom && nume_b >= 0 && nume_b <= denom) ||
+            (denom < 0 && nume_a <= 0 && nume_a >= denom && nume_b <= 0 && nume_b >= denom)) {
+            double ua = nume_a / denom;
+            double ix = s1.first().lon() + ua*(s1.second().lon() - s1.first().lon());
+            double iy = s1.first().lat() + ua*(s1.second().lat() - s1.first().lat());
+            return osmium::Location(ix, iy);
+        }
+    }
+
+    return osmium::Location();
+}
+
+bool outside_x_range(const osmium::UndirectedSegment& s1, const osmium::UndirectedSegment& s2) {
+    if (s1.first().x() > s2.second().x()) {
+        return true;
+    }
+    return false;
+}
+
+bool y_range_overlap(const osmium::UndirectedSegment& s1, const osmium::UndirectedSegment& s2) {
+    int tmin = s1.first().y() < s1.second().y() ? s1.first().y( ) : s1.second().y();
+    int tmax = s1.first().y() < s1.second().y() ? s1.second().y() : s1.first().y();
+    int omin = s2.first().y() < s2.second().y() ? s2.first().y()  : s2.second().y();
+    int omax = s2.first().y() < s2.second().y() ? s2.second().y() : s2.first().y();
+    if (tmin > omax || omin > tmax) {
+        return false;
+    }
+    return true;
+}
+
+std::unique_ptr<OGRLineString> create_ogr_linestring(const osmium::Segment& segment) {
+    std::unique_ptr<OGRLineString> line { new OGRLineString };
+    line->setNumPoints(2);
+    line->setPoint(0, segment.first().lon(), segment.first().lat());
+    line->setPoint(1, segment.second().lon(), segment.second().lat());
+    line->setCoordinateDimension(2);
+
+    return line;
+}
+
+/**
+ * Checks if there are intersections between any coastline segments.
+ * Returns the number of intersections and overlaps.
+ */
+unsigned int CoastlineRingCollection::check_for_intersections(OutputDatabase& output) {
+    unsigned int overlaps = 0;
+
+    std::vector<osmium::UndirectedSegment> segments;
+    if (debug) std::cerr << "Setting up segments...\n";
+    for (const auto& ring : m_list) {
+        ring->add_segments_to_vector(segments);
+    }
+
+    if (debug) std::cerr << "Sorting...\n";
+    std::sort(segments.begin(), segments.end());
+
+    if (debug) std::cerr << "Finding intersections...\n";
+    std::vector<osmium::Location> intersections;
+    for (auto it1 = segments.cbegin(); it1 != segments.cend()-1; ++it1) {
+        const osmium::UndirectedSegment& s1 = *it1;
+        for (auto it2 = it1+1; it2 != segments.cend(); ++it2) {
+            const osmium::UndirectedSegment& s2 = *it2;
+            if (s1 == s2) {
+                std::unique_ptr<OGRLineString> line = create_ogr_linestring(s1);
+                output.add_error_line(std::move(line), "overlap");
+                overlaps++;
+            } else {
+                if (outside_x_range(s2, s1)) {
+                    break;
+                }
+                if (y_range_overlap(s1, s2)) {
+                    osmium::Location i = intersection(s1, s2);
+                    if (i) {
+                        intersections.push_back(i);
+                    }
+                }
+            }
+        }
+    }
+
+    for (const auto& intersection : intersections) {
+        std::unique_ptr<OGRPoint> point { new OGRPoint(intersection.lon(), intersection.lat()) };
+        output.add_error_point(std::move(point), "intersection");
+    }
+
+    return intersections.size() + overlaps;
+}
+
+bool CoastlineRingCollection::close_antarctica_ring(int epsg) {
+    for (const auto& ring : m_list) {
+        osmium::Location fpos = ring->first_position();
+        osmium::Location lpos = ring->last_position();
+        if (fpos.lon() > 179.99 && lpos.lon() < -179.99 &&
+            fpos.lat() <  -77.0 && fpos.lat() >  -78.0 &&
+            lpos.lat() <  -77.0 && lpos.lat() >  -78.0) {
+
+            m_end_nodes.erase(ring->last_node_id());
+            m_start_nodes.erase(ring->first_node_id());
+            ring->close_antarctica_ring(epsg);
+            return true;
+        }
+    }
+    return false;
+}
+
+void CoastlineRingCollection::close_rings(OutputDatabase& output, bool debug, double max_distance) {
+    std::vector<Connection> connections;
+
+    // Create vector with all possible combinations of connections between rings.
+    for (idmap_type::iterator eit = m_end_nodes.begin(); eit != m_end_nodes.end(); ++eit) {
+        for (idmap_type::iterator sit = m_start_nodes.begin(); sit != m_start_nodes.end(); ++sit) {
+            double distance = (*sit->second)->distance_to_start_position((*eit->second)->last_position());
+            if (distance < max_distance) {
+                connections.emplace_back(distance, eit->first, sit->first);
+            }
+        }
+    }
+
+    // Sort vector by distance, shortest at end.
+    std::sort(connections.begin(), connections.end(), Connection::sort_by_distance);
+
+    // Go through vector starting with the shortest connections and close rings
+    // using the connections in turn.
+    while (!connections.empty()) {
+        Connection conn = connections.back();
+        connections.pop_back();
+
+        // Invalidate all other connections using one of the same end points.
+        connections.erase(remove_if(connections.begin(), connections.end(), conn), connections.end());
+
+        idmap_type::iterator eit = m_end_nodes.find(conn.start_id);
+        idmap_type::iterator sit = m_start_nodes.find(conn.end_id);
+
+        if (eit != m_end_nodes.end() && sit != m_start_nodes.end()) {
+            if (debug) {
+                std::cerr << "Closing ring between node " << conn.end_id << " and node " << conn.start_id << "\n";
+            }
+
+            m_fixed_rings++;
+
+            CoastlineRing* e = eit->second->get();
+            CoastlineRing* s = sit->second->get();
+
+            output.add_error_point(e->ogr_last_point(), "fixed_end_point", e->last_node_id());
+            output.add_error_point(s->ogr_first_point(), "fixed_end_point", s->first_node_id());
+
+            if (e->last_position() != s->first_position()) {
+                std::unique_ptr<OGRLineString> linestring { new OGRLineString };
+                linestring->addPoint(e->last_position().lon(), e->last_position().lat());
+                linestring->addPoint(s->first_position().lon(), s->first_position().lat());
+                output.add_error_line(std::move(linestring), "added_line");
+            }
+
+            if (e == s) {
+                // connect to itself by closing ring
+                e->close_ring();
+
+                m_end_nodes.erase(eit);
+                m_start_nodes.erase(sit);
+            } else {
+                // connect to other ring
+                e->join_over_gap(*s);
+
+                m_list.erase(sit->second);
+                if (e->first_position() == e->last_position()) {
+                    output.add_error_point(e->ogr_first_point(), "double_node", e->first_node_id());
+                    m_start_nodes.erase(e->first_node_id());
+                    m_end_nodes.erase(eit);
+                    m_start_nodes.erase(sit);
+                    m_end_nodes.erase(e->last_node_id());
+                    e->fake_close();
+                } else {
+                    m_end_nodes[e->last_node_id()] = eit->second;
+                    m_end_nodes.erase(eit);
+                    m_start_nodes.erase(sit);
+                }
+            }
+        }
+    }
+}
+
+/**
+ * Finds some questionably polygons. This will find
+ * a) some polygons touching another polygon in a single point
+ * b) holes inside land (those should usually be tagged as water, riverbank, or so, not as coastline)
+ *    very large such objects will not be reported, this excludes the Great Lakes etc.
+ * c) holes inside holes (those are definitely wrong)
+ *
+ * Returns the number of warnings.
+ */
+unsigned int CoastlineRingCollection::output_questionable(const CoastlinePolygons& polygons, OutputDatabase& output) {
+    const unsigned int max_nodes_to_be_considered_questionable = 10000;
+    unsigned int warnings = 0;
+
+    typedef std::pair<osmium::Location, CoastlineRing*> pos_ring_ptr_t;
+    std::vector<pos_ring_ptr_t> rings;
+    rings.reserve(m_list.size());
+
+    // put all rings in a vector...
+    for (const auto& ring : m_list) {
+        rings.emplace_back(ring->first_position(), ring.get());
+    }
+
+    // ... and sort it by position of the first node in the ring (this allows binary search in it)
+    std::sort(rings.begin(), rings.end());
+
+    // 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();
+        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()) {
+            rings_it->second->set_outer();
+        }
+    }
+
+    // find all rings not marked as outer and output them to the error_lines table
+    for (const auto& ring : m_list) {
+        if (!ring->is_outer()) {
+            if (ring->is_closed() && ring->npoints() > 3 && ring->npoints() < max_nodes_to_be_considered_questionable) {
+                output.add_error_line(ring->ogr_linestring(m_factory, false), "questionable", ring->ring_id());
+                warnings++;
+            }
+        }
+    }
+
+    return warnings;
+}
diff --git a/coastline_ring_collection.hpp b/coastline_ring_collection.hpp
new file mode 100644
index 0000000..42d7eef
--- /dev/null
+++ b/coastline_ring_collection.hpp
@@ -0,0 +1,133 @@
+#ifndef COASTLINE_RING_COLLECTION_HPP
+#define COASTLINE_RING_COLLECTION_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <list>
+#include <vector>
+
+#include <osmium/geom/ogr.hpp>
+#include <osmium/osm/way.hpp>
+
+#include "coastline_ring.hpp"
+
+class OGRGeometry;
+class OGRPolygon;
+class OutputDatabase;
+class CoastlinePolygons;
+
+typedef std::list<std::shared_ptr<CoastlineRing>> coastline_rings_list_t;
+typedef std::map<osmium::object_id_type, coastline_rings_list_t::iterator> idmap_type;
+
+/**
+ * A collection of CoastlineRing objects. Keeps a list of all start and end
+ * nodes so it can efficiently join CoastlineRings.
+ */
+class CoastlineRingCollection {
+
+    coastline_rings_list_t m_list;
+
+    // Mapping from node IDs to CoastlineRings.
+    idmap_type m_start_nodes;
+    idmap_type m_end_nodes;
+
+    unsigned int m_ways;
+    unsigned int m_rings_from_single_way;
+    unsigned int m_fixed_rings;
+
+    void add_partial_ring(const osmium::Way& way);
+
+    osmium::geom::OGRFactory<> m_factory;
+
+public:
+
+    typedef coastline_rings_list_t::const_iterator const_iterator;
+
+    CoastlineRingCollection();
+
+    /// Return the number of CoastlineRings in the collection.
+    size_t size() const { return m_list.size(); }
+
+    /**
+     * Add way to collection. A new CoastlineRing will be created for the way
+     * or it will be joined to an existing CoastlineRing.
+     */
+    void add_way(const osmium::Way& way) {
+        m_ways++;
+        if (way.is_closed()) {
+            m_rings_from_single_way++;
+            m_list.push_back(std::make_shared<CoastlineRing>(way));
+        } else {
+            add_partial_ring(way);
+        }
+    }
+
+    unsigned int num_ways() const { return m_ways; }
+
+    unsigned int num_rings_from_single_way() const { return m_rings_from_single_way; }
+
+    unsigned int num_unconnected_nodes() const { return m_start_nodes.size() + m_end_nodes.size(); }
+
+    unsigned int num_fixed_rings() const { return m_fixed_rings; }
+
+    void setup_positions(posmap_type& posmap);
+
+    unsigned int check_positions(bool output_missing);
+
+    void add_polygons_to_vector(std::vector<OGRGeometry*>& vector);
+
+    unsigned int output_rings(OutputDatabase& output);
+
+    unsigned int check_for_intersections(OutputDatabase& output);
+
+    bool close_antarctica_ring(int epsg);
+
+    void close_rings(OutputDatabase& output, bool debug, double max_distance);
+
+    unsigned int output_questionable(const CoastlinePolygons& polygons, OutputDatabase& output);
+
+private:
+
+    struct Connection {
+
+        double distance;
+        osmium::object_id_type start_id;
+        osmium::object_id_type end_id;
+
+        Connection(double d, osmium::object_id_type s, osmium::object_id_type e) : distance(d), start_id(s), end_id(e) { }
+
+        /**
+        * Returns true if start or end ID of this connection is the same as the
+        * other connections start or end ID. Used as predicate in std::remove_if().
+        */
+        bool operator()(const Connection& other) {
+            return start_id == other.start_id || end_id == other.end_id;
+        }
+
+        // Used in std::sort
+        static bool sort_by_distance(const Connection& a, const Connection& b) { return a.distance > b.distance; }
+
+    };
+
+};
+
+#endif // COASTLINE_RING_COLLECTION_HPP
diff --git a/coastline_sources.qgs b/coastline_sources.qgs
new file mode 100644
index 0000000..af93348
--- /dev/null
+++ b/coastline_sources.qgs
@@ -0,0 +1,329 @@
+<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
+<qgis projectname="" version="1.7.4-Wroclaw">
+    <title></title>
+    <mapcanvas>
+        <units>degrees</units>
+        <extent>
+            <xmin>-189.000000</xmin>
+            <ymin>-95.960075</ymin>
+            <xmax>189.000000</xmax>
+            <ymax>94.578297</ymax>
+        </extent>
+        <projections>0</projections>
+        <destinationsrs>
+            <spatialrefsys>
+                <proj4>+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs</proj4>
+                <srsid>3452</srsid>
+                <srid>4326</srid>
+                <authid>EPSG:4326</authid>
+                <description>WGS 84</description>
+                <projectionacronym>longlat</projectionacronym>
+                <ellipsoidacronym>WGS84</ellipsoidacronym>
+                <geographicflag>true</geographicflag>
+            </spatialrefsys>
+        </destinationsrs>
+    </mapcanvas>
+    <legend>
+        <legendlayer open="true" checked="Qt::Checked" name="ways" showFeatureCount="0">
+            <filegroup open="true" hidden="false">
+                <legendlayerfile isInOverview="0" layerid="ways20120427112632472" visible="1"/>
+            </filegroup>
+        </legendlayer>
+        <legendlayer open="true" checked="Qt::Checked" name="polygons" showFeatureCount="0">
+            <filegroup open="true" hidden="false">
+                <legendlayerfile isInOverview="0" layerid="polygons20120327152822242" visible="1"/>
+            </filegroup>
+        </legendlayer>
+    </legend>
+    <projectlayers layercount="2">
+        <maplayer minimumScale="0" maximumScale="1e+08" geometry="Polygon" type="vector" hasScaleBasedVisibilityFlag="0">
+            <id>polygons20120327152822242</id>
+            <datasource>dbname='./testdata.db' table="polygons" (GEOMETRY) sql=</datasource>
+            <layername>polygons</layername>
+            <srs>
+                <spatialrefsys>
+                    <proj4>+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs</proj4>
+                    <srsid>3284</srsid>
+                    <srid>4148</srid>
+                    <authid>EPSG:4148</authid>
+                    <description>Hartebeesthoek94</description>
+                    <projectionacronym>longlat</projectionacronym>
+                    <ellipsoidacronym>WGS84</ellipsoidacronym>
+                    <geographicflag>true</geographicflag>
+                </spatialrefsys>
+            </srs>
+            <transparencyLevelInt>255</transparencyLevelInt>
+            <provider encoding="System">spatialite</provider>
+            <vectorjoins/>
+            <renderer-v2 symbollevels="0" type="singleSymbol">
+                <symbols>
+                    <symbol outputUnit="MM" alpha="0.4980392156862745" type="fill" name="0">
+                        <layer pass="0" class="SimpleFill" locked="0">
+                            <prop k="color" v="100,100,100,127"/>
+                            <prop k="color_border" v="0,0,0,127"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="style" v="solid"/>
+                            <prop k="style_border" v="no"/>
+                            <prop k="width_border" v="0.26"/>
+                        </layer>
+                    </symbol>
+                </symbols>
+                <rotation field=""/>
+                <sizescale field=""/>
+            </renderer-v2>
+            <customproperties/>
+            <displayfield>OGC_FID</displayfield>
+            <label>0</label>
+            <labelattributes>
+                <label fieldname="" text="Label"/>
+                <family fieldname="" name="Sans"/>
+                <size fieldname="" units="pt" value="12"/>
+                <bold fieldname="" on="0"/>
+                <italic fieldname="" on="0"/>
+                <underline fieldname="" on="0"/>
+                <strikeout fieldname="" on="0"/>
+                <color fieldname="" red="0" blue="0" green="0"/>
+                <x fieldname=""/>
+                <y fieldname=""/>
+                <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+                <angle fieldname="" value="0" auto="0"/>
+                <alignment fieldname="" value="center"/>
+                <buffercolor fieldname="" red="255" blue="255" green="255"/>
+                <buffersize fieldname="" units="pt" value="1"/>
+                <bufferenabled fieldname="" on=""/>
+                <multilineenabled fieldname="" on=""/>
+                <selectedonly on=""/>
+            </labelattributes>
+            <edittypes>
+                <edittype type="0" name="OGC_FID"/>
+                <edittype type="0" name="clockwise"/>
+            </edittypes>
+            <editform>.</editform>
+            <editforminit></editforminit>
+            <annotationform>.</annotationform>
+            <attributeactions/>
+        </maplayer>
+        <maplayer minimumScale="0" maximumScale="1e+08" geometry="Line" type="vector" hasScaleBasedVisibilityFlag="0">
+            <id>ways20120427112632472</id>
+            <datasource>dbname='./coastline-ways.db' table="ways" (GEOMETRY) sql=</datasource>
+            <layername>ways</layername>
+            <srs>
+                <spatialrefsys>
+                    <proj4>+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs</proj4>
+                    <srsid>3284</srsid>
+                    <srid>4148</srid>
+                    <authid>EPSG:4148</authid>
+                    <description>Hartebeesthoek94</description>
+                    <projectionacronym>longlat</projectionacronym>
+                    <ellipsoidacronym>WGS84</ellipsoidacronym>
+                    <geographicflag>true</geographicflag>
+                </spatialrefsys>
+            </srs>
+            <transparencyLevelInt>255</transparencyLevelInt>
+            <provider encoding="System">spatialite</provider>
+            <vectorjoins/>
+            <renderer-v2 symbollevels="0" type="RuleRenderer" firstrule="0">
+                <rules>
+                    <rule scalemaxdenom="0" description="" filter="" symbol="0" scalemindenom="0" label="other"/>
+                    <rule scalemaxdenom="0" description="" filter="source LIKE 'PGS%'" symbol="1" scalemindenom="0" label="PGS*"/>
+                    <rule scalemaxdenom="0" description="" filter="source = ''" symbol="2" scalemindenom="0" label="empty"/>
+                    <rule scalemaxdenom="0" description="" filter="source = 'Bing' OR source = 'bing'" symbol="3" scalemindenom="0" label="Bing/bing"/>
+                    <rule scalemaxdenom="0" description="" filter="source LIKE 'gadm%' OR source LIKE 'GADM%'" symbol="4" scalemindenom="0" label="GADM*/gadm*"/>
+                    <rule scalemaxdenom="0" description="" filter="source = 'YahooJapan/ALPSMAP'" symbol="5" scalemindenom="0" label="YahooJapan/ALPSMAP"/>
+                    <rule scalemaxdenom="0" description="" filter="source = 'GeoBase'" symbol="6" scalemindenom="0" label="GeoBase"/>
+                    <rule scalemaxdenom="0" description="" filter="source LIKE 'NRCan-CanVec-%'" symbol="7" scalemindenom="0" label="NRCan-CanVec-*"/>
+                    <rule scalemaxdenom="0" description="" filter="source = 'Landsat' OR source = 'landsat'" symbol="8" scalemindenom="0" label="Landsat/landsat"/>
+                    <rule scalemaxdenom="0" description="" filter="source = 'ABS_2006'" symbol="9" scalemindenom="0" label="ABS_2006"/>
+                </rules>
+                <symbols>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="0">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="161,161,161,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="1">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="85,255,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="2">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="0,0,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="3">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="255,170,127,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="4">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="5">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="0,85,255,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="6">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="170,85,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="7">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="0,255,255,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="8">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="0,170,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="9">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="15,136,104,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="default">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="157,230,96,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.26"/>
+                        </layer>
+                    </symbol>
+                </symbols>
+            </renderer-v2>
+            <customproperties/>
+            <displayfield>name</displayfield>
+            <label>0</label>
+            <labelattributes>
+                <label fieldname="" text="Label"/>
+                <family fieldname="" name="Sans"/>
+                <size fieldname="" units="pt" value="12"/>
+                <bold fieldname="" on="0"/>
+                <italic fieldname="" on="0"/>
+                <underline fieldname="" on="0"/>
+                <strikeout fieldname="" on="0"/>
+                <color fieldname="" red="0" blue="0" green="0"/>
+                <x fieldname=""/>
+                <y fieldname=""/>
+                <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+                <angle fieldname="" value="0" auto="0"/>
+                <alignment fieldname="" value="center"/>
+                <buffercolor fieldname="" red="255" blue="255" green="255"/>
+                <buffersize fieldname="" units="pt" value="1"/>
+                <bufferenabled fieldname="" on=""/>
+                <multilineenabled fieldname="" on=""/>
+                <selectedonly on=""/>
+            </labelattributes>
+            <edittypes>
+                <edittype type="0" name="OGC_FID"/>
+                <edittype type="0" name="name"/>
+                <edittype type="0" name="source"/>
+                <edittype type="0" name="way_id"/>
+            </edittypes>
+            <editform></editform>
+            <editforminit></editforminit>
+            <annotationform></annotationform>
+            <attributeactions/>
+        </maplayer>
+    </projectlayers>
+    <properties>
+        <SpatialRefSys>
+            <ProjectCrs type="QString">EPSG:4326</ProjectCrs>
+        </SpatialRefSys>
+        <Paths>
+            <Absolute type="bool">false</Absolute>
+        </Paths>
+        <Gui>
+            <SelectionColorBluePart type="int">0</SelectionColorBluePart>
+            <CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
+            <CanvasColorRedPart type="int">255</CanvasColorRedPart>
+            <SelectionColorRedPart type="int">255</SelectionColorRedPart>
+            <SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
+            <SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
+            <CanvasColorBluePart type="int">255</CanvasColorBluePart>
+        </Gui>
+        <PositionPrecision>
+            <DecimalPlaces type="int">2</DecimalPlaces>
+            <Automatic type="bool">true</Automatic>
+        </PositionPrecision>
+    </properties>
+</qgis>
diff --git a/coastline_sqlite.qgs b/coastline_sqlite.qgs
new file mode 100644
index 0000000..2bb753e
--- /dev/null
+++ b/coastline_sqlite.qgs
@@ -0,0 +1,821 @@
+<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
+<qgis projectname="" version="1.7.4-Wroclaw">
+    <title></title>
+    <mapcanvas>
+        <units>degrees</units>
+        <extent>
+            <xmin>7.124809</xmin>
+            <ymin>53.614608</ymin>
+            <xmax>7.655311</xmax>
+            <ymax>53.881862</ymax>
+        </extent>
+        <projections>0</projections>
+        <destinationsrs>
+            <spatialrefsys>
+                <proj4>+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs</proj4>
+                <srsid>3452</srsid>
+                <srid>4326</srid>
+                <authid>EPSG:4326</authid>
+                <description>WGS 84</description>
+                <projectionacronym>longlat</projectionacronym>
+                <ellipsoidacronym>WGS84</ellipsoidacronym>
+                <geographicflag>true</geographicflag>
+            </spatialrefsys>
+        </destinationsrs>
+    </mapcanvas>
+    <legend>
+        <legendlayer open="true" checked="Qt::Checked" name="error_points" showFeatureCount="0">
+            <filegroup open="true" hidden="false">
+                <legendlayerfile isInOverview="0" layerid="error_points20120327152822195" visible="1"/>
+            </filegroup>
+        </legendlayer>
+        <legendlayer open="true" checked="Qt::Checked" name="rings" showFeatureCount="0">
+            <filegroup open="true" hidden="false">
+                <legendlayerfile isInOverview="0" layerid="rings20120327152822288" visible="1"/>
+            </filegroup>
+        </legendlayer>
+        <legendlayer open="true" checked="Qt::Checked" name="error_lines" showFeatureCount="0">
+            <filegroup open="true" hidden="false">
+                <legendlayerfile isInOverview="0" layerid="error_lines20120327152821609" visible="1"/>
+            </filegroup>
+        </legendlayer>
+        <legendlayer open="true" checked="Qt::Checked" name="lines" showFeatureCount="0">
+            <filegroup open="true" hidden="false">
+                <legendlayerfile isInOverview="0" layerid="lines20120513170615065" visible="1"/>
+            </filegroup>
+        </legendlayer>
+        <legendlayer open="true" checked="Qt::Checked" name="land_polygons" showFeatureCount="0">
+            <filegroup open="true" hidden="false">
+                <legendlayerfile isInOverview="0" layerid="polygons20120327152822242" visible="1"/>
+            </filegroup>
+        </legendlayer>
+        <legendlayer open="true" checked="Qt::Checked" name="water_polygons" showFeatureCount="0">
+            <filegroup open="true" hidden="false">
+                <legendlayerfile isInOverview="0" layerid="water_polygons20120521162144305" visible="1"/>
+            </filegroup>
+        </legendlayer>
+    </legend>
+    <projectlayers layercount="6">
+        <maplayer minimumScale="0" maximumScale="1e+08" geometry="Line" type="vector" hasScaleBasedVisibilityFlag="0">
+            <id>error_lines20120327152821609</id>
+            <datasource>dbname='./testdata.db' table="error_lines" (GEOMETRY) sql=</datasource>
+            <layername>error_lines</layername>
+            <srs>
+                <spatialrefsys>
+                    <proj4>+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs</proj4>
+                    <srsid>3284</srsid>
+                    <srid>4148</srid>
+                    <authid>EPSG:4148</authid>
+                    <description>Hartebeesthoek94</description>
+                    <projectionacronym>longlat</projectionacronym>
+                    <ellipsoidacronym>WGS84</ellipsoidacronym>
+                    <geographicflag>true</geographicflag>
+                </spatialrefsys>
+            </srs>
+            <transparencyLevelInt>255</transparencyLevelInt>
+            <provider encoding="System">spatialite</provider>
+            <vectorjoins/>
+            <renderer-v2 attr="error" symbollevels="0" type="categorizedSymbol">
+                <categories>
+                    <category symbol="0" value="not_a_ring" label="not_a_ring"/>
+                    <category symbol="1" value="not_closed" label="not_closed"/>
+                    <category symbol="2" value="direction" label="direction"/>
+                    <category symbol="3" value="added_line" label="added_line"/>
+                    <category symbol="4" value="invalid" label="invalid"/>
+                    <category symbol="5" value="overlap" label="overlap"/>
+                    <category symbol="6" value="questionable" label="questionable"/>
+                    <category symbol="7" value="" label="(unknown)"/>
+                </categories>
+                <symbols>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="0">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="0,0,255,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                        <layer pass="0" class="LineDecoration" locked="0">
+                            <prop k="color" v="0,0,255,255"/>
+                            <prop k="width" v="0.26"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="1">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="170,85,127,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                        <layer pass="0" class="LineDecoration" locked="0">
+                            <prop k="color" v="170,85,127,255"/>
+                            <prop k="width" v="0.26"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="2">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="255,255,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="1"/>
+                        </layer>
+                        <layer pass="0" class="LineDecoration" locked="0">
+                            <prop k="color" v="255,85,0,255"/>
+                            <prop k="width" v="0.52"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="3">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="255,170,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="4">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="0,85,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="5">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="round"/>
+                            <prop k="color" v="170,0,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="4"/>
+                        </layer>
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="round"/>
+                            <prop k="color" v="255,255,255,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="3"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="6">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="0,0,127,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="dot"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="7">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.5"/>
+                        </layer>
+                    </symbol>
+                </symbols>
+                <source-symbol>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="0">
+                        <layer pass="0" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="square"/>
+                            <prop k="color" v="168,66,141,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="bevel"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.26"/>
+                        </layer>
+                    </symbol>
+                </source-symbol>
+                <colorramp type="gradient" name="[source]">
+                    <prop k="color1" v="0,0,255,255"/>
+                    <prop k="color2" v="175,175,175,255"/>
+                </colorramp>
+                <rotation field=""/>
+                <sizescale field=""/>
+            </renderer-v2>
+            <customproperties/>
+            <displayfield>osm_id</displayfield>
+            <label>0</label>
+            <labelattributes>
+                <label fieldname="" text="Label"/>
+                <family fieldname="" name="Sans"/>
+                <size fieldname="" units="pt" value="12"/>
+                <bold fieldname="" on="0"/>
+                <italic fieldname="" on="0"/>
+                <underline fieldname="" on="0"/>
+                <strikeout fieldname="" on="0"/>
+                <color fieldname="" red="0" blue="0" green="0"/>
+                <x fieldname=""/>
+                <y fieldname=""/>
+                <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+                <angle fieldname="" value="0" auto="0"/>
+                <alignment fieldname="" value="center"/>
+                <buffercolor fieldname="" red="255" blue="255" green="255"/>
+                <buffersize fieldname="" units="pt" value="1"/>
+                <bufferenabled fieldname="" on=""/>
+                <multilineenabled fieldname="" on=""/>
+                <selectedonly on=""/>
+            </labelattributes>
+            <edittypes>
+                <edittype type="0" name="OGC_FID"/>
+                <edittype type="0" name="error"/>
+                <edittype type="0" name="osm_id"/>
+            </edittypes>
+            <editform>.</editform>
+            <editforminit></editforminit>
+            <annotationform>.</annotationform>
+            <attributeactions/>
+        </maplayer>
+        <maplayer minimumScale="0" maximumScale="1e+08" geometry="Point" type="vector" hasScaleBasedVisibilityFlag="0">
+            <id>error_points20120327152822195</id>
+            <datasource>dbname='./testdata.db' table="error_points" (GEOMETRY) sql=</datasource>
+            <layername>error_points</layername>
+            <srs>
+                <spatialrefsys>
+                    <proj4>+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs</proj4>
+                    <srsid>3284</srsid>
+                    <srid>4148</srid>
+                    <authid>EPSG:4148</authid>
+                    <description>Hartebeesthoek94</description>
+                    <projectionacronym>longlat</projectionacronym>
+                    <ellipsoidacronym>WGS84</ellipsoidacronym>
+                    <geographicflag>true</geographicflag>
+                </spatialrefsys>
+            </srs>
+            <transparencyLevelInt>255</transparencyLevelInt>
+            <provider encoding="System">spatialite</provider>
+            <vectorjoins/>
+            <renderer-v2 attr="error" symbollevels="0" type="categorizedSymbol">
+                <categories>
+                    <category symbol="0" value="end_point" label="end_point"/>
+                    <category symbol="1" value="not_a_ring" label="not_a_ring"/>
+                    <category symbol="2" value="self_intersection" label="self_intersection"/>
+                    <category symbol="3" value="tagged_node" label="tagged_node"/>
+                    <category symbol="4" value="fixed_end_point" label="fixed_end_point"/>
+                    <category symbol="5" value="double_node" label="double_node"/>
+                    <category symbol="6" value="intersection" label="intersection"/>
+                    <category symbol="7" value="" label="(unknown)"/>
+                </categories>
+                <symbols>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="0">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="0,0,0,255"/>
+                            <prop k="name" v="rectangle"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="2"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="1">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,255,255,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="name" v="circle"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="3"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="2">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="name" v="circle"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="2.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="3">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="name" v="regular_star"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="4"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="4">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,170,0,255"/>
+                            <prop k="color_border" v="0,0,0,255"/>
+                            <prop k="name" v="rectangle"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="2"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="5">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="name" v="circle"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="3"/>
+                        </layer>
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="255,255,255,255"/>
+                            <prop k="name" v="circle"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="2"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="6">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="name" v="cross2"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="4"/>
+                        </layer>
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="5"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="name" v="cross2"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="4"/>
+                        </layer>
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="355"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="name" v="cross2"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="4"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="7">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="name" v="circle"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="2.5"/>
+                        </layer>
+                    </symbol>
+                </symbols>
+                <source-symbol>
+                    <symbol outputUnit="MM" alpha="1" type="marker" name="0">
+                        <layer pass="0" class="SimpleMarker" locked="0">
+                            <prop k="angle" v="0"/>
+                            <prop k="color" v="255,0,0,255"/>
+                            <prop k="color_border" v="0,0,0,255"/>
+                            <prop k="name" v="circle"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="size" v="2"/>
+                        </layer>
+                    </symbol>
+                </source-symbol>
+                <colorramp type="gradient" name="[source]">
+                    <prop k="color1" v="0,0,255,255"/>
+                    <prop k="color2" v="175,175,175,255"/>
+                </colorramp>
+                <rotation field=""/>
+                <sizescale field=""/>
+            </renderer-v2>
+            <customproperties>
+                <property key="labeling" value="pal"/>
+                <property key="labeling/addDirectionSymbol" value="false"/>
+                <property key="labeling/bufferColorB" value="255"/>
+                <property key="labeling/bufferColorG" value="255"/>
+                <property key="labeling/bufferColorR" value="255"/>
+                <property key="labeling/bufferSize" value="1"/>
+                <property key="labeling/dataDefinedProperty0" value=""/>
+                <property key="labeling/dataDefinedProperty1" value=""/>
+                <property key="labeling/dataDefinedProperty10" value=""/>
+                <property key="labeling/dataDefinedProperty11" value=""/>
+                <property key="labeling/dataDefinedProperty12" value=""/>
+                <property key="labeling/dataDefinedProperty13" value=""/>
+                <property key="labeling/dataDefinedProperty14" value=""/>
+                <property key="labeling/dataDefinedProperty2" value=""/>
+                <property key="labeling/dataDefinedProperty3" value=""/>
+                <property key="labeling/dataDefinedProperty4" value=""/>
+                <property key="labeling/dataDefinedProperty5" value=""/>
+                <property key="labeling/dataDefinedProperty6" value=""/>
+                <property key="labeling/dataDefinedProperty7" value=""/>
+                <property key="labeling/dataDefinedProperty8" value=""/>
+                <property key="labeling/dataDefinedProperty9" value=""/>
+                <property key="labeling/dist" value="1"/>
+                <property key="labeling/distInMapUnits" value="false"/>
+                <property key="labeling/enabled" value="false"/>
+                <property key="labeling/fieldName" value="osm_id"/>
+                <property key="labeling/fontFamily" value="Sans"/>
+                <property key="labeling/fontItalic" value="false"/>
+                <property key="labeling/fontSize" value="10"/>
+                <property key="labeling/fontSizeInMapUnits" value="false"/>
+                <property key="labeling/fontStrikeout" value="false"/>
+                <property key="labeling/fontUnderline" value="false"/>
+                <property key="labeling/fontWeight" value="50"/>
+                <property key="labeling/labelPerPart" value="false"/>
+                <property key="labeling/mergeLines" value="false"/>
+                <property key="labeling/minFeatureSize" value="0"/>
+                <property key="labeling/multiLineLabels" value="false"/>
+                <property key="labeling/obstacle" value="true"/>
+                <property key="labeling/placement" value="0"/>
+                <property key="labeling/placementFlags" value="0"/>
+                <property key="labeling/priority" value="5"/>
+                <property key="labeling/scaleMax" value="0"/>
+                <property key="labeling/scaleMin" value="0"/>
+                <property key="labeling/textColorB" value="0"/>
+                <property key="labeling/textColorG" value="0"/>
+                <property key="labeling/textColorR" value="0"/>
+            </customproperties>
+            <displayfield>osm_id</displayfield>
+            <label>0</label>
+            <labelattributes>
+                <label fieldname="" text="Label"/>
+                <family fieldname="" name="Sans"/>
+                <size fieldname="" units="pt" value="12"/>
+                <bold fieldname="" on="0"/>
+                <italic fieldname="" on="0"/>
+                <underline fieldname="" on="0"/>
+                <strikeout fieldname="" on="0"/>
+                <color fieldname="" red="0" blue="0" green="0"/>
+                <x fieldname=""/>
+                <y fieldname=""/>
+                <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+                <angle fieldname="" value="0" auto="0"/>
+                <alignment fieldname="" value="center"/>
+                <buffercolor fieldname="" red="255" blue="255" green="255"/>
+                <buffersize fieldname="" units="pt" value="1"/>
+                <bufferenabled fieldname="" on=""/>
+                <multilineenabled fieldname="" on=""/>
+                <selectedonly on=""/>
+            </labelattributes>
+            <edittypes>
+                <edittype type="0" name="OGC_FID"/>
+                <edittype type="0" name="error"/>
+                <edittype type="0" name="osm_id"/>
+            </edittypes>
+            <editform>.</editform>
+            <editforminit></editforminit>
+            <annotationform>.</annotationform>
+            <attributeactions/>
+        </maplayer>
+        <maplayer minimumScale="0" maximumScale="1e+08" geometry="Line" type="vector" hasScaleBasedVisibilityFlag="0">
+            <id>lines20120513170615065</id>
+            <datasource>dbname='./testdata.db' table="lines" (GEOMETRY) sql=</datasource>
+            <layername>lines</layername>
+            <srs>
+                <spatialrefsys>
+                    <proj4>+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs</proj4>
+                    <srsid>3452</srsid>
+                    <srid>4326</srid>
+                    <authid>EPSG:4326</authid>
+                    <description>WGS 84</description>
+                    <projectionacronym>longlat</projectionacronym>
+                    <ellipsoidacronym>WGS84</ellipsoidacronym>
+                    <geographicflag>true</geographicflag>
+                </spatialrefsys>
+            </srs>
+            <transparencyLevelInt>255</transparencyLevelInt>
+            <provider encoding="System">spatialite</provider>
+            <vectorjoins/>
+            <renderer-v2 symbollevels="0" type="singleSymbol">
+                <symbols>
+                    <symbol outputUnit="MM" alpha="1" type="line" name="0">
+                        <layer pass="7" class="SimpleLine" locked="0">
+                            <prop k="capstyle" v="round"/>
+                            <prop k="color" v="0,0,127,255"/>
+                            <prop k="customdash" v="5;2"/>
+                            <prop k="joinstyle" v="round"/>
+                            <prop k="offset" v="0"/>
+                            <prop k="penstyle" v="solid"/>
+                            <prop k="use_custom_dash" v="0"/>
+                            <prop k="width" v="0.8"/>
+                        </layer>
+                    </symbol>
+                </symbols>
+                <rotation field=""/>
+                <sizescale field=""/>
+            </renderer-v2>
+            <customproperties/>
+            <displayfield>OGC_FID</displayfield>
+            <label>0</label>
+            <labelattributes>
+                <label fieldname="" text="Label"/>
+                <family fieldname="" name="Ubuntu"/>
+                <size fieldname="" units="pt" value="12"/>
+                <bold fieldname="" on="0"/>
+                <italic fieldname="" on="0"/>
+                <underline fieldname="" on="0"/>
+                <strikeout fieldname="" on="0"/>
+                <color fieldname="" red="0" blue="0" green="0"/>
+                <x fieldname=""/>
+                <y fieldname=""/>
+                <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+                <angle fieldname="" value="0" auto="0"/>
+                <alignment fieldname="" value="center"/>
+                <buffercolor fieldname="" red="255" blue="255" green="255"/>
+                <buffersize fieldname="" units="pt" value="1"/>
+                <bufferenabled fieldname="" on=""/>
+                <multilineenabled fieldname="" on=""/>
+                <selectedonly on=""/>
+            </labelattributes>
+            <edittypes>
+                <edittype type="0" name="OGC_FID"/>
+            </edittypes>
+            <editform>.</editform>
+            <editforminit></editforminit>
+            <annotationform>.</annotationform>
+            <attributeactions/>
+        </maplayer>
+        <maplayer minimumScale="0" maximumScale="1e+08" geometry="Polygon" type="vector" hasScaleBasedVisibilityFlag="0">
+            <id>polygons20120327152822242</id>
+            <datasource>dbname='./testdata.db' table="land_polygons" (GEOMETRY) sql=</datasource>
+            <layername>land_polygons</layername>
+            <srs>
+                <spatialrefsys>
+                    <proj4>+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs</proj4>
+                    <srsid>3284</srsid>
+                    <srid>4148</srid>
+                    <authid>EPSG:4148</authid>
+                    <description>Hartebeesthoek94</description>
+                    <projectionacronym>longlat</projectionacronym>
+                    <ellipsoidacronym>WGS84</ellipsoidacronym>
+                    <geographicflag>true</geographicflag>
+                </spatialrefsys>
+            </srs>
+            <transparencyLevelInt>255</transparencyLevelInt>
+            <provider encoding="System">spatialite</provider>
+            <vectorjoins/>
+            <renderer-v2 symbollevels="0" type="singleSymbol">
+                <symbols>
+                    <symbol outputUnit="MM" alpha="0.4980392156862745" type="fill" name="0">
+                        <layer pass="0" class="SimpleFill" locked="0">
+                            <prop k="color" v="238,229,178,127"/>
+                            <prop k="color_border" v="0,0,0,127"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="style" v="solid"/>
+                            <prop k="style_border" v="no"/>
+                            <prop k="width_border" v="0.26"/>
+                        </layer>
+                    </symbol>
+                </symbols>
+                <rotation field=""/>
+                <sizescale field=""/>
+            </renderer-v2>
+            <customproperties/>
+            <displayfield>OGC_FID</displayfield>
+            <label>0</label>
+            <labelattributes>
+                <label fieldname="" text="Label"/>
+                <family fieldname="" name="Sans"/>
+                <size fieldname="" units="pt" value="12"/>
+                <bold fieldname="" on="0"/>
+                <italic fieldname="" on="0"/>
+                <underline fieldname="" on="0"/>
+                <strikeout fieldname="" on="0"/>
+                <color fieldname="" red="0" blue="0" green="0"/>
+                <x fieldname=""/>
+                <y fieldname=""/>
+                <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+                <angle fieldname="" value="0" auto="0"/>
+                <alignment fieldname="" value="center"/>
+                <buffercolor fieldname="" red="255" blue="255" green="255"/>
+                <buffersize fieldname="" units="pt" value="1"/>
+                <bufferenabled fieldname="" on=""/>
+                <multilineenabled fieldname="" on=""/>
+                <selectedonly on=""/>
+            </labelattributes>
+            <edittypes>
+                <edittype type="0" name="OGC_FID"/>
+                <edittype type="0" name="clockwise"/>
+            </edittypes>
+            <editform>.</editform>
+            <editforminit></editforminit>
+            <annotationform>.</annotationform>
+            <attributeactions/>
+        </maplayer>
+        <maplayer minimumScale="0" maximumScale="1e+08" geometry="Polygon" type="vector" hasScaleBasedVisibilityFlag="0">
+            <id>rings20120327152822288</id>
+            <datasource>dbname='./testdata.db' table="rings" (GEOMETRY) sql=</datasource>
+            <layername>rings</layername>
+            <srs>
+                <spatialrefsys>
+                    <proj4>+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs</proj4>
+                    <srsid>3284</srsid>
+                    <srid>4148</srid>
+                    <authid>EPSG:4148</authid>
+                    <description>Hartebeesthoek94</description>
+                    <projectionacronym>longlat</projectionacronym>
+                    <ellipsoidacronym>WGS84</ellipsoidacronym>
+                    <geographicflag>true</geographicflag>
+                </spatialrefsys>
+            </srs>
+            <transparencyLevelInt>255</transparencyLevelInt>
+            <provider encoding="System">spatialite</provider>
+            <vectorjoins/>
+            <renderer-v2 attr="valid" symbollevels="0" type="categorizedSymbol">
+                <categories>
+                    <category symbol="0" value="0" label="not valid"/>
+                    <category symbol="1" value="1" label="valid"/>
+                </categories>
+                <symbols>
+                    <symbol outputUnit="MM" alpha="1" type="fill" name="0">
+                        <layer pass="0" class="SimpleFill" locked="0">
+                            <prop k="color" v="0,0,255,255"/>
+                            <prop k="color_border" v="255,0,0,255"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="style" v="no"/>
+                            <prop k="style_border" v="dot"/>
+                            <prop k="width_border" v="0.5"/>
+                        </layer>
+                    </symbol>
+                    <symbol outputUnit="MM" alpha="1" type="fill" name="1">
+                        <layer pass="0" class="SimpleFill" locked="0">
+                            <prop k="color" v="87,87,215,255"/>
+                            <prop k="color_border" v="0,170,0,255"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="style" v="no"/>
+                            <prop k="style_border" v="dot"/>
+                            <prop k="width_border" v="0.5"/>
+                        </layer>
+                    </symbol>
+                </symbols>
+                <source-symbol>
+                    <symbol outputUnit="MM" alpha="1" type="fill" name="0">
+                        <layer pass="0" class="SimpleFill" locked="0">
+                            <prop k="color" v="227,8,184,255"/>
+                            <prop k="color_border" v="0,0,0,255"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="style" v="solid"/>
+                            <prop k="style_border" v="solid"/>
+                            <prop k="width_border" v="0.26"/>
+                        </layer>
+                    </symbol>
+                </source-symbol>
+                <colorramp type="gradient" name="[source]">
+                    <prop k="color1" v="0,0,255,255"/>
+                    <prop k="color2" v="175,175,175,255"/>
+                </colorramp>
+                <rotation field=""/>
+                <sizescale field=""/>
+            </renderer-v2>
+            <customproperties/>
+            <displayfield>osm_id</displayfield>
+            <label>0</label>
+            <labelattributes>
+                <label fieldname="" text="Label"/>
+                <family fieldname="" name="Sans"/>
+                <size fieldname="" units="pt" value="12"/>
+                <bold fieldname="" on="0"/>
+                <italic fieldname="" on="0"/>
+                <underline fieldname="" on="0"/>
+                <strikeout fieldname="" on="0"/>
+                <color fieldname="" red="0" blue="0" green="0"/>
+                <x fieldname=""/>
+                <y fieldname=""/>
+                <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+                <angle fieldname="" value="0" auto="0"/>
+                <alignment fieldname="" value="center"/>
+                <buffercolor fieldname="" red="255" blue="255" green="255"/>
+                <buffersize fieldname="" units="pt" value="1"/>
+                <bufferenabled fieldname="" on=""/>
+                <multilineenabled fieldname="" on=""/>
+                <selectedonly on=""/>
+            </labelattributes>
+            <edittypes>
+                <edittype type="0" name="OGC_FID"/>
+                <edittype type="0" name="land"/>
+                <edittype type="0" name="npoints"/>
+                <edittype type="0" name="nways"/>
+                <edittype type="0" name="osm_id"/>
+                <edittype type="0" name="valid"/>
+            </edittypes>
+            <editform>.</editform>
+            <editforminit></editforminit>
+            <annotationform>.</annotationform>
+            <attributeactions/>
+        </maplayer>
+        <maplayer minimumScale="0" maximumScale="1e+08" geometry="Polygon" type="vector" hasScaleBasedVisibilityFlag="0">
+            <id>water_polygons20120521162144305</id>
+            <datasource>dbname='./testdata.db' table="water_polygons" (GEOMETRY) sql=</datasource>
+            <layername>water_polygons</layername>
+            <srs>
+                <spatialrefsys>
+                    <proj4>+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs</proj4>
+                    <srsid>3452</srsid>
+                    <srid>4326</srid>
+                    <authid>EPSG:4326</authid>
+                    <description>WGS 84</description>
+                    <projectionacronym>longlat</projectionacronym>
+                    <ellipsoidacronym>WGS84</ellipsoidacronym>
+                    <geographicflag>true</geographicflag>
+                </spatialrefsys>
+            </srs>
+            <transparencyLevelInt>255</transparencyLevelInt>
+            <provider encoding="System">spatialite</provider>
+            <vectorjoins/>
+            <renderer-v2 symbollevels="0" type="singleSymbol">
+                <symbols>
+                    <symbol outputUnit="MM" alpha="1" type="fill" name="0">
+                        <layer pass="0" class="SimpleFill" locked="0">
+                            <prop k="color" v="219,237,255,255"/>
+                            <prop k="color_border" v="0,0,0,255"/>
+                            <prop k="offset" v="0,0"/>
+                            <prop k="style" v="solid"/>
+                            <prop k="style_border" v="no"/>
+                            <prop k="width_border" v="0.26"/>
+                        </layer>
+                    </symbol>
+                </symbols>
+                <rotation field=""/>
+                <sizescale field=""/>
+            </renderer-v2>
+            <customproperties/>
+            <displayfield>OGC_FID</displayfield>
+            <label>0</label>
+            <labelattributes>
+                <label fieldname="" text="Label"/>
+                <family fieldname="" name="Sans"/>
+                <size fieldname="" units="pt" value="12"/>
+                <bold fieldname="" on="0"/>
+                <italic fieldname="" on="0"/>
+                <underline fieldname="" on="0"/>
+                <strikeout fieldname="" on="0"/>
+                <color fieldname="" red="0" blue="0" green="0"/>
+                <x fieldname=""/>
+                <y fieldname=""/>
+                <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+                <angle fieldname="" value="0" auto="0"/>
+                <alignment fieldname="" value="center"/>
+                <buffercolor fieldname="" red="255" blue="255" green="255"/>
+                <buffersize fieldname="" units="pt" value="1"/>
+                <bufferenabled fieldname="" on=""/>
+                <multilineenabled fieldname="" on=""/>
+                <selectedonly on=""/>
+            </labelattributes>
+            <edittypes>
+                <edittype type="0" name="OGC_FID"/>
+            </edittypes>
+            <editform>.</editform>
+            <editforminit></editforminit>
+            <annotationform>.</annotationform>
+            <attributeactions/>
+        </maplayer>
+    </projectlayers>
+    <properties>
+        <SpatialRefSys>
+            <ProjectCrs type="QString">EPSG:4326</ProjectCrs>
+        </SpatialRefSys>
+        <Paths>
+            <Absolute type="bool">false</Absolute>
+        </Paths>
+        <Gui>
+            <SelectionColorBluePart type="int">0</SelectionColorBluePart>
+            <CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
+            <CanvasColorRedPart type="int">255</CanvasColorRedPart>
+            <SelectionColorRedPart type="int">255</SelectionColorRedPart>
+            <SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
+            <SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
+            <CanvasColorBluePart type="int">255</CanvasColorBluePart>
+        </Gui>
+        <PositionPrecision>
+            <DecimalPlaces type="int">2</DecimalPlaces>
+            <Automatic type="bool">true</Automatic>
+        </PositionPrecision>
+    </properties>
+</qgis>
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..bb302c1
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,35 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake Config
+#
+#  OSMCoastline documentation
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring documentation")
+
+message(STATUS "Looking for doxygen")
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+    message(STATUS "Looking for doxygen - found")
+    configure_file(header.html ${CMAKE_CURRENT_BINARY_DIR}/header.html @ONLY)
+    configure_file(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+    add_custom_target(doc
+        ${DOXYGEN_EXECUTABLE}
+        ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+        COMMENT "Generating API documentation with Doxygen" VERBATIM
+    )
+#    install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html"
+#            DESTINATION "share/doc/libosmium-dev")
+else()
+    message(STATUS "Looking for doxygen - not found")
+    message(STATUS "  Disabled making of documentation.")
+endif()
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring documentation - done")
+
+
+#-----------------------------------------------------------------------------
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000..efb6f22
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,2312 @@
+# Doxyfile 1.8.7
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "OSMCoastline"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = @OSMCOASTLINE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = "@PROJECT_BINARY_DIR@/doc"
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @PROJECT_SOURCE_DIR@
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.hpp *.cpp
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+#DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/doc/header.html b/doc/header.html
new file mode 100644
index 0000000..495d500
--- /dev/null
+++ b/doc/header.html
@@ -0,0 +1,56 @@
+<!-- HTML header for doxygen 1.8.8-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="viewport" content="width=device-width, initial-scale=1"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <!--BEGIN PROJECT_LOGO-->
+  <td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
+  <!--END PROJECT_LOGO-->
+  <!--BEGIN PROJECT_NAME-->
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">$projectname
+   <!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+   </div>
+   <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+  </td>
+  <!--END PROJECT_NAME-->
+  <!--BEGIN !PROJECT_NAME-->
+   <!--BEGIN PROJECT_BRIEF-->
+    <td style="padding-left: 0.5em;">
+    <div id="projectbrief">$projectbrief</div>
+    </td>
+   <!--END PROJECT_BRIEF-->
+  <!--END !PROJECT_NAME-->
+  <!--BEGIN DISABLE_INDEX-->
+   <!--BEGIN SEARCHENGINE-->
+   <td>$searchbox</td>
+   <!--END SEARCHENGINE-->
+  <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/ogr_include.hpp b/ogr_include.hpp
new file mode 100644
index 0000000..d372d6a
--- /dev/null
+++ b/ogr_include.hpp
@@ -0,0 +1,42 @@
+#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/options.cpp b/options.cpp
new file mode 100644
index 0000000..ae99b0d
--- /dev/null
+++ b/options.cpp
@@ -0,0 +1,197 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <iostream>
+#include <string>
+#include <cstring>
+#include <cstdlib>
+#include <getopt.h>
+
+#include "osmcoastline.hpp"
+#include "options.hpp"
+
+Options::Options(int argc, char* argv[]) :
+    inputfile(),
+    bbox_overlap(-1),
+    close_distance(1.0),
+    close_rings(true),
+    create_index(true),
+    debug(false),
+    max_points_in_polygon(1000),
+    split_large_polygons(true),
+    output_polygons(output_polygon_type::land),
+    output_database(),
+    overwrite_output(false),
+    output_rings(false),
+    output_lines(false),
+    epsg(4326),
+    simplify(false),
+    tolerance(0),
+    verbose(false)
+{
+    static struct option long_options[] = {
+        {"bbox-overlap",    required_argument, 0, 'b'},
+        {"close-distance",  required_argument, 0, 'c'},
+        {"no-index",              no_argument, 0, 'i'},
+        {"debug",                 no_argument, 0, 'd'},
+        {"help",                  no_argument, 0, 'h'},
+        {"output-lines",          no_argument, 0, 'l'},
+        {"max-points",      required_argument, 0, 'm'},
+        {"output-database", required_argument, 0, 'o'},
+        {"output-polygons", required_argument, 0, 'p'},
+        {"output-rings",          no_argument, 0, 'r'},
+        {"overwrite",             no_argument, 0, 'f'},
+        {"srs",             required_argument, 0, 's'},
+        {"verbose",               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);
+        if (c == -1)
+            break;
+
+        switch (c) {
+            case 'b':
+                bbox_overlap = atof(optarg);
+                break;
+            case 'c':
+                close_distance = atoi(optarg);
+                if (close_distance == 0) {
+                    close_rings = false;
+                }
+                break;
+            case 'i':
+                create_index = false;
+                break;
+            case 'd':
+                debug = true;
+                std::cerr << "Enabled debug option\n";
+                break;
+            case 'h':
+                print_help();
+                exit(return_code_ok);
+            case 'l':
+                output_lines = true;
+                break;
+            case 'm':
+                max_points_in_polygon = atoi(optarg);
+                if (max_points_in_polygon == 0) {
+                    split_large_polygons = false;
+                }
+                break;
+            case 'p':
+                if (!strcmp(optarg, "none")) {
+                    output_polygons = output_polygon_type::none;
+                } else if (!strcmp(optarg, "land")) {
+                    output_polygons = output_polygon_type::land;
+                } else if (!strcmp(optarg, "water")) {
+                    output_polygons = output_polygon_type::water;
+                } else if (!strcmp(optarg, "both")) {
+                    output_polygons = output_polygon_type::both;
+                } else {
+                    std::cerr << "Unknown argument '" << optarg << "' for -p/--output-polygon option\n";
+                    exit(return_code_cmdline);
+                }
+                break;
+            case 'o':
+                output_database = optarg;
+                break;
+            case 'r':
+                output_rings = true;
+                break;
+            case 'f':
+                overwrite_output = true;
+                break;
+            case 's':
+                epsg = get_epsg(optarg);
+                break;
+            case 'v':
+                verbose = true;
+                break;
+            default:
+                exit(return_code_cmdline);
+        }
+    }
+
+    if (!split_large_polygons && (output_polygons == output_polygon_type::water || output_polygons == output_polygon_type::both)) {
+        std::cerr << "Can not use -m/--max-points=0 when writing out water polygons\n";
+        exit(return_code_cmdline);
+    }
+
+    if (optind != argc - 1) {
+        std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n";
+        exit(return_code_cmdline);
+    }
+
+    if (output_database.empty()) {
+        std::cerr << "Missing --output-database/-o option.\n";
+        exit(return_code_cmdline);
+    }
+
+    if (bbox_overlap == -1) {
+        if (epsg == 4326) {
+            bbox_overlap = 0.0001;
+        } else {
+            bbox_overlap = 10;
+        }
+    }
+
+    inputfile = argv[optind];
+}
+
+int Options::get_epsg(const char* text) {
+    if (!strcasecmp(text, "WGS84") || !strcmp(text, "4326")) {
+        return 4326;
+    }
+    if (!strcmp(text, "3857")) {
+        return 3857;
+    }
+    if (!strcmp(text, "3785") || !strcmp(text, "900913")) {
+        std::cerr << "Please use code 3857 for the 'Google Mercator' projection!\n";
+        exit(return_code_cmdline);
+    }
+    std::cerr << "Unknown SRS '" << text << "'. Currently only 4326 (WGS84) and 3857 ('Google Mercator') are supported.\n";
+    exit(return_code_cmdline);
+}
+
+void Options::print_help() const {
+    std::cout << "osmcoastline [OPTIONS] OSMFILE\n"
+                << "\nOptions:\n"
+                << "  -h, --help                 - This help message\n"
+                << "  -c, --close-distance=DIST  - Distance between nodes under which open rings\n"
+                << "                               are closed (0 - disable closing of rings)\n"
+                << "  -b, --bbox-overlap=OVERLAP - Set overlap when splitting polygons\n"
+                << "  -i, --no-index             - Do not create spatial indexes in output db\n"
+                << "  -d, --debug                - Enable debugging output\n"
+                << "  -f, --overwrite            - Overwrite output file if it already exists\n"
+                << "  -l, --output-lines         - Output coastlines as lines to database file\n"
+                << "  -m, --max-points=NUM       - Split lines/polygons with more than this many\n"
+                << "                               points (0 - disable splitting)\n"
+                << "  -o, --output-database=FILE - Spatialite database file for output\n"
+                << "  -p, --output-polygons=land|water|both|none\n"
+                << "                             - Which polygons to write out (default: land)\n"
+                << "  -r, --output-rings         - Output rings to database file\n"
+                << "  -s, --srs=EPSGCODE         - Set SRS (4326 for WGS84 (default) or 3857)\n"
+                << "  -v, --verbose              - Verbose output\n"
+                << "\n";
+}
+
diff --git a/options.hpp b/options.hpp
new file mode 100644
index 0000000..acfd094
--- /dev/null
+++ b/options.hpp
@@ -0,0 +1,110 @@
+#ifndef OPTIONS_HPP
+#define OPTIONS_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <string>
+
+enum class output_polygon_type {
+    none  = 0,
+    land  = 1,
+    water = 2,
+    both  = 3
+};
+
+/**
+ * This class encapsulates the command line parsing.
+ */
+class Options {
+
+public:
+
+    /// Input OSM file name.
+    std::string inputfile;
+
+    /// Overlap when splitting polygons.
+    double bbox_overlap;
+
+    /**
+     * If the distance between two ring-endnodes is smaller than this the ring
+     * can be closed there.
+     */
+    double close_distance;
+
+    /// Attempt to close unclosed rings?
+    bool close_rings;
+
+    /// Add spatial index to Spatialite database tables?
+    bool create_index;
+
+    /// Show debug output?
+    bool debug;
+
+    /// Maximum number of points in polygons.
+    int max_points_in_polygon;
+
+    /// Should large polygons be split?
+    bool split_large_polygons;
+
+    /// What polygons should be written out?
+    output_polygon_type output_polygons;
+
+    /// Output Spatialite database file name.
+    std::string output_database;
+
+    /// Should output database be overwritten
+    bool overwrite_output;
+
+    /// Should the rings output table be populated?
+    bool output_rings;
+
+    /// Should the lines output table be populated?
+    bool output_lines;
+
+    /// EPSG code of output SRS.
+    int epsg;
+
+    /// Should the coastline be simplified?
+    bool simplify;
+
+    /// Tolerance for simplification
+    double tolerance;
+
+    /// Verbose output?
+    bool verbose;
+
+    Options(int argc, char* argv[]);
+
+private:
+
+    /**
+     * Get EPSG code from text. This method knows about a few common cases
+     * of specifying WGS84 or the "Google mercator" SRS. More are currently
+     * not supported.
+     */
+    int get_epsg(const char* text);
+
+    void print_help() const;
+
+};
+
+#endif // OPTIONS_HPP
diff --git a/osmcoastline.cpp b/osmcoastline.cpp
new file mode 100644
index 0000000..cd04804
--- /dev/null
+++ b/osmcoastline.cpp
@@ -0,0 +1,324 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <fstream>
+#include <list>
+#include <time.h>
+#include <unistd.h>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/visitor.hpp>
+
+#include "osmcoastline.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 "verbose_output.hpp"
+
+// The global SRS object is used in many places to transform
+// from WGS84 to the output SRS etc.
+SRS srs;
+
+// Global debug marker
+bool debug;
+
+// If there are more than this many warnings, the program exit code will indicate an error.
+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);
+
+    int is_valid;
+    const char* options[] = { "METHOD=ONLY_CCW", nullptr };
+    if (debug) {
+        std::cerr << "Calling organizePolygons()\n";
+    }
+    std::unique_ptr<OGRGeometry> mega_geometry { OGRGeometryFactory::organizePolygons(&all_polygons[0], all_polygons.size(), &is_valid, options) };
+    if (debug) {
+        std::cerr << "organizePolygons() done\n";
+    }
+
+    assert(mega_geometry->getGeometryType() == wkbMultiPolygon);
+    OGRMultiPolygon* mega_multipolygon = static_cast<OGRMultiPolygon*>(mega_geometry.get());
+
+    polygon_vector_type polygons;
+    polygons.reserve(mega_multipolygon->getNumGeometries());
+    for (int i=0; i < mega_multipolygon->getNumGeometries(); ++i) {
+        OGRGeometry* geom = mega_multipolygon->getGeometryRef(i);
+        assert(geom->getGeometryType() == wkbPolygon);
+        std::unique_ptr<OGRPolygon> p { static_cast<OGRPolygon*>(geom) };
+        if (p->IsValid()) {
+            polygons.push_back(p.release());
+        } else {
+            output.add_error_line(static_cast<OGRLineString*>(p->getExteriorRing()->clone()), "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()));
+                (*warnings)++;
+            } else {
+                std::cerr << "Ignoring invalid polygon geometry.\n";
+                (*errors)++;
+            }
+        }
+    }
+
+    mega_multipolygon->removeGeometry(-1, FALSE);
+
+    return polygons;
+}
+
+
+/* ================================================== */
+
+std::pair<int, int> get_memory_usage() {
+    char filename[100];
+    sprintf(filename, "/proc/%d/status", getpid());
+    std::ifstream status_file(filename);
+    std::string line;
+
+    int vmpeak = 0;
+    int vmsize = 0;
+    if (status_file.is_open()) {
+        while (! status_file.eof() ) {
+            std::getline(status_file, line);
+            if (line.substr(0, 6) == "VmPeak") {
+                int f = line.find_first_of("0123456789");
+                int l = line.find_last_of("0123456789");
+                vmpeak = atoi(line.substr(f, l-f+1).c_str());
+            }
+            if (line.substr(0, 6) == "VmSize") {
+                int f = line.find_first_of("0123456789");
+                int l = line.find_last_of("0123456789");
+                vmsize = atoi(line.substr(f, l-f+1).c_str());
+            }
+        }
+        status_file.close();
+    }
+
+    return std::make_pair(vmsize / 1024, vmpeak / 1024);
+}
+
+std::string memory_usage() {
+    std::pair<int, int> mem = get_memory_usage();
+    std::ostringstream s;
+    s << "Memory used currently: " << mem.first << " MB (Peak was: " << mem.second << " MB).\n";
+    return s.str();
+}
+
+/* ================================================== */
+
+int main(int argc, char *argv[]) {
+    Stats stats;
+    unsigned int warnings = 0;
+    unsigned int errors = 0;
+
+    // Parse command line and setup 'options' object with them.
+    Options options(argc, argv);
+
+    // The vout object is an output stream we can write to instead of
+    // std::cerr. Nothing is written if we are not in verbose mode.
+    // The running time will be prepended to output lines.
+    VerboseOutput vout(options.verbose);
+
+    debug = options.debug;
+
+    CPLSetConfigOption("OGR_ENABLE_PARTIAL_REPROJECTION", "TRUE");
+    vout << "Using SRS " << options.epsg << " for output. (Change with the --srs/s option.)\n";
+    if (!srs.set_output(options.epsg)) {
+        std::cerr << "Setting up output transformation failed\n";
+        exit(return_code_fatal);
+    }
+
+    // Set up output database.
+    vout << "Writing to output database '" << options.output_database << "'. (Was set with the --output-database/-o option.)\n";
+    if (options.overwrite_output) {
+        vout << "Removing database output file (if it exists) (because you told me to with --overwrite/-f).\n";
+        unlink(options.output_database.c_str());
+    }
+    if (options.create_index) {
+        vout << "Will create geometry index. (If you do not want an index use --no-index/-i.)\n";
+    } 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);
+
+    // The collection of all coastline rings we will be filling and then
+    // operating on.
+    CoastlineRingCollection coastline_rings;
+
+    {
+        // This is in an extra scope so that the considerable amounts of memory
+        // held by the handlers is recovered after we don't need them any more.
+        vout << "Reading from file '" << options.inputfile << "'.\n";
+        osmium::io::File infile(options.inputfile);
+
+        vout << "Reading ways (1st pass through input file)...\n";
+        CoastlineHandlerPass1 handler_pass1(coastline_rings);
+        osmium::io::Reader reader1(infile, osmium::osm_entity_bits::way);
+        osmium::apply(reader1, handler_pass1);
+        reader1.close();
+        stats.ways = coastline_rings.num_ways();
+        stats.unconnected_nodes = coastline_rings.num_unconnected_nodes();
+        stats.rings = coastline_rings.size();
+        stats.rings_from_single_way = coastline_rings.num_rings_from_single_way();
+        vout << "  There are " << coastline_rings.num_unconnected_nodes() << " nodes where the coastline is not closed.\n";
+        vout << "  There are " << coastline_rings.size() << " coastline rings ("
+             << coastline_rings.num_rings_from_single_way() << " from a single way and "
+             << coastline_rings.size() - coastline_rings.num_rings_from_single_way() << " from multiple ways).\n";
+        vout << memory_usage();
+
+        vout << "Reading nodes (2nd pass through input file)...\n";
+        CoastlineHandlerPass2 handler_pass2(coastline_rings, output_database);
+        osmium::io::Reader reader2(infile, osmium::osm_entity_bits::node);
+        osmium::apply(reader2, handler_pass2);
+        reader2.close();
+    }
+
+    vout << "Checking for missing positions...\n";
+    unsigned int missing_positions = coastline_rings.check_positions(options.debug);
+    if (missing_positions) {
+        vout << "  There are " << missing_positions << " positions missing. Check that input file contains all nodes needed.\n";
+        exit(return_code_error);
+    } else {
+        vout << "  All positions are there.\n";
+    }
+
+    vout << memory_usage();
+
+    output_database.set_options(options);
+
+    vout << "Check line segments for intersections and overlaps...\n";
+    warnings += coastline_rings.check_for_intersections(output_database);
+
+    vout << "Trying to close Antarctica ring...\n";
+    if (coastline_rings.close_antarctica_ring(options.epsg)) {
+        vout << "  Closed Antarctica ring.\n";
+    } else {
+        vout << "  Did not find open Antarctica ring.\n";
+    }
+
+    if (options.close_rings) {
+        vout << "Close broken rings... (Use --close-distance/-c 0 if you do not want this.)\n";
+        vout << "  Closing if distance between nodes smaller than " << options.close_distance << ". (Set this with --close-distance/-c.)\n";
+        coastline_rings.close_rings(output_database, options.debug, options.close_distance);
+        stats.rings_fixed = coastline_rings.num_fixed_rings();
+        warnings += coastline_rings.num_fixed_rings();
+        vout << "  Closed " << coastline_rings.num_fixed_rings() << " rings. This left "
+            << coastline_rings.num_unconnected_nodes() << " nodes where the coastline could not be closed.\n";
+        errors += coastline_rings.num_unconnected_nodes();
+    } else {
+        vout << "Not closing broken rings (because you used the option --close-distance/-c 0).\n";
+    }
+
+    if (options.output_rings) {
+        vout << "Writing out rings... (Because you gave the --output-rings/-r option.)\n";
+        warnings += coastline_rings.output_rings(output_database);
+    } else {
+        vout << "Not writing out rings. (Use option --output-rings/-r if you want the rings.)\n";
+    }
+
+    if (options.output_polygons != output_polygon_type::none) {
+        vout << "Create polygons...\n";
+        CoastlinePolygons coastline_polygons(create_polygons(coastline_rings, output_database, &warnings, &errors), output_database, options.bbox_overlap, options.max_points_in_polygon);
+        stats.land_polygons_before_split = coastline_polygons.num_polygons();
+
+        vout << "Fixing coastlines going the wrong way...\n";
+        stats.rings_turned_around = coastline_polygons.fix_direction();
+        vout << "  Turned " << stats.rings_turned_around << " polygons around.\n";
+        warnings += stats.rings_turned_around;
+
+        if (options.epsg != 4326) {
+            vout << "Transforming polygons to EPSG " << options.epsg << "...\n";
+            coastline_polygons.transform();
+        }
+
+        if (options.output_lines) {
+            vout << "Writing coastlines as lines... (Because you used --output-lines/-l)\n";
+            coastline_polygons.output_lines(options.max_points_in_polygon);
+        } else {
+            vout << "Not writing coastlines as lines (Use --output-lines/-l if you want this).\n";
+        }
+
+        if (options.epsg == 4326) {
+            vout << "Checking for questionable input data...\n";
+            unsigned int questionable = coastline_rings.output_questionable(coastline_polygons, output_database);
+            warnings += questionable;
+            vout << "  Found " << questionable << " rings in input data.\n";
+        } else {
+            vout << "Not performing check for questionable input data, because it only works in EPSG:4326...\n";
+        }
+
+        if (options.split_large_polygons) {
+            vout << "Split polygons with more than " << options.max_points_in_polygon << " points... (Use --max-points/-m to change this. Set to 0 not to split at all.)\n";
+            vout << "  Using overlap of " << options.bbox_overlap << " (Set this with --bbox-overlap/-b).\n";
+            coastline_polygons.split();
+            stats.land_polygons_after_split = coastline_polygons.num_polygons();
+        }
+        if (options.output_polygons == output_polygon_type::land ||
+            options.output_polygons == output_polygon_type::both) {
+            vout << "Writing out land polygons...\n";
+            coastline_polygons.output_land_polygons(options.output_polygons == output_polygon_type::both);
+        }
+        if (options.output_polygons == output_polygon_type::water ||
+            options.output_polygons == output_polygon_type::both) {
+            vout << "Writing out water polygons...\n";
+            warnings += coastline_polygons.output_water_polygons();
+        }
+    } else {
+        vout << "Not creating polygons (Because you set the --no-polygons/-p option).\n";
+    }
+
+    vout << memory_usage();
+
+    vout << "Committing database transactions...\n";
+    output_database.set_meta(vout.runtime(), get_memory_usage().second, stats);
+    output_database.commit();
+    vout << "All done.\n";
+    vout << memory_usage();
+
+    std::cout << "There were " << warnings << " warnings.\n";
+    std::cout << "There were " << errors << " errors.\n";
+
+    google::protobuf::ShutdownProtobufLibrary();
+
+    if (errors || warnings > max_warnings) {
+        return return_code_error;
+    } else if (warnings) {
+        return return_code_warning;
+    } else {
+        return return_code_ok;
+    }
+}
+
diff --git a/osmcoastline.hpp b/osmcoastline.hpp
new file mode 100644
index 0000000..27abac2
--- /dev/null
+++ b/osmcoastline.hpp
@@ -0,0 +1,33 @@
+#ifndef OSMCOASTLINE_HPP
+#define OSMCOASTLINE_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+enum return_codes {
+    return_code_ok      = 0,
+    return_code_warning = 1,
+    return_code_error   = 2,
+    return_code_fatal   = 3,
+    return_code_cmdline = 4
+};
+
+#endif // OSMCOASTLINE_HPP
diff --git a/osmcoastline_filter.cpp b/osmcoastline_filter.cpp
new file mode 100644
index 0000000..579d5a0
--- /dev/null
+++ b/osmcoastline_filter.cpp
@@ -0,0 +1,142 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <iostream>
+#include <set>
+#include <getopt.h>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/io/pbf_output.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/osm/entity_bits.hpp>
+
+#include "osmcoastline.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"
+              << "\n";
+}
+
+int main(int argc, char* argv[]) {
+    std::string output_filename;
+
+    static struct option long_options[] = {
+        {"help",         no_argument, 0, 'h'},
+        {"output", required_argument, 0, 'o'},
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        int c = getopt_long(argc, argv, "ho:", long_options, 0);
+        if (c == -1)
+            break;
+
+        switch (c) {
+            case 'h':
+                print_help();
+                exit(return_code_ok);
+            case 'o':
+                output_filename = optarg;
+                break;
+            default:
+                exit(return_code_fatal);
+        }
+    }
+
+    if (output_filename.empty()) {
+        std::cerr << "Missing -o/--output=OSMFILE option\n";
+        exit(return_code_cmdline);
+    }
+
+    if (optind != argc - 1) {
+        std::cerr << "Usage: osmcoastline_filter [OPTIONS] OSMFILE\n";
+        exit(return_code_cmdline);
+    }
+
+    osmium::io::Header header;
+    header.set("generator", "osmcoastline_filter");
+    header.add_box(osmium::Box(-180.0, -90.0, 180.0, 90.0));
+
+    osmium::io::File infile(argv[optind]);
+
+    try {
+        osmium::io::Writer writer(output_filename, header);
+
+        std::set<osmium::object_id_type> ids;
+        osmium::memory::Buffer output_buffer(10240);
+
+        {
+            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());
+                        }
+                    }
+                }
+            }
+            reader.close();
+        }
+
+        {
+            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));
+                        }
+                    }
+                }
+            }
+            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";
+        exit(return_code_fatal);
+    }
+
+    google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/osmcoastline_readmeta.sh b/osmcoastline_readmeta.sh
new file mode 100755
index 0000000..14f04be
--- /dev/null
+++ b/osmcoastline_readmeta.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+#
+#  osmcoastline_readmeta.sh [COASTLINEDB]
+#
+
+if [ "x$1" = "x" ]; then
+    DBFILE=testdata.db
+else
+    DBFILE=$1
+fi
+
+if [ ! -e $DBFILE ]; then
+    echo "Can't open '$DBFILE'"
+    exit 1
+fi
+
+echo "Options used to create this data:\n"
+
+echo -n "  Overlap (--bbox-overlap/-b): "
+sqlite3 $DBFILE "SELECT overlap FROM options;"
+
+echo -n "  Close gaps in coastline smaller than (--close-distance/-c): "
+sqlite3 $DBFILE "SELECT close_distance FROM options;"
+
+echo -n "  Max points in polygons (--max-points/-m): "
+sqlite3 $DBFILE "SELECT max_points_in_polygons FROM options;"
+
+echo -n "  Split large polygons: "
+sqlite3 $DBFILE "SELECT CASE split_large_polygons WHEN 0 THEN 'no' ELSE 'yes' END FROM options;"
+
+echo -n "  Spatial reference system (--srid/-s): "
+sqlite3 $DBFILE "SELECT CASE srid WHEN 4326 THEN '4326 (WGS84)' WHEN 3857 THEN '3857 (Mercator)' ELSE srid END FROM geometry_columns WHERE f_table_name='land_polygons';"
+
+echo "\nMetadata:\n"
+
+echo -n "  Database created at: "
+sqlite3 $DBFILE "SELECT timestamp FROM meta;"
+
+echo -n "  Runtime (minutes): "
+sqlite3 $DBFILE "SELECT CAST(round(CAST(runtime AS REAL)/60) AS INT) FROM meta;"
+
+echo -n "  Memory usage (MB): "
+sqlite3 $DBFILE "SELECT memory_usage FROM meta;"
+
+echo -n "  Ways tagged natural=coastline: "
+sqlite3 $DBFILE "SELECT num_ways FROM meta;"
+
+echo -n "  Number of nodes where coastline is not closed (before fixing): "
+sqlite3 $DBFILE "SELECT num_unconnected_nodes FROM meta;"
+
+echo -n "  Coastline rings: "
+sqlite3 $DBFILE "SELECT num_rings FROM meta;"
+
+echo -n "  Coastline rings created from a single way: "
+sqlite3 $DBFILE "SELECT num_rings_from_single_way FROM meta;"
+
+echo -n "  Coastline rings created from more then one way: "
+sqlite3 $DBFILE "SELECT num_rings - num_rings_from_single_way FROM meta;"
+
+echo -n "  Number of rings fixed (closed): "
+sqlite3 $DBFILE "SELECT num_rings_fixed FROM meta;"
+
+echo -n "  Number of rings turned around: "
+sqlite3 $DBFILE "SELECT num_rings_turned_around FROM meta;"
+
+echo -n "  Number of land polygons before split: "
+sqlite3 $DBFILE "SELECT num_land_polygons_before_split FROM meta;"
+
+echo -n "  Number of land polygons after split: "
+sqlite3 $DBFILE "SELECT CASE num_land_polygons_after_split WHEN 0 THEN 'NOT SPLIT' ELSE num_land_polygons_after_split END FROM meta;"
+
+echo "\nErrors/warnings (Points):\n"
+echo ".width 3 20\nSELECT count(*), error FROM error_points GROUP BY error;" | sqlite3 -column $DBFILE | sed -e 's/^/  /'
+
+echo "\nErrors/warnings (LineStrings):\n"
+echo ".width 3 20\nSELECT count(*), error FROM error_lines GROUP BY error;" | sqlite3 -column $DBFILE | sed -e 's/^/  /'
+
+echo "\nOutput:\n"
+echo "SELECT count(*), 'land_polygons' FROM land_polygons;" | sqlite3 -column $DBFILE | sed -e 's/^/  /'
+echo "SELECT count(*), 'water_polygons' FROM water_polygons;" | sqlite3 -column $DBFILE | sed -e 's/^/  /'
+echo "SELECT count(*), 'lines' FROM lines;" | sqlite3 -column $DBFILE | sed -e 's/^/  /'
+echo "SELECT count(*), 'rings' FROM rings;" | sqlite3 -column $DBFILE | sed -e 's/^/  /'
+
+echo
+
diff --git a/osmcoastline_ways.cpp b/osmcoastline_ways.cpp
new file mode 100644
index 0000000..c27c28b
--- /dev/null
+++ b/osmcoastline_ways.cpp
@@ -0,0 +1,165 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <iostream>
+#include <set>
+
+#include <osmium/geom/haversine.hpp>
+#include <osmium/geom/ogr.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/index/map/sparse_mem_array.hpp>
+#include <osmium/io/any_input.hpp>
+#include <osmium/visitor.hpp>
+
+#include "ogr_include.hpp"
+#include "osmcoastline.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;
+
+class CoastlineWaysHandler : public osmium::handler::Handler {
+
+    double m_length;
+
+    std::unique_ptr<OGRDataSource, OGRDataSourceDestroyer> m_data_source;
+    OGRLayer* m_layer_ways;
+
+    osmium::geom::OGRFactory<> m_factory;
+
+public:
+
+    CoastlineWaysHandler() :
+        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("coastline-ways.db", 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();
+    }
+
+    ~CoastlineWaysHandler() {
+        m_layer_ways->CommitTransaction();
+    }
+
+    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"));
+
+            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);
+        } catch (osmium::geometry_error&) {
+            std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
+        }
+    }
+
+    double sum_length() const {
+        return m_length;
+    }
+
+};
+
+int main(int argc, char* argv[]) {
+    if (argc != 2) {
+        std::cerr << "Usage: osmcoastline_ways OSMFILE\n";
+        exit(return_code_cmdline);
+    }
+
+    index_type store_pos;
+    index_type store_neg;
+    node_location_handler_type location_handler(store_pos, store_neg);
+
+    osmium::io::File infile(argv[1]);
+    osmium::io::Reader reader1(infile, osmium::osm_entity_bits::node);
+    osmium::apply(reader1, location_handler);
+    reader1.close();
+
+    CoastlineWaysHandler coastline_ways_handler;
+    osmium::io::Reader reader2(infile, osmium::osm_entity_bits::way);
+    osmium::apply(reader2, location_handler, coastline_ways_handler);
+    reader2.close();
+
+    std::cerr << "Sum of way lengths: " << std::fixed << (coastline_ways_handler.sum_length() / 1000) << "km\n";
+
+    google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/output_database.cpp b/output_database.cpp
new file mode 100644
index 0000000..2db050e
--- /dev/null
+++ b/output_database.cpp
@@ -0,0 +1,179 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <iostream>
+#include <sstream>
+
+#include "ogr_include.hpp"
+#include "osmcoastline.hpp"
+#include "output_database.hpp"
+#include "output_layers.hpp"
+#include "options.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) :
+    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 ("
+         "timestamp                      TEXT, "
+         "runtime                        INTEGER, "
+         "memory_usage                   INTEGER, "
+         "num_ways                       INTEGER, "
+         "num_unconnected_nodes          INTEGER, "
+         "num_rings                      INTEGER, "
+         "num_rings_from_single_way      INTEGER, "
+         "num_rings_fixed                INTEGER, "
+         "num_rings_turned_around        INTEGER, "
+         "num_land_polygons_before_split INTEGER, "
+         "num_land_polygons_after_split  INTEGER)");
+}
+
+void OutputDatabase::set_options(const Options& options) {
+    std::ostringstream sql;
+
+    sql << "INSERT INTO options (overlap, close_distance, max_points_in_polygons, split_large_polygons) VALUES ("
+        << options.bbox_overlap << ", ";
+
+    if (options.close_distance==0) {
+        sql << "NULL, ";
+    } else {
+        sql << options.close_distance << ", ";
+    }
+
+    sql << options.max_points_in_polygon << ", "
+        << (options.split_large_polygons ? 1 : 0)
+        << ")";
+
+    exec(sql.str().c_str());
+}
+
+void OutputDatabase::set_meta(int runtime, int memory_usage, const Stats& stats) {
+    std::ostringstream sql;
+
+    sql << "INSERT INTO meta (timestamp, runtime, memory_usage, "
+        << "num_ways, num_unconnected_nodes, num_rings, num_rings_from_single_way, num_rings_fixed, num_rings_turned_around, "
+        << "num_land_polygons_before_split, num_land_polygons_after_split) VALUES (datetime('now'), "
+        << runtime << ", "
+        << memory_usage << ", "
+        << stats.ways << ", "
+        << stats.unconnected_nodes << ", "
+        << stats.rings << ", "
+        << stats.rings_from_single_way << ", "
+        << stats.rings_fixed << ", "
+        << stats.rings_turned_around << ", "
+        << stats.land_polygons_before_split << ", "
+        << stats.land_polygons_after_split
+        << ")";
+
+    exec(sql.str().c_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;
+}
+
+void OutputDatabase::exec(const char* sql) {
+    m_data_source->ReleaseResultSet(m_data_source->ExecuteSQL(sql, nullptr, nullptr));
+}
+
diff --git a/output_database.hpp b/output_database.hpp
new file mode 100644
index 0000000..2c19dbb
--- /dev/null
+++ b/output_database.hpp
@@ -0,0 +1,105 @@
+#ifndef OUTPUT_DATABASE_HPP
+#define OUTPUT_DATABASE_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <memory>
+#include <string>
+
+#include <osmium/osm/types.hpp>
+#include <ogr_spatialref.h>
+
+#include "ogr_include.hpp"
+
+class LayerErrorPoints;
+class LayerErrorLines;
+class LayerRings;
+class LayerPolygons;
+class LayerLines;
+
+class Options;
+struct Stats;
+
+/**
+ * Handle output to an sqlite database (via OGR).
+ * Several tables/layers are created using the right SRS for the different
+ * kinds of data.
+ */
+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;
+
+    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;
+
+    const char** layer_options() const;
+
+    /// Execute arbitrary SQL command on database
+    void exec(const char* sql);
+
+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);
+
+    void set_options(const Options& options);
+    void set_meta(int runtime, int memory_usage, const Stats& stats);
+
+    void commit();
+
+};
+
+#endif // OUTPUT_DATABASE_HPP
diff --git a/output_layers.cpp b/output_layers.cpp
new file mode 100644
index 0000000..b35e024
--- /dev/null
+++ b/output_layers.cpp
@@ -0,0 +1,326 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <cassert>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+#include <gdal_version.h>
+#include <geos_c.h>
+
+#include <osmium/osm/types.hpp>
+
+#include "ogr_include.hpp"
+#include "osmcoastline.hpp"
+#include "output_layers.hpp"
+#include "srs.hpp"
+
+extern SRS srs;
+
+/***************************************************************/
+
+void Layer::commit() {
+    if (m_layer->CommitTransaction() != OGRERR_NONE) {
+        throw std::runtime_error("Layer commit failed");
+    }
+}
+
+/***************************************************************/
+
+LayerErrorPoints::LayerErrorPoints(OGRDataSource* data_source, const char** options) :
+    Layer()
+{
+    m_layer = data_source->CreateLayer("error_points", srs.out(), wkbPoint, const_cast<char**>(options));
+    if (!m_layer) {
+        std::cerr << "Creating layer 'error_points' failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_osm_id("osm_id", OFTString);
+    field_osm_id.SetWidth(10);
+    if (m_layer->CreateField(&field_osm_id) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'osm_id' on 'error_points' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_error("error", OFTString);
+    field_error.SetWidth(16);
+    if (m_layer->CreateField(&field_error) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'error' on 'error_points' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    m_layer->StartTransaction();
+}
+
+void LayerErrorPoints::add(OGRPoint* point, const char* error, osmium::object_id_type osm_id) {
+    srs.transform(point);
+
+    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
+
+    feature->SetGeometryDirectly(point);
+    feature->SetField("osm_id", std::to_string(osm_id).c_str());
+    feature->SetField("error", error);
+
+    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
+        std::cerr << "Failed to create feature on layer 'error_points'.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFeature::DestroyFeature(feature);
+}
+
+/***************************************************************/
+
+LayerErrorLines::LayerErrorLines(OGRDataSource* data_source, const char** options) :
+    Layer()
+{
+    m_layer = data_source->CreateLayer("error_lines", srs.out(), wkbLineString, const_cast<char**>(options));
+    if (!m_layer) {
+        std::cerr << "Creating layer 'error_lines' failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_osm_id("osm_id", OFTString);
+    field_osm_id.SetWidth(10);
+    if (m_layer->CreateField(&field_osm_id) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'osm_id' on 'error_lines' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_error("error", OFTString);
+    field_error.SetWidth(16);
+    if (m_layer->CreateField(&field_error) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'error' on 'error_lines' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    m_layer->StartTransaction();
+}
+
+void LayerErrorLines::add(OGRLineString* linestring, const char* error, osmium::object_id_type osm_id) {
+    srs.transform(linestring);
+
+    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
+
+    feature->SetGeometryDirectly(linestring);
+    feature->SetField("osm_id", std::to_string(osm_id).c_str());
+    feature->SetField("error", error);
+
+    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
+        std::cerr << "Failed to create feature on layer 'error_lines'.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFeature::DestroyFeature(feature);
+}
+
+/***************************************************************/
+
+LayerRings::LayerRings(OGRDataSource* data_source, const char** options) :
+    Layer()
+{
+    m_layer = data_source->CreateLayer("rings", srs.out(), wkbPolygon, const_cast<char**>(options));
+    if (!m_layer) {
+        std::cerr << "Creating layer 'rings' failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_osm_id("osm_id", OFTString);
+    field_osm_id.SetWidth(10);
+    if (m_layer->CreateField(&field_osm_id) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'osm_id' on 'rings' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_nways("nways", OFTInteger);
+    field_nways.SetWidth(6);
+    if (m_layer->CreateField(&field_nways) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'nways' on 'rings' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_npoints("npoints", OFTInteger);
+    field_npoints.SetWidth(8);
+    if (m_layer->CreateField(&field_npoints) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'npoints' on 'rings' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_fixed("fixed", OFTInteger);
+    field_fixed.SetWidth(1);
+    if (m_layer->CreateField(&field_fixed) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'fixed' on 'rings' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_land("land", OFTInteger);
+    field_land.SetWidth(1);
+    if (m_layer->CreateField(&field_land) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'land' on 'rings' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFieldDefn field_valid("valid", OFTInteger);
+    field_valid.SetWidth(1);
+    if (m_layer->CreateField(&field_valid) != OGRERR_NONE ) {
+        std::cerr << "Creating field 'valid' on 'rings' layer failed.\n";
+        exit(return_code_fatal);
+    }
+
+    m_layer->StartTransaction();
+}
+
+void LayerRings::add(OGRPolygon* polygon, int osm_id, int nways, int npoints, bool fixed, LayerErrorPoints* layer_error_points) {
+    srs.transform(polygon);
+
+    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
+
+    feature->SetGeometryDirectly(polygon);
+    feature->SetField("osm_id", osm_id);
+    feature->SetField("nways", nways);
+    feature->SetField("npoints", npoints);
+    feature->SetField("fixed", fixed ? 0 : 1);
+
+    if (polygon->getExteriorRing()->isClockwise()) {
+        feature->SetField("land", 1);
+    } else {
+        feature->SetField("land", 0);
+    }
+
+    if (polygon->IsValid()) {
+        feature->SetField("valid", 1);
+    } else {
+        /*
+           When the polygon is invalid we find out what and where the problem is.
+           This code is a bit strange because older versions of the GEOS library
+           only export this information as a string. We parse the reason and
+           point coordinates (of a self-intersection-point for instance) from
+           this string and create a point in the error layer for it.
+
+           The exportToGEOS() method on OGR geometries is not documented. Let's
+           hope that it will always be available. We use the GEOSisValidReason()
+           function from the GEOS C interface to get to the reason.
+        */
+
+#if GDAL_VERSION_MAJOR == 1 && GDAL_VERSION_MINOR <= 10
+        GEOSGeom p { polygon->exportToGEOS() };
+        char* r = GEOSisValidReason(p);
+        std::string reason = r;
+        GEOSFree(r);
+        GEOSGeom_destroy(p);
+#else
+        GEOSContextHandle_t contextHandle = OGRGeometry::createGEOSContext();
+        std::string reason = GEOSisValidReason(polygon->exportToGEOS(contextHandle));
+        OGRGeometry::freeGEOSContext(contextHandle);
+#endif
+        size_t left_bracket = reason.find('[');
+        size_t right_bracket = reason.find(']');
+
+        std::istringstream iss(reason.substr(left_bracket+1, right_bracket-left_bracket-1), std::istringstream::in);
+        double x;
+        double y;
+        iss >> x;
+        iss >> y;
+        reason = reason.substr(0, left_bracket);
+
+        std::unique_ptr<OGRPoint> point { new OGRPoint() };
+        point->assignSpatialReference(polygon->getSpatialReference());
+        point->setX(x);
+        point->setY(y);
+
+        if (reason == "Self-intersection") {
+            reason = "self_intersection";
+        }
+        layer_error_points->add(point.release(), reason.c_str(), osm_id);
+
+        feature->SetField("valid", 0);
+    }
+
+    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
+        std::cerr << "Failed to create feature in layer 'rings'.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFeature::DestroyFeature(feature);
+}
+
+/***************************************************************/
+
+LayerPolygons::LayerPolygons(OGRDataSource* data_source, const char** options, const char* name) :
+    Layer(),
+    m_name(name)
+{
+    m_layer = data_source->CreateLayer(name, srs.out(), wkbPolygon, const_cast<char**>(options));
+    if (!m_layer) {
+        std::cerr << "Creating layer '" << name << "' failed.\n";
+        exit(return_code_fatal);
+    }
+
+    m_layer->StartTransaction();
+}
+
+void LayerPolygons::add(OGRPolygon* polygon) {
+    srs.transform(polygon);
+
+    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
+
+    feature->SetGeometryDirectly(polygon);
+
+    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
+        std::cerr << "Failed to create feature in layer '" << m_name << "'.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFeature::DestroyFeature(feature);
+}
+
+/***************************************************************/
+
+LayerLines::LayerLines(OGRDataSource* data_source, const char** options) :
+    Layer()
+{
+    m_layer = data_source->CreateLayer("lines", srs.out(), wkbLineString, const_cast<char**>(options));
+    if (!m_layer) {
+        std::cerr << "Creating layer 'lines' failed.\n";
+        exit(return_code_fatal);
+    }
+
+    m_layer->StartTransaction();
+}
+
+void LayerLines::add(OGRLineString* linestring) {
+    srs.transform(linestring);
+
+    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
+
+    feature->SetGeometryDirectly(linestring);
+
+    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
+        std::cerr << "Failed to create feature in layer 'lines'.\n";
+        exit(return_code_fatal);
+    }
+
+    OGRFeature::DestroyFeature(feature);
+}
+
diff --git a/output_layers.hpp b/output_layers.hpp
new file mode 100644
index 0000000..9c5b314
--- /dev/null
+++ b/output_layers.hpp
@@ -0,0 +1,124 @@
+#ifndef OUTPUT_LAYER_HPP
+#define OUTPUT_LAYER_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <osmium/osm/types.hpp>
+
+#include "srs.hpp"
+
+extern SRS srs;
+
+class OGRLayer;
+class OGRDataSource;
+class OGRPoint;
+class OGRLineString;
+class OGRPolygon;
+
+/**
+ * Parent class for all output layers.
+ */
+class Layer {
+
+protected:
+
+    /// OGRLayer implementing this output layer.
+    OGRLayer* m_layer;
+
+    Layer() : m_layer(nullptr) {}
+
+public:
+
+    /// Commit transaction on this layer.
+    void commit();
+
+};
+
+/**
+ * Layer for any errors in one point.
+ */
+class LayerErrorPoints : public Layer {
+
+public:
+
+    LayerErrorPoints(OGRDataSource* data_source, const char** options);
+    void add(OGRPoint* point, const char* error, osmium::object_id_type id);
+
+};
+
+/**
+ * Layer for any errors in a linestring.
+ */
+class LayerErrorLines : public Layer {
+
+public:
+
+    LayerErrorLines(OGRDataSource* data_source, const char** options);
+    void add(OGRLineString* linestring, const char* error, osmium::object_id_type id);
+
+};
+
+/**
+ * Layer for polygon rings.
+ * Will contain polygons without holes, ie. with just an outer ring.
+ * Polygon outer rings will be oriented according to usual GIS custom with
+ * points going clockwise around the ring, ie "land" is on the right hand side of
+ * the border. This is the other way around from how it looks in OSM.
+ */
+class LayerRings : public Layer {
+
+public:
+
+    LayerRings(OGRDataSource* data_source, const char** options);
+    void add(OGRPolygon* polygon, int id, int nways, int npoints, bool fixed, LayerErrorPoints* layer_error_points);
+
+};
+
+/**
+ * Layer for completed polygons.
+ * Polygons can contain inner rings for large water areas such as the Caspian Sea.
+ */
+class LayerPolygons : public Layer {
+
+    const char* m_name;
+
+public:
+
+    LayerPolygons(OGRDataSource* data_source, const char** options, const char* name);
+    void add(OGRPolygon* polygon);
+
+};
+
+/**
+ * Layer for coastlines generated from completed polygons.
+ * Lines containt at most max-points points.
+ */
+class LayerLines : public Layer {
+
+public:
+
+    LayerLines(OGRDataSource* data_source, const char** options);
+    void add(OGRLineString* lines);
+
+};
+
+#endif // OUTPUT_LAYER_HPP
diff --git a/render_image.sh b/render_image.sh
new file mode 100755
index 0000000..1251a11
--- /dev/null
+++ b/render_image.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+#  render_image.sh [DBFILE]
+#
+#  Render polygons in DBFILE using shp2img program from mapserver.
+#  Automatically detects SRID and renders accordingly.
+#  If no DBFILE is given, testdata.db is used.
+#
+
+WIDTH=2048
+
+if [ "x$1" = "x" ]; then
+    DBFILE=testdata.db
+else
+    DBFILE=$1
+fi
+
+SRID=`sqlite3 $DBFILE "SELECT srid FROM geometry_columns WHERE f_table_name='polygons'"`
+
+if [ "$SRID" = "4326" ]; then
+    # If SRID is WGS84 the image height is half its width
+    HEIGHT=`expr $WIDTH / 2`
+    EXTENT="-180 -90 180 90"
+else
+    # If SRID is 3857 (Mercator) the image height is the same as its width
+    HEIGHT=$WIDTH
+    EXTENT="-20037508.342789244 -20037508.342789244 20037508.342789244 20037508.342789244"
+fi
+
+rm -f coastline-mapserver.db
+ln -s $DBFILE coastline-mapserver.db
+shp2img -m coastline.map -l polygons -i PNG -o polygons.png -s $WIDTH $HEIGHT -e $EXTENT
+rm -f coastline-mapserver.db
+
diff --git a/runtest.sh.in b/runtest.sh.in
new file mode 100755
index 0000000..bb92c6d
--- /dev/null
+++ b/runtest.sh.in
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ "x$1" = "x-v" ]; then
+    osmcoastline_valgrind="valgrind --leak-check=full --show-reachable=yes"
+fi
+
+exec $osmcoastline_valgrind ./osmcoastline --debug --verbose --overwrite --output-lines --output-polygons=both --output-rings -o testdata.db @PROJECT_SOURCE_DIR@/testdata.osm
+
diff --git a/simplify.sql b/simplify.sql
new file mode 100644
index 0000000..a6cfcfc
--- /dev/null
+++ b/simplify.sql
@@ -0,0 +1,21 @@
+--
+--  simplify.sql
+--
+--  You can use this to simplify coastline polygons if needed.
+--  It will only work properly if polygons are not split and
+--  the 3857 projection is used (ie if osmcoastline was run with
+--  "-m 0 -s 3857").
+--
+
+CREATE TABLE simplified_land_polygons (
+    OGC_FID INTEGER PRIMARY KEY
+);
+
+SELECT AddGeometryColumn('simplified_land_polygons', 'GEOMETRY', 3857, 'POLYGON', 'XY', 1);
+
+--  Depending on the detail you need you might have to change the numbers here.
+--  The given numbers work up to about zoom level 9.
+INSERT INTO simplified_land_polygons (ogc_fid, geometry) SELECT ogc_fid, SimplifyPreserveTopology(geometry, 300) FROM land_polygons WHERE ST_Area(geometry) > 300000;
+
+SELECT CreateSpatialIndex('simplified_land_polygons', 'GEOMETRY');
+
diff --git a/simplify_and_split/README b/simplify_and_split/README
new file mode 100644
index 0000000..20e063c
--- /dev/null
+++ b/simplify_and_split/README
@@ -0,0 +1,95 @@
+
+HOW TO SIMPLIFY AND SPLIT LAND/WATER POLYGONS
+=============================================
+
+The osmcoastline program already has built-in support for splitting land and
+water polygons created from the coastline. But it is fairly limited in what it
+can do. This is fine for many use cases, but if you want something different
+here are some tips and code that helps you with polygon simplification (for
+lower zoom levels) and with doing different kinds of splits using a
+PostgreSQL/PostGIS database. You should be somewhat familiar with PostGIS
+before attempting this.
+
+Note that the polygon simplification described here is done simply to make the
+geometries smaller and the polygon therefore faster to render. For proper
+generalization to create nice cartography, this is not the right process. See
+http://www.imagico.de/map/coastline_en.php for more about this.
+
+The different *.sql files in this directory run different steps of the process
+and they can be parameterized in different ways. Depending on what you want to
+do you have to run some or all of these SQL scripts, some maybe several times
+with different parameters. The *.sql files all have some documentation at the
+top, read it.
+
+Note that some of these steps can take a long time!
+
+Here is a step-by-step guide with an example. You can change the zoom levels,
+tolerances, etc.:
+
+1. Create PostgreSQL database with PostGIS extensions, this description assumes
+   the database is called "coastlines".
+
+2. Create complete (non-split) land polygons in Mercator (3857) projection
+   with osmcoastline or download them from
+   http://data.openstreetmapdata.com/land-polygons-complete-3857.zip .
+   The following assumes you have downloaded this file.
+
+3. Load data into PostGIS database:
+
+   # unzip land-polygons-complete-3857.zip
+   # cd land-polygons-complete-3857
+   # shp2pgsql -s 3857 -S -I land_polygons.shp | psql -d coastlines
+
+4. Prepare some tables:
+
+   # psql -d coastlines -f setup_tables.sql
+
+5. For every zoom level you want, you have to prepare tile tables:
+
+   # psql -d coastlines -v zoom=3 setup_bbox_tiles.sql
+   # psql -d coastlines -v zoom=5 setup_bbox_tiles.sql
+   # psql -d coastlines -v zoom=6 setup_bbox_tiles.sql
+
+6. For every simplification step you need, do the simplification:
+
+   # psql -d coastlines -v tolerance=3000 -v min_area=3000000 -f simplify_land_polygons.sql
+   # psql -d coastlines -v tolerance=300  -v min_area=300000  -f simplify_land_polygons.sql
+
+7. For every zoom level and simplification step you need you can create the
+   final split land polygons:
+
+   # psql -d coastlines -v tolerance=3000 -v min_area=3000000 -v zoom=3 -f split_land_polygons.sql
+   # psql -d coastlines -v tolerance=300  -v min_area=300000  -v zoom=5 -f split_land_polygons.sql
+
+   Instead of splitting the non-split polygons for each zoom level, you can use
+   the already split polygons for smaller zoom levels and split them again for
+   larger zoom levels. This is probably faster than always starting from the
+   non-split polygons:
+
+   # psql -d coastlines -v tolerance=300 -v min_area=300000 -v from_zoom=5 -v to_zoom=6 -f split_tiles.sql
+
+8. After all split polygons for land areas are created you can call create the
+   water polygons from them. Unlike the other scripts, this doesn't take any
+   parameters, it will just create a water polygon for every split land polygon
+   regardless of how the land polygon was created.
+
+   # psql -d coastlines -f create_water_polygons.sql
+
+Note that splitting Polygons can lead to MultiPolygons, so some tables use
+MultiPolygon geometries. It is probably better for rendering to split
+multipolygons into polygons again. You can use the function ST_Dump() for this.
+
+Also note that sometimes splitting (Multi)Polygons can lead to non-polygon
+geometry types such as lines or points, this code will just remove those
+cases.
+
+The tables and SQL queries in these files are crafted in a way that allows any
+number of different simplification parameters and any number of different
+splittings based on different zoom levels in the same tables. The parameters
+"tolerance", "min_area" and "zoom" will appear in all tables as columns to
+allow you to distinguish which geometry belongs to which. In addition the "x"
+and "y" columns give you the tile numbers a specific geometry is for. This may
+or may not be the most efficient way of doing this, so you might want to
+optimize data layout and especially index creation for your use case, but it is
+a flexible starting point for your own experiments.
+
diff --git a/simplify_and_split/create_water_polygons.sql b/simplify_and_split/create_water_polygons.sql
new file mode 100644
index 0000000..5a21609
--- /dev/null
+++ b/simplify_and_split/create_water_polygons.sql
@@ -0,0 +1,38 @@
+-- ======================================================================
+-- Create water polygons
+--
+-- Creates split water polygons from all split land polygons.
+--
+-- Call like this:
+-- psql -d coastlines -f create_water_polygons.sql
+--
+-- ======================================================================
+
+-- This is a helper view that makes the following INSERT easier to write.
+-- For every tile this view contains the union of all land polygons in that tile.
+CREATE VIEW merged_land_polygons AS
+    SELECT tolerance, min_area, zoom, x, y, ST_Union(geom) AS geom
+        FROM split_land_polygons p
+        GROUP BY tolerance, min_area, zoom, x, y;
+
+INSERT INTO split_water_polygons (tolerance, min_area, zoom, x, y, geom)
+    SELECT p.tolerance, p.min_area, p.zoom, p.x, p.y, ST_Multi(ST_Difference(b.geom, p.geom))
+        FROM merged_land_polygons p, bbox_tiles b
+        WHERE p.zoom = b.zoom
+          AND p.x = b.x
+          AND p.y = b.y;
+
+-- If there are no land polygons in a tile, no water polygon will be created for it.
+-- This INSERT adds the water polygons in that case.
+INSERT INTO split_water_polygons (tolerance, min_area, zoom, x, y, geom)
+    SELECT p.tolerance, p.min_area, x, y, b.zoom, ST_Multi(geom)
+        FROM bbox_tiles b, (SELECT distinct tolerance, min_area, zoom from split_land_polygons) p
+        WHERE b.zoom=p.zoom
+          AND x || '-' || y || '-' || b.zoom NOT IN (SELECT x || '-' || y || '-' || zoom FROM split_land_polygons);
+
+DROP VIEW merged_land_polygons;
+
+CREATE INDEX
+    ON split_water_polygons
+    USING GIST (geom);
+
diff --git a/simplify_and_split/setup_bbox_tiles.sql b/simplify_and_split/setup_bbox_tiles.sql
new file mode 100644
index 0000000..46babfd
--- /dev/null
+++ b/simplify_and_split/setup_bbox_tiles.sql
@@ -0,0 +1,27 @@
+-- ======================================================================
+--
+-- Set up helper table with polygons containing the bbox for each tile
+--
+-- Call like this:
+-- psql -d coastlines -v zoom=$ZOOM -f setup_bbox_tiles.sql
+--
+-- for instance:
+-- psql -d coastlines -v zoom=3 -f setup_bbox_tiles.sql
+--
+-- ======================================================================
+
+-- max value for x or y coordinate in spherical mercator
+\set cmax 20037508.34
+\set pow (2.0 ^ :zoom)::integer
+\set tilesize (2*:cmax / :pow)
+
+CREATE VIEW tiles AS SELECT * FROM generate_series(0, :pow - 1) AS x, generate_series(0, :pow - 1) AS y;
+CREATE VIEW bbox AS SELECT :zoom AS zoom, x, y, x*:tilesize - :cmax AS x1, (:pow - y - 1)*:tilesize - :cmax AS y1, (x+1)*:tilesize - :cmax AS x2, (:pow - y)*:tilesize - :cmax AS y2 FROM tiles;
+
+INSERT INTO bbox_tiles (zoom, x, y, geom)
+    SELECT zoom, x, y, ST_SetSRID(ST_MakeBox2D(ST_MakePoint(x1, y1), ST_MakePoint(x2, y2)), 3857) AS geom
+        FROM bbox;
+
+DROP VIEW bbox;
+DROP VIEW tiles;
+
diff --git a/simplify_and_split/setup_tables.sql b/simplify_and_split/setup_tables.sql
new file mode 100644
index 0000000..6e9ebca
--- /dev/null
+++ b/simplify_and_split/setup_tables.sql
@@ -0,0 +1,55 @@
+-- ======================================================================
+-- Setup tables
+-- ======================================================================
+
+DROP TABLE IF EXISTS simplified_land_polygons;
+CREATE TABLE simplified_land_polygons (
+    id        SERIAL,
+    fid       INT,
+    tolerance INT,
+    min_area  INT
+);
+
+SELECT AddGeometryColumn('simplified_land_polygons', 'geom', 3857, 'POLYGON', 2);
+
+
+DROP TABLE IF EXISTS split_land_polygons;
+CREATE TABLE split_land_polygons (
+    id        SERIAL,
+    fid       INT,
+    tolerance INT,
+    min_area  INT,
+    zoom      INT,
+    x         INT,
+    y         INT
+);
+
+-- splitting can make multipolygons out of polygons, so geometry type is different
+SELECT AddGeometryColumn('split_land_polygons', 'geom', 3857, 'MULTIPOLYGON', 2);
+
+
+DROP TABLE IF EXISTS split_water_polygons;
+CREATE TABLE split_water_polygons (
+    id        SERIAL,
+    tolerance INT,
+    min_area  INT,
+    zoom      INT,
+    x         INT,
+    y         INT
+);
+
+SELECT AddGeometryColumn('split_water_polygons', 'geom', 3857, 'MULTIPOLYGON', 2);
+
+
+DROP TABLE IF EXISTS bbox_tiles;
+CREATE TABLE bbox_tiles (
+    id        SERIAL,
+    zoom      INT,
+    x         INT,
+    y         INT
+);
+
+SELECT AddGeometryColumn('bbox_tiles', 'geom', 3857, 'POLYGON', 2);
+
+CREATE INDEX idx_bbox_files_geom ON bbox_tiles USING GIST (geom);
+
diff --git a/simplify_and_split/simplify_land_polygons.sql b/simplify_and_split/simplify_land_polygons.sql
new file mode 100644
index 0000000..dab3db4
--- /dev/null
+++ b/simplify_and_split/simplify_land_polygons.sql
@@ -0,0 +1,28 @@
+-- ======================================================================
+--
+-- Simplify land polygons
+--
+-- Parameters:
+--   tolerance: Tolerance for simplification algorithm, higher values
+--              mean more simplification
+--   min_area:  Polygons with smaller area than this will not appear
+--              in the output
+--
+-- Call like this:
+-- psql -d $DB -v tolerance=$TOLERANCE -v min_area=$MIN_AREA -f simplify_land_polygons.sql
+--
+-- for instance:
+-- psql -d coastlines -v tolerance=300 -v min_area=300000 -f simplify_land_polygons.sql
+--
+-- ======================================================================
+
+INSERT INTO simplified_land_polygons (fid, tolerance, min_area, geom)
+    SELECT fid, :tolerance, :min_area, ST_SimplifyPreserveTopology(geom, :tolerance)
+        FROM land_polygons
+        WHERE ST_Area(geom) > :min_area;
+
+CREATE INDEX
+    ON simplified_land_polygons
+    USING GIST (geom)
+    WHERE tolerance=:tolerance AND min_area=:min_area;
+
diff --git a/simplify_and_split/split_land_polygons.sql b/simplify_and_split/split_land_polygons.sql
new file mode 100644
index 0000000..50ecfa2
--- /dev/null
+++ b/simplify_and_split/split_land_polygons.sql
@@ -0,0 +1,49 @@
+-- ======================================================================
+--
+-- Split land polygons into tiles
+--
+-- This can either split non-simplified land polygons or simplified land
+-- polygons. Set tolerance=0 and min_area=0 to use non-simplified land
+-- polygons, otherwise the simplified polygons with the given parameters
+-- are used.
+--
+-- Call like this:
+-- psql -d $DB -v tolerance=$TOLERANCE -v min_area=$MIN_AREA -v zoom=$ZOOM -f split_land_polygons.sql
+--
+-- for instance:
+-- psql -d coastlines -v tolerance=300 -v min_area=300000 -v zoom=3 -f split_land_polygons.sql
+--
+-- ======================================================================
+
+-- Only one of the following INSERT statements will do anything thanks to the
+-- last condition (:tolerance (!)=0).
+
+-- case 1: split non-simplified polygons
+INSERT INTO split_land_polygons (fid, tolerance, min_area, zoom, x, y, geom)
+    SELECT p.fid, 0, 0, b.zoom, b.x, b.y, ST_Multi(ST_Intersection(p.geom, b.geom))
+        FROM land_polygons p, bbox_tiles b
+        WHERE p.geom && b.geom
+          AND ST_Intersects(p.geom, b.geom)
+          AND b.zoom=:zoom
+          AND ST_GeometryType(ST_Multi(ST_Intersection(p.geom, b.geom))) = 'ST_MultiPolygon'
+          AND :tolerance=0;
+
+-- case 2: split simplified polygons
+INSERT INTO split_land_polygons (fid, tolerance, min_area, zoom, x, y, geom)
+    SELECT p.fid, p.tolerance, p.min_area, b.zoom, b.x, b.y, ST_Multi(ST_Intersection(p.geom, b.geom))
+        FROM simplified_land_polygons p, bbox_tiles b
+        WHERE p.geom && b.geom
+          AND ST_Intersects(p.geom, b.geom)
+          AND p.tolerance=:tolerance
+          AND p.min_area=:min_area
+          AND b.zoom=:zoom
+          AND ST_GeometryType(ST_Multi(ST_Intersection(p.geom, b.geom))) = 'ST_MultiPolygon'
+          AND :tolerance!=0;
+
+CREATE INDEX
+    ON split_land_polygons
+    USING GIST (geom)
+    WHERE tolerance=:tolerance
+        AND min_area=:min_area
+        AND zoom=:zoom;
+
diff --git a/simplify_and_split/split_tiles.sql b/simplify_and_split/split_tiles.sql
new file mode 100644
index 0000000..2b15f38
--- /dev/null
+++ b/simplify_and_split/split_tiles.sql
@@ -0,0 +1,23 @@
+-- ======================================================================
+--
+-- Split land polygon tiles into smaller tiles
+--
+-- Call like this:
+-- psql -d $DB -v tolerance=$TOLERANCE -v min_area=$MIN_AREA -v from_zoom=$FROM_ZOOM -v to_zoom=$TO_ZOOM -f split_tiles.sql
+--
+-- for instance:
+-- psql -d coastlines -v tolerance=0 -v min_area=0 -v from_zoom=5 -v to_zoom=6 -f split_tiles.sql
+--
+-- ======================================================================
+
+INSERT INTO split_land_polygons (fid, tolerance, min_area, zoom, x, y, geom)
+    SELECT p.fid, :tolerance, :min_area, :to_zoom, b.x, b.y, ST_Multi(ST_Intersection(p.geom, b.geom))
+        FROM split_land_polygons p, bbox_tiles b
+        WHERE p.geom && b.geom
+          AND ST_Intersects(p.geom, b.geom)
+          AND p.tolerance=:tolerance
+          AND p.min_area=:min_area
+          AND p.zoom=:from_zoom
+          AND b.zoom=:to_zoom
+          AND ST_GeometryType(ST_Multi(ST_Intersection(p.geom, b.geom))) = 'ST_MultiPolygon';
+
diff --git a/srs.cpp b/srs.cpp
new file mode 100644
index 0000000..11d5d39
--- /dev/null
+++ b/srs.cpp
@@ -0,0 +1,70 @@
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <ogr_geometry.h>
+
+#include "srs.hpp"
+
+bool SRS::set_output(int epsg) {
+    m_srs_out.importFromEPSG(epsg);
+
+    if (epsg != 4326) {
+        m_transform = std::unique_ptr<OGRCoordinateTransformation>(OGRCreateCoordinateTransformation(&m_srs_wgs84, &m_srs_out));
+        if (!m_transform) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void SRS::transform(OGRGeometry* geometry) {
+    if (!m_transform) { // Output SRS is WGS84, no transformation needed.
+        return;
+    }
+
+    // Transform if no SRS is set on input geometry or it is set to WGS84.
+    OGRSpatialReference* srs = geometry->getSpatialReference();
+    if (srs == nullptr || srs->IsSame(&m_srs_wgs84)) {
+        if (geometry->transform(m_transform.get()) != OGRERR_NONE) {
+            throw TransformationException();
+        }
+    }
+}
+
+OGREnvelope SRS::max_extent() const {
+    OGREnvelope envelope;
+
+    if (m_transform) {
+        envelope.MinX = -20037508.342789244;
+        envelope.MinY = -20037508.342789244;
+        envelope.MaxX =  20037508.342789244;
+        envelope.MaxY =  20037508.342789244;
+    } else {
+        envelope.MinX = -180;
+        envelope.MinY =  -90;
+        envelope.MaxX =  180;
+        envelope.MaxY =   90;
+    }
+
+    return envelope;
+}
+
diff --git a/srs.hpp b/srs.hpp
new file mode 100644
index 0000000..2f53e89
--- /dev/null
+++ b/srs.hpp
@@ -0,0 +1,88 @@
+#ifndef SRS_HPP
+#define SRS_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <memory>
+
+#include <ogr_spatialref.h>
+
+class OGRGeometry;
+class OGREnvelope;
+
+class SRS {
+
+    /// WGS84 (input) SRS.
+    OGRSpatialReference m_srs_wgs84;
+
+    /// Output SRS.
+    OGRSpatialReference m_srs_out;
+
+    /**
+     * If the output SRS is not WGS84, this contains the transformation
+     * object. Otherwise nullptr.
+     */
+    std::unique_ptr<OGRCoordinateTransformation> m_transform;
+
+public:
+
+    /**
+     * This exception is thrown when a transformation to the output SRS fails.
+     */
+    class TransformationException {};
+
+    SRS() {
+        m_srs_wgs84.SetWellKnownGeogCS("WGS84");
+    }
+
+    /**
+     * Set output SRS to EPGS code. Call this method before using any
+     * of the other methods of this object.
+     */
+    bool set_output(int epsg);
+
+    OGRSpatialReference* wgs84() { return &m_srs_wgs84; }
+    OGRSpatialReference* out()   { return &m_srs_out; }
+
+    /**
+     * Transform geometry to output SRS (if it is not in the output SRS
+     * already).
+     */
+    void transform(OGRGeometry* geometry);
+
+    /**
+     * Return max extent for output SRS.
+     */
+    OGREnvelope max_extent() const;
+
+    /**
+     * These values are used to decide which coastline segments are
+     * bogus. They are near the antimeridian or southern edge of the
+     * map and only there to close the coastline polygons.
+     */
+    double max_x() const { return m_transform ?  20037500.0 :  179.9999; }
+    double min_x() const { return m_transform ? -20037500.0 : -179.9999; }
+    double min_y() const { return m_transform ? -20037400.0 :  -85.049;  }
+
+};
+
+#endif // SRS_HPP
diff --git a/stats.hpp b/stats.hpp
new file mode 100644
index 0000000..052c9d6
--- /dev/null
+++ b/stats.hpp
@@ -0,0 +1,36 @@
+#ifndef STATS_HPP
+#define STATS_HPP
+
+/*
+
+  Copyright 2012-2015 Jochen Topf <jochen at topf.org>.
+
+  This file is part of OSMCoastline.
+
+  OSMCoastline is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  OSMCoastline is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with OSMCoastline.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+struct Stats {
+    unsigned int ways;
+    unsigned int unconnected_nodes;
+    unsigned int rings;
+    unsigned int rings_from_single_way;
+    unsigned int rings_fixed;
+    unsigned int rings_turned_around;
+    unsigned int land_polygons_before_split;
+    unsigned int land_polygons_after_split;
+};
+
+#endif // STATS_HPP
diff --git a/taginfo.json b/taginfo.json
new file mode 100644
index 0000000..a9eed7b
--- /dev/null
+++ b/taginfo.json
@@ -0,0 +1,30 @@
+{
+    "data_format": 1,
+    "data_url": "https://raw.githubusercontent.com/osmcode/osmcoastline/master/taginfo.json",
+    "project": {
+        "name": "OSMCoastline",
+        "description": "Program that assembles continuous coastlines from OSM data and creates land and water polygons.",
+        "project_url": "http://wiki.osm.org/wiki/OSMCoastline",
+        "doc_url": "https://github.com/osmcode/osmcoastline",
+        "icon_url": "http://osmcode.org/img/logo-osmcoastline-16x16.png",
+        "contact_name": "Jochen Topf",
+        "contact_email": "jochen at remote.org",
+        "keywords": [
+            "export"
+        ]
+    },
+    "tags": [
+        {
+            "key": "natural",
+            "value": "coastline",
+            "object_types": [ "way" ],
+            "description": "The coastline."
+        },
+        {
+            "key": "coastline",
+            "value": "bogus",
+            "object_types": [ "way" ],
+            "description": "Pseudo-coastline in Antarctica tagged for technical reasons."
+        }
+    ]
+}
diff --git a/testdata.osm b/testdata.osm
new file mode 100644
index 0000000..c53c362
--- /dev/null
+++ b/testdata.osm
@@ -0,0 +1,735 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' upload='false' generator='JOSM'>
+  <node id='-566' visible='true' lat='53.74' lon='7.30' />
+  <node id='-565' visible='true' lat='53.74' lon='7.25' />
+  <node id='-564' visible='true' lat='53.74' lon='7.20' />
+  <node id='-563' visible='true' lat='53.85569892214832' lon='7.536873252131046' />
+  <node id='-561' visible='true' lat='53.84953278957106' lon='7.537570150479769' />
+  <node id='-559' visible='true' lat='53.847203125285915' lon='7.558709400391042' />
+  <node id='-557' visible='true' lat='53.847614251934004' lon='7.576364158558699' />
+  <node id='-555' visible='true' lat='53.85501384116708' lon='7.57473806241168' />
+  <node id='-554' visible='true' lat='53.85638399191468' lon='7.55336651305083' />
+  <node id='-550' visible='true' lat='53.86159015564557' lon='7.531298065341259' />
+  <node id='-548' visible='true' lat='53.85679502839138' lon='7.52293528515658' />
+  <node id='-546' visible='true' lat='53.84418807315669' lon='7.524096782404452' />
+  <node id='-544' visible='true' lat='53.841172803879466' lon='7.559870897638915' />
+  <node id='-542' visible='true' lat='53.8435028037526' lon='7.5900698260835915' />
+  <node id='-540' visible='true' lat='53.85309555475569' lon='7.589837526634018' />
+  <node id='-538' visible='true' lat='53.86159015564557' lon='7.587049933239126' />
+  <node id='-537' visible='true' lat='53.862549115156284' lon='7.548952823508918' />
+  <node id='-533' visible='true' lat='53.87035696730325' lon='7.56428458718083' />
+  <node id='-531' visible='true' lat='53.868713330061716' lon='7.600291001864868' />
+  <node id='-529' visible='true' lat='53.86487792531916' lon='7.607492284801675' />
+  <node id='-527' visible='true' lat='53.84542152981897' lon='7.607027685902527' />
+  <node id='-525' visible='true' lat='53.83664949279521' lon='7.598897205167422' />
+  <node id='-523' visible='true' lat='53.83664949279521' lon='7.558709400391042' />
+  <node id='-521' visible='true' lat='53.838568532929614' lon='7.512946408824879' />
+  <node id='-519' visible='true' lat='53.84281752313211' lon='7.5078358209342415' />
+  <node id='-517' visible='true' lat='53.85542489110162' lon='7.5071389225855185' />
+  <node id='-515' visible='true' lat='53.86939818676157' lon='7.515501702770197' />
+  <node id='-514' visible='true' lat='53.87158965284901' lon='7.54593293066445' />
+  <node id='-428' visible='true' lat='53.75883' lon='7.48438' />
+  <node id='-426' visible='true' lat='53.85517' lon='7.17644' />
+  <node id='-424' visible='true' lat='53.85497' lon='7.33171' />
+  <node id='-422' visible='true' lat='53.8469' lon='7.34744' />
+  <node id='-420' visible='true' lat='53.84186' lon='7.32214' />
+  <node id='-418' visible='true' lat='53.84206' lon='7.28965' />
+  <node id='-416' visible='true' lat='53.84206' lon='7.25647' />
+  <node id='-414' visible='true' lat='53.84206' lon='7.21441' />
+  <node id='-412' visible='true' lat='53.84226' lon='7.17542' />
+  <node id='-410' visible='true' lat='53.84973' lon='7.15524' />
+  <node id='-408' visible='true' lat='53.81763' lon='7.54706' />
+  <node id='-406' visible='true' lat='53.83141' lon='7.40314' />
+  <node id='-404' visible='true' lat='53.83121' lon='7.57551' />
+  <node id='-402' visible='true' lat='53.82374' lon='7.58372' />
+  <node id='-400' visible='true' lat='53.81789' lon='7.57449' />
+  <node id='-398' visible='true' lat='53.81688' lon='7.5184' />
+  <node id='-396' visible='true' lat='53.81688' lon='7.48488' />
+  <node id='-394' visible='true' lat='53.81607' lon='7.45273' />
+  <node id='-392' visible='true' lat='53.81627' lon='7.41238' />
+  <node id='-390' visible='true' lat='53.82213' lon='7.39186' />
+  <node id='-388' visible='true' lat='53.81648' lon='7.22067' />
+  <node id='-386' visible='true' lat='53.82762' lon='7.15056' />
+  <node id='-384' visible='true' lat='53.83304' lon='7.17571' />
+  <node id='-382' visible='true' lat='53.83361' lon='7.33871' />
+  <node id='-380' visible='true' lat='53.8202' lon='7.35515' />
+  <node id='-378' visible='true' lat='53.81563' lon='7.3242' />
+  <node id='-376' visible='true' lat='53.81591' lon='7.29179' />
+  <node id='-374' visible='true' lat='53.81648' lon='7.25019' />
+  <node id='-372' visible='true' lat='53.81677' lon='7.16797' />
+  <node id='-370' visible='true' lat='53.66948' lon='7.22641' />
+  <node id='-368' visible='true' lat='53.67961' lon='7.20897' />
+  <node id='-366' visible='true' lat='53.63745' lon='7.2117' />
+  <node id='-364' visible='true' lat='53.65752' lon='7.21375' />
+  <node id='-362' visible='true' lat='53.67292' lon='7.1816' />
+  <node id='-360' visible='true' lat='53.65732' lon='7.14877' />
+  <node id='-358' visible='true' lat='53.63765' lon='7.14843' />
+  <node id='-356' visible='true' lat='53.65551' lon='7.41078' />
+  <node id='-354' visible='true' lat='53.65774' lon='7.42349' />
+  <node id='-352' visible='true' lat='53.65133' lon='7.43055' />
+  <node id='-350' visible='true' lat='53.64993' lon='7.41501' />
+  <node id='-348' visible='true' lat='53.78143' lon='7.6005' />
+  <node id='-346' visible='true' lat='53.78588' lon='7.61792' />
+  <node id='-344' visible='true' lat='53.7945' lon='7.63204' />
+  <node id='-342' visible='true' lat='53.80562' lon='7.59956' />
+  <node id='-340' visible='true' lat='53.80534' lon='7.57508' />
+  <node id='-338' visible='true' lat='53.80062' lon='7.55342' />
+  <node id='-336' visible='true' lat='53.78449' lon='7.55295' />
+  <node id='-334' visible='true' lat='53.78032' lon='7.58732' />
+  <node id='-332' visible='true' lat='53.79124' lon='7.2118' />
+  <node id='-330' visible='true' lat='53.79104' lon='7.23011' />
+  <node id='-328' visible='true' lat='53.76095' lon='7.23078' />
+  <node id='-326' visible='true' lat='53.79045' lon='7.27006' />
+  <node id='-324' visible='true' lat='53.77275' lon='7.29003' />
+  <node id='-322' visible='true' lat='53.76547' lon='7.26373' />
+  <node id='-320' visible='true' lat='53.75878' lon='7.18584' />
+  <node id='-318' visible='true' lat='53.76941' lon='7.17552' />
+  <node id='-316' visible='true' lat='53.77924' lon='7.19649' />
+  <node id='-314' visible='true' lat='53.72037' lon='7.36471' />
+  <node id='-312' visible='true' lat='53.72703' lon='7.35772' />
+  <node id='-310' visible='true' lat='53.73162' lon='7.37556' />
+  <node id='-308' visible='true' lat='53.73781' lon='7.39069' />
+  <node id='-306' visible='true' lat='53.73207' lon='7.43839' />
+  <node id='-304' visible='true' lat='53.72496' lon='7.43102' />
+  <node id='-302' visible='true' lat='53.71578' lon='7.44266' />
+  <node id='-300' visible='true' lat='53.71578' lon='7.4318' />
+  <node id='-298' visible='true' lat='53.71945' lon='7.42521' />
+  <node id='-296' visible='true' lat='53.76056' lon='7.43875'>
+    <tag k='error' v='node with tag natural=coastline' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </node>
+  <node id='-294' visible='true' lat='53.72244' lon='7.18941' />
+  <node id='-292' visible='true' lat='53.71303' lon='7.14947' />
+  <node id='-290' visible='true' lat='53.70637' lon='7.13744' />
+  <node id='-288' visible='true' lat='53.69719' lon='7.14636' />
+  <node id='-286' visible='true' lat='53.69696' lon='7.16537' />
+  <node id='-284' visible='true' lat='53.70086' lon='7.17157' />
+  <node id='-282' visible='true' lat='53.70591' lon='7.16537' />
+  <node id='-280' visible='true' lat='53.7066' lon='7.17041' />
+  <node id='-278' visible='true' lat='53.70408' lon='7.18049' />
+  <node id='-276' visible='true' lat='53.70132' lon='7.17972' />
+  <node id='-274' visible='true' lat='53.69857' lon='7.19562' />
+  <node id='-272' visible='true' lat='53.70729' lon='7.2026' />
+  <node id='-270' visible='true' lat='53.70293' lon='7.2565' />
+  <node id='-268' visible='true' lat='53.71234' lon='7.3236' />
+  <node id='-266' visible='true' lat='53.71647' lon='7.34997' />
+  <node id='-264' visible='true' lat='53.72519' lon='7.34842' />
+  <node id='-262' visible='true' lat='53.7268' lon='7.33795' />
+  <node id='-260' visible='true' lat='53.72404' lon='7.24564' />
+  <node id='-258' visible='true' lat='53.72794' lon='7.46011' />
+  <node id='-256' visible='true' lat='53.72083' lon='7.46631' />
+  <node id='-254' visible='true' lat='53.72041' lon='7.48139' />
+  <node id='-252' visible='true' lat='53.72924' lon='7.485' />
+  <node id='-250' visible='true' lat='53.72611' lon='7.47633' />
+  <node id='-248' visible='true' lat='53.72235' lon='7.49117' />
+  <node id='-246' visible='true' lat='53.73194' lon='7.51284' />
+  <node id='-244' visible='true' lat='53.74335' lon='7.50351' />
+  <node id='-242' visible='true' lat='53.74133' lon='7.46772' />
+  <node id='-240' visible='true' lat='53.74473' lon='7.5201' />
+  <node id='-238' visible='true' lat='53.744' lon='7.53916' />
+  <node id='-236' visible='true' lat='53.74741' lon='7.55918' />
+  <node id='-234' visible='true' lat='53.75851' lon='7.55534' />
+  <node id='-232' visible='true' lat='53.75665' lon='7.51804' />
+  <node id='-230' visible='true' lat='53.74603' lon='7.51818' />
+  <node id='-228' visible='true' lat='53.74879' lon='7.57262' />
+  <node id='-226' visible='true' lat='53.74822' lon='7.58866' />
+  <node id='-224' visible='true' lat='53.74684' lon='7.60004' />
+  <node id='-222' visible='true' lat='53.74668' lon='7.60566' />
+  <node id='-220' visible='true' lat='53.74643' lon='7.60923' />
+  <node id='-218' visible='true' lat='53.74668' lon='7.6202' />
+  <node id='-216' visible='true' lat='53.74716' lon='7.63185' />
+  <node id='-214' visible='true' lat='53.7483' lon='7.63158' />
+  <node id='-212' visible='true' lat='53.74862' lon='7.62979' />
+  <node id='-210' visible='true' lat='53.7513' lon='7.63281' />
+  <node id='-208' visible='true' lat='53.75195' lon='7.64076' />
+  <node id='-206' visible='true' lat='53.75341' lon='7.64268' />
+  <node id='-204' visible='true' lat='53.75527' lon='7.64268' />
+  <node id='-202' visible='true' lat='53.75705' lon='7.63596' />
+  <node id='-200' visible='true' lat='53.75819' lon='7.62664' />
+  <node id='-198' visible='true' lat='53.75868' lon='7.60127' />
+  <node id='-196' visible='true' lat='53.7453' lon='7.46731' />
+  <node id='-194' visible='true' lat='53.75114' lon='7.47225' />
+  <node id='-192' visible='true' lat='53.75609' lon='7.49182' />
+  <node id='-190' visible='true' lat='53.75575' lon='7.47831' />
+  <node id='-188' visible='true' lat='53.75251' lon='7.48939' />
+  <node id='-186' visible='true' lat='53.75608' lon='7.51174' />
+  <node id='-184' visible='true' lat='53.66609' lon='7.34469' />
+  <node id='-182' visible='true' lat='53.67469' lon='7.35238' />
+  <node id='-180' visible='true' lat='53.68083' lon='7.35357' />
+  <node id='-178' visible='true' lat='53.67829' lon='7.37368' />
+  <node id='-176' visible='true' lat='53.68663' lon='7.37415' />
+  <node id='-174' visible='true' lat='53.68839' lon='7.39151' />
+  <node id='-172' visible='true' lat='53.68566' lon='7.44579' />
+  <node id='-170' visible='true' lat='53.68436' lon='7.47458' />
+  <node id='-168' visible='true' lat='53.68208' lon='7.48692' />
+  <node id='-166' visible='true' lat='53.67543' lon='7.50666' />
+  <node id='-164' visible='true' lat='53.67104' lon='7.51708' />
+  <node id='-162' visible='true' lat='53.67039' lon='7.5297' />
+  <node id='-160' visible='true' lat='53.67201' lon='7.53409' />
+  <node id='-158' visible='true' lat='53.67364' lon='7.54944' />
+  <node id='-156' visible='true' lat='53.62488' lon='7.55164' />
+  <node id='-154' visible='true' lat='53.62714' lon='7.34223' />
+  <node id='-152' visible='true' lat='53.65577' lon='7.39313' />
+  <node id='-150' visible='true' lat='53.66584' lon='7.41754' />
+  <node id='-148' visible='true' lat='53.65414' lon='7.4584' />
+  <node id='-146' visible='true' lat='53.64114' lon='7.4222' />
+  <node id='-144' visible='true' lat='53.64715' lon='7.38847' />
+  <node id='-142' visible='true' lat='53.7204' lon='7.55273' />
+  <node id='-140' visible='true' lat='53.71212' lon='7.57056' />
+  <node id='-138' visible='true' lat='53.71878' lon='7.59332' />
+  <node id='-136' visible='true' lat='53.7277' lon='7.58619' />
+  <node id='-134' visible='true' lat='53.72786' lon='7.56316' />
+  <node id='-132' visible='true' lat='53.70417' lon='7.57029' />
+  <node id='-130' visible='true' lat='53.69914' lon='7.59689' />
+  <node id='-128' visible='true' lat='53.71602' lon='7.62157' />
+  <node id='-126' visible='true' lat='53.72316' lon='7.60539' />
+  <node id='-124' visible='true' lat='53.72056' lon='7.5733' />
+  <node id='-122' visible='true' lat='53.77018' lon='7.32458' />
+  <node id='-120' visible='true' lat='53.77018' lon='7.36818' />
+  <node id='-118' visible='true' lat='53.77359' lon='7.38847' />
+  <node id='-116' visible='true' lat='53.77748' lon='7.3956' />
+  <node id='-114' visible='true' lat='53.78137' lon='7.39807' />
+  <node id='-112' visible='true' lat='53.78477' lon='7.4063' />
+  <node id='-110' visible='true' lat='53.7872' lon='7.41699' />
+  <node id='-108' visible='true' lat='53.79206' lon='7.41864' />
+  <node id='-106' visible='true' lat='53.7974' lon='7.41617' />
+  <node id='-104' visible='true' lat='53.79967' lon='7.40492' />
+  <node id='-102' visible='true' lat='53.80048' lon='7.3871' />
+  <node id='-100' visible='true' lat='53.79773' lon='7.36544' />
+  <node id='-98' visible='true' lat='53.78963' lon='7.34322' />
+  <node id='-96' visible='true' lat='53.78412' lon='7.32979' />
+  <node id='-94' visible='true' lat='53.77683' lon='7.32156' />
+  <node id='-92' visible='true' lat='53.77958' lon='7.47293' />
+  <node id='-90' visible='true' lat='53.78396' lon='7.50145' />
+  <node id='-88' visible='true' lat='53.79093' lon='7.50804' />
+  <node id='-86' visible='true' lat='53.79514' lon='7.49624' />
+  <node id='-84' visible='true' lat='53.79732' lon='7.48294' />
+  <node id='-82' visible='true' lat='53.79271' lon='7.45483' />
+  <node id='-80' visible='true' lat='53.78769' lon='7.44743' />
+  <node id='-78' visible='true' lat='53.78282' lon='7.4477' />
+  <node id='-76' visible='true' lat='53.78282' lon='7.4477' />
+  <node id='-74' visible='true' lat='53.79732' lon='7.48294' />
+  <node id='-72' visible='true' lat='53.69958' lon='7.49462' />
+  <node id='-70' visible='true' lat='53.69067' lon='7.50333' />
+  <node id='-68' visible='true' lat='53.69039' lon='7.5224' />
+  <node id='-66' visible='true' lat='53.69819' lon='7.52687' />
+  <node id='-64' visible='true' lat='53.70363' lon='7.52098' />
+  <node id='-62' visible='true' lat='53.69791' lon='7.51628' />
+  <node id='-60' visible='true' lat='53.69248' lon='7.53134' />
+  <node id='-58' visible='true' lat='53.70209' lon='7.54523' />
+  <node id='-56' visible='true' lat='53.7099' lon='7.53111' />
+  <node id='-54' visible='true' lat='53.70864' lon='7.51251' />
+  <node id='-52' visible='true' lat='53.6334' lon='7.25437' />
+  <node id='-50' visible='true' lat='53.64218' lon='7.29264' />
+  <node id='-48' visible='true' lat='53.6321' lon='7.3096' />
+  <node id='-46' visible='true' lat='53.64218' lon='7.29264' />
+  <node id='-44' visible='true' lat='53.64948' lon='7.30645' />
+  <node id='-42' visible='true' lat='53.66011' lon='7.2895' />
+  <node id='-40' visible='true' lat='53.65149' lon='7.2563' />
+  <node id='-38' visible='true' lat='53.66621' lon='7.2557' />
+  <node id='-36' visible='true' lat='53.67475' lon='7.2941' />
+  <node id='-34' visible='true' lat='53.66492' lon='7.31094' />
+  <node id='-32' visible='true' lat='53.68228' lon='7.30779' />
+  <node id='-30' visible='true' lat='53.6929' lon='7.29083' />
+  <node id='-28' visible='true' lat='53.68429' lon='7.25764' />
+  <node id='-26' visible='true' lat='53.64637' lon='7.59305' />
+  <node id='-24' visible='true' lat='53.65894' lon='7.60126' />
+  <node id='-22' visible='true' lat='53.85003' lon='7.4003' />
+  <node id='-20' visible='true' lat='53.87022' lon='7.4293' />
+  <node id='-18' visible='true' lat='53.8625' lon='7.48075' />
+  <node id='-16' visible='true' lat='53.83807' lon='7.45677' />
+  <node id='-14' visible='true' lat='53.84025' lon='7.40902' />
+  <node id='-12' visible='true' lat='53.85054' lon='7.43366' />
+  <node id='-10' visible='true' lat='53.85389' lon='7.42777' />
+  <node id='-8' visible='true' lat='53.85787' lon='7.43562' />
+  <node id='-6' visible='true' lat='53.85466' lon='7.4487' />
+  <node id='-4' visible='true' lat='53.84874' lon='7.44194' />
+  <way id='-556' visible='true'>
+    <nd ref='-554' />
+    <nd ref='-555' />
+    <nd ref='-557' />
+    <nd ref='-559' />
+    <nd ref='-561' />
+    <nd ref='-563' />
+    <nd ref='-554' />
+    <tag k='error' v='hole nested in hole' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-539' visible='true'>
+    <nd ref='-537' />
+    <nd ref='-538' />
+    <nd ref='-540' />
+    <nd ref='-542' />
+    <nd ref='-544' />
+    <nd ref='-546' />
+    <nd ref='-548' />
+    <nd ref='-550' />
+    <nd ref='-537' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-516' visible='true'>
+    <nd ref='-514' />
+    <nd ref='-515' />
+    <nd ref='-517' />
+    <nd ref='-519' />
+    <nd ref='-521' />
+    <nd ref='-523' />
+    <nd ref='-525' />
+    <nd ref='-527' />
+    <nd ref='-529' />
+    <nd ref='-531' />
+    <nd ref='-533' />
+    <nd ref='-514' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-510' visible='true'>
+    <nd ref='-418' />
+    <nd ref='-416' />
+    <nd ref='-414' />
+    <tag k='error' v='part is reversed' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-508' visible='true'>
+    <nd ref='-418' />
+    <nd ref='-420' />
+    <nd ref='-422' />
+    <nd ref='-424' />
+    <nd ref='-426' />
+    <nd ref='-410' />
+    <nd ref='-412' />
+    <nd ref='-414' />
+    <tag k='error' v='part is reversed' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-506' visible='true'>
+    <nd ref='-408' />
+    <nd ref='-398' />
+    <nd ref='-396' />
+    <tag k='natural' v='coastline' />
+  </way>
+  <way id='-504' visible='true'>
+    <nd ref='-396' />
+    <nd ref='-398' />
+    <nd ref='-408' />
+    <tag k='natural' v='coastline' />
+  </way>
+  <way id='-502' visible='true'>
+    <nd ref='-408' />
+    <nd ref='-400' />
+    <nd ref='-402' />
+    <nd ref='-404' />
+    <nd ref='-406' />
+    <nd ref='-390' />
+    <nd ref='-392' />
+    <nd ref='-394' />
+    <nd ref='-396' />
+    <tag k='natural' v='coastline' />
+  </way>
+  <way id='-500' visible='true'>
+    <nd ref='-388' />
+    <nd ref='-374' />
+    <nd ref='-376' />
+    <tag k='natural' v='coastline' />
+  </way>
+  <way id='-498' visible='true'>
+    <nd ref='-388' />
+    <nd ref='-374' />
+    <nd ref='-376' />
+    <tag k='natural' v='coastline' />
+  </way>
+  <way id='-496' visible='true'>
+    <nd ref='-376' />
+    <nd ref='-378' />
+    <nd ref='-380' />
+    <nd ref='-382' />
+    <nd ref='-384' />
+    <nd ref='-386' />
+    <nd ref='-372' />
+    <nd ref='-388' />
+    <tag k='natural' v='coastline' />
+  </way>
+  <way id='-494' visible='true'>
+    <nd ref='-364' />
+    <nd ref='-362' />
+    <tag k='error' v='double coastline' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-492' visible='true'>
+    <nd ref='-364' />
+    <nd ref='-370' />
+    <nd ref='-368' />
+    <nd ref='-362' />
+    <tag k='error' v='double coastline' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-490' visible='true'>
+    <nd ref='-362' />
+    <nd ref='-360' />
+    <nd ref='-358' />
+    <nd ref='-366' />
+    <nd ref='-364' />
+    <tag k='error' v='double coastline' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-488' visible='true'>
+    <nd ref='-350' />
+    <nd ref='-352' />
+    <nd ref='-354' />
+    <nd ref='-356' />
+    <nd ref='-350' />
+    <tag k='natural' v='coastline' />
+    <tag k='note' v='Land inside lake inside land' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-486' visible='true'>
+    <nd ref='-342' />
+    <nd ref='-344' />
+    <nd ref='-346' />
+    <nd ref='-348' />
+    <nd ref='-334' />
+    <tag k='error' v='orientation' />
+    <tag k='natural' v='coastline' />
+  </way>
+  <way id='-484' visible='true'>
+    <nd ref='-334' />
+    <nd ref='-336' />
+    <nd ref='-338' />
+    <nd ref='-340' />
+    <nd ref='-342' />
+    <tag k='error' v='orientation' />
+    <tag k='natural' v='coastline' />
+  </way>
+  <way id='-482' visible='true'>
+    <nd ref='-330' />
+    <nd ref='-332' />
+    <nd ref='-316' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-480' visible='true'>
+    <nd ref='-328' />
+    <nd ref='-322' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-478' visible='true'>
+    <nd ref='-322' />
+    <nd ref='-324' />
+    <nd ref='-326' />
+    <nd ref='-330' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-476' visible='true'>
+    <nd ref='-316' />
+    <nd ref='-318' />
+    <nd ref='-320' />
+    <nd ref='-328' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-474' visible='true'>
+    <nd ref='-314' />
+    <nd ref='-312' />
+    <nd ref='-310' />
+    <nd ref='-308' />
+    <nd ref='-306' />
+    <nd ref='-304' />
+    <nd ref='-302' />
+    <nd ref='-300' />
+    <nd ref='-298' />
+    <nd ref='-314' />
+    <tag k='error' v='orientation' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-472' visible='true'>
+    <nd ref='-294' />
+    <nd ref='-292' />
+    <nd ref='-290' />
+    <nd ref='-288' />
+    <nd ref='-286' />
+    <nd ref='-284' />
+    <nd ref='-282' />
+    <nd ref='-280' />
+    <nd ref='-278' />
+    <nd ref='-276' />
+    <nd ref='-274' />
+    <nd ref='-272' />
+    <nd ref='-270' />
+    <nd ref='-268' />
+    <nd ref='-266' />
+    <nd ref='-264' />
+    <nd ref='-262' />
+    <nd ref='-260' />
+    <nd ref='-294' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-470' visible='true'>
+    <nd ref='-258' />
+    <nd ref='-256' />
+    <nd ref='-254' />
+    <nd ref='-252' />
+    <nd ref='-250' />
+    <nd ref='-248' />
+    <nd ref='-246' />
+    <nd ref='-244' />
+    <nd ref='-242' />
+    <nd ref='-258' />
+    <tag k='error' v='self-intersection' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-468' visible='true'>
+    <nd ref='-240' />
+    <nd ref='-238' />
+    <nd ref='-236' />
+    <nd ref='-234' />
+    <nd ref='-232' />
+    <nd ref='-230' />
+    <tag k='error' v='not closed' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-466' visible='true'>
+    <nd ref='-228' />
+    <nd ref='-226' />
+    <nd ref='-224' />
+    <nd ref='-222' />
+    <tag k='error' v='not connected' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-464' visible='true'>
+    <nd ref='-220' />
+    <nd ref='-218' />
+    <nd ref='-216' />
+    <nd ref='-214' />
+    <nd ref='-212' />
+    <nd ref='-210' />
+    <nd ref='-208' />
+    <nd ref='-206' />
+    <nd ref='-204' />
+    <nd ref='-202' />
+    <nd ref='-200' />
+    <nd ref='-198' />
+    <tag k='error' v='not connected' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-462' visible='true'>
+    <nd ref='-196' />
+    <nd ref='-194' />
+    <nd ref='-192' />
+    <nd ref='-428' />
+    <nd ref='-190' />
+    <nd ref='-188' />
+    <nd ref='-186' />
+    <tag k='error' v='self-intersection' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-460' visible='true'>
+    <nd ref='-184' />
+    <nd ref='-154' />
+    <nd ref='-156' />
+    <nd ref='-158' />
+    <nd ref='-160' />
+    <nd ref='-162' />
+    <nd ref='-164' />
+    <nd ref='-166' />
+    <nd ref='-168' />
+    <nd ref='-170' />
+    <nd ref='-172' />
+    <nd ref='-174' />
+    <nd ref='-176' />
+    <nd ref='-178' />
+    <nd ref='-180' />
+    <nd ref='-182' />
+    <nd ref='-184' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-458' visible='true'>
+    <nd ref='-152' />
+    <nd ref='-150' />
+    <nd ref='-148' />
+    <nd ref='-146' />
+    <nd ref='-144' />
+    <nd ref='-152' />
+    <tag k='natural' v='coastline' />
+    <tag k='note' v='inside lake' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-456' visible='true'>
+    <nd ref='-142' />
+    <nd ref='-140' />
+    <nd ref='-138' />
+    <nd ref='-136' />
+    <nd ref='-134' />
+    <nd ref='-142' />
+    <tag k='error' v='overlap' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-454' visible='true'>
+    <nd ref='-132' />
+    <nd ref='-130' />
+    <nd ref='-128' />
+    <nd ref='-126' />
+    <nd ref='-124' />
+    <nd ref='-132' />
+    <tag k='error' v='overlap' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-452' visible='true'>
+    <nd ref='-122' />
+    <nd ref='-120' />
+    <nd ref='-118' />
+    <nd ref='-116' />
+    <nd ref='-114' />
+    <nd ref='-112' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-450' visible='true'>
+    <nd ref='-112' />
+    <nd ref='-110' />
+    <nd ref='-108' />
+    <nd ref='-106' />
+    <nd ref='-104' />
+    <nd ref='-102' />
+    <nd ref='-100' />
+    <nd ref='-98' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-448' visible='true'>
+    <nd ref='-98' />
+    <nd ref='-96' />
+    <nd ref='-94' />
+    <nd ref='-122' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-446' visible='true'>
+    <nd ref='-76' />
+    <nd ref='-92' />
+    <nd ref='-90' />
+    <nd ref='-88' />
+    <nd ref='-86' />
+    <nd ref='-74' />
+    <tag k='error' v='node ids don't match but same pos' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-444' visible='true'>
+    <nd ref='-84' />
+    <nd ref='-82' />
+    <nd ref='-80' />
+    <nd ref='-78' />
+    <tag k='error' v='node ids don't match but same pos' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-442' visible='true'>
+    <nd ref='-54' />
+    <nd ref='-72' />
+    <nd ref='-70' />
+    <nd ref='-68' />
+    <nd ref='-66' />
+    <tag k='error' v='intersection' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-440' visible='true'>
+    <nd ref='-66' />
+    <nd ref='-64' />
+    <nd ref='-62' />
+    <nd ref='-60' />
+    <nd ref='-58' />
+    <nd ref='-56' />
+    <nd ref='-54' />
+    <tag k='error' v='intersection' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-438' visible='true'>
+    <nd ref='-52' />
+    <nd ref='-50' />
+    <nd ref='-48' />
+    <nd ref='-46' />
+    <nd ref='-44' />
+    <nd ref='-42' />
+    <nd ref='-40' />
+    <nd ref='-52' />
+    <tag k='error' v='lines overlap' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-436' visible='true'>
+    <nd ref='-38' />
+    <nd ref='-36' />
+    <nd ref='-34' />
+    <nd ref='-36' />
+    <nd ref='-32' />
+    <nd ref='-30' />
+    <nd ref='-28' />
+    <nd ref='-38' />
+    <tag k='error' v='lines overlap' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-434' visible='true'>
+    <nd ref='-24' />
+    <nd ref='-26' />
+    <nd ref='-24' />
+    <tag k='error' v='less than 4 nodes' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-432' visible='true'>
+    <nd ref='-22' />
+    <nd ref='-14' />
+    <nd ref='-16' />
+    <nd ref='-18' />
+    <nd ref='-20' />
+    <nd ref='-22' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-430' visible='true'>
+    <nd ref='-12' />
+    <nd ref='-10' />
+    <nd ref='-8' />
+    <nd ref='-6' />
+    <nd ref='-4' />
+    <nd ref='-12' />
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='ok' />
+  </way>
+  <way id='-1' visible='true'>
+    <nd ref='-564'/>
+    <nd ref='-565'/>
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+  <way id='-2' visible='true'>
+    <nd ref='-564'/>
+    <nd ref='-566'/>
+    <nd ref='-566'/>
+    <tag k='natural' v='coastline' />
+    <tag k='status' v='error' />
+  </way>
+</osm>
diff --git a/verbose_output.hpp b/verbose_output.hpp
new file mode 100644
index 0000000..555a592
--- /dev/null
+++ b/verbose_output.hpp
@@ -0,0 +1,48 @@
+#ifndef VERBOSE_OUTPUT_HPP
+#define VERBOSE_OUTPUT_HPP
+
+class VerboseOutput {
+
+    time_t m_start;
+    bool m_verbose;
+    bool m_newline;
+
+public:
+
+    VerboseOutput(bool verbose) :
+        m_start(time(nullptr)),
+        m_verbose(verbose),
+        m_newline(true) {
+    }
+
+    int runtime() const {
+        return time(nullptr) - m_start;
+    }
+
+    void start_line() {
+        if (m_newline) {
+            int elapsed = time(nullptr) - m_start;
+            char timestr[20];
+            snprintf(timestr, sizeof(timestr)-1, "[%2d:%02d] ", elapsed / 60, elapsed % 60);
+            std::cerr << timestr;
+            m_newline = false;
+        }
+    }
+
+    template<typename T>
+    friend VerboseOutput& operator<<(VerboseOutput& out, T t) {
+        if (out.m_verbose) {
+            std::ostringstream o;
+            o << t;
+            out.start_line();
+            std::cerr << o.str();
+            if (o.str()[o.str().size()-1] == '\n') {
+                out.m_newline = true;
+            }
+        }
+        return out;
+    }
+
+}; // class VerboseOutput
+
+#endif // VERBOSE_OUTPUT_HPP

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osmcoastline.git



More information about the Pkg-grass-devel mailing list