[osm2pgsql] 03/09: Imported Upstream version 0.87.4

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Mon Jul 6 06:50:51 UTC 2015


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

sebastic pushed a commit to branch master
in repository osm2pgsql.

commit a8c2a65b8670dc86e1af71210c6a5031cb4ac23d
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Mon Jul 6 08:02:55 2015 +0200

    Imported Upstream version 0.87.4
---
 .travis.yml                                   |  92 ++-
 Makefile.am                                   |  29 +-
 UTF8sanitizer.cpp                             |  10 +-
 configure.ac                                  |  29 +-
 default.style                                 |  10 +-
 docs/osm2pgsql.1                              |   7 +-
 empty.style                                   |   2 +-
 expire-tiles.cpp                              |  14 +-
 expire-tiles.hpp                              |   8 +-
 geometry-builder.cpp                          |  18 +-
 geometry-processor.cpp                        |   8 +-
 geometry-processor.hpp                        |  12 +-
 input.cpp                                     |   9 +-
 input.hpp                                     |   1 +
 m4/ax_cxx_compile_stdcxx_11.m4                | 142 ++++
 middle-pgsql.cpp                              |  20 +-
 middle-ram.cpp                                |   9 +-
 middle-ram.hpp                                |   6 +-
 middle.hpp                                    |   7 +-
 multi.lua                                     |   4 +-
 multi.style.json                              |   2 +-
 node-persistent-cache-reader.cpp              |  30 +-
 node-persistent-cache.cpp                     | 361 ++++------
 node-persistent-cache.hpp                     |  18 +-
 node-ram-cache.cpp                            | 113 ++--
 node-ram-cache.hpp                            |  83 ++-
 options.cpp                                   |   5 -
 osm2pgsql.cpp                                 |   8 +-
 osmdata.cpp                                   |  44 +-
 output-multi.cpp                              |  12 +-
 output-multi.hpp                              |  20 +-
 output-null.cpp                               |  13 +-
 output-pgsql.cpp                              |   2 +-
 output.hpp                                    |   9 +-
 parse-o5m.cpp                                 |  11 +-
 parse-o5m.hpp                                 |   5 +-
 parse-pbf.cpp                                 |  21 +-
 parse-pbf.hpp                                 |  10 +-
 parse-xml2.cpp                                |  11 +-
 parse-xml2.hpp                                |   1 -
 parse.cpp                                     |  14 +-
 parse.hpp                                     |   9 +-
 pgsql-id-tracker.cpp                          |   4 +-
 pgsql-id-tracker.hpp                          |   3 +
 pgsql.cpp                                     |   8 +-
 processor-line.cpp                            |   2 -
 processor-point.cpp                           |  11 +-
 processor-point.hpp                           |   5 +-
 processor-polygon.cpp                         |   2 -
 rb.cpp                                        | 930 --------------------------
 rb.hpp                                        | 122 ----
 reprojection.cpp                              |  13 +-
 reprojection.hpp                              |   2 +-
 sanitizer.hpp                                 |   1 -
 style.lua                                     | 137 ++--
 table.cpp                                     |  19 +-
 table.hpp                                     |   9 +-
 tagtransform.cpp                              |  20 +-
 tagtransform.hpp                              |  13 +-
 tests/middle-tests.cpp                        | 140 +++-
 tests/middle-tests.hpp                        |   3 +
 tests/regression-test.py                      |   2 +-
 tests/test-expire-tiles.cpp                   |   1 +
 tests/test-middle-pgsql.cpp                   |  95 ++-
 tests/test-middle-ram.cpp                     |  62 +-
 tests/test-output-multi-line-storage.cpp      |   2 +-
 tests/test-output-multi-line.cpp              |   2 +-
 tests/test-output-multi-point-multi-table.cpp |   2 +-
 tests/test-output-multi-point.cpp             |   2 +-
 tests/test-output-multi-poly-trivial.cpp      |   2 +-
 tests/test-output-multi-polygon.cpp           |   2 +-
 tests/test-output-multi-tags.cpp              |   2 +-
 tests/test-output-pgsql.cpp                   |   4 +-
 tests/test-parse-options.cpp                  |   1 -
 tests/test-parse-xml2.cpp                     |   1 +
 util.hpp                                      |   7 +-
 76 files changed, 1027 insertions(+), 1843 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 52f3c92..d339253 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,43 +1,73 @@
 language: cpp
-compiler:
-  - gcc
-  - clang
-env:
-  - USE_LUA=true  BOOST_PPA=false
-  - USE_LUA=true  BOOST_PPA=1.54
-  - USE_LUA=true  BOOST_PPA=1.55
-# Skip some parts of the matrix for speed
-#  - USE_LUA=false BOOST_PPA=false
-#  - USE_LUA=false BOOST_PPA=1.54
-  - USE_LUA=false BOOST_PPA=1.55
+
+addons:
+  apt:
+    packages:
+    - libtool
+    - libxml2-dev
+    - libgeos-dev
+    - libgeos++-dev
+    - libpq-dev
+    - libbz2-dev
+    - libproj-dev
+    - protobuf-c-compiler
+    - libprotobuf-c0-dev
+
+matrix:
+  include:
+    #basic tests of with/without lua and old boost versions, with both clang and gc
+    - os: linux
+      compiler: clang
+      env: USE_LUA=true
+    - os: linux
+      compiler: clang
+      env: USE_LUA=true BOOST_PPA=1.55
+    - os: linux
+      compiler: clang
+      env: USE_LUA=false BOOST_PPA=1.55
+    - os: linux
+      compiler: gcc
+      env: USE_LUA=true
+    - os: linux
+      compiler: gcc
+      env: USE_LUA=true BOOST_PPA=1.55
+    - os: linux
+      compiler: gcc
+      env: USE_LUA=false BOOST_PPA=1.55
+    # additional tests
+    - os: linux
+      compiler: clang
+      env: USE_LUA=true BOOST_PPA=1.54
+
 before_install:
-  - |-
-    if [ "${BOOST_PPA}" != "false" ]; then
-      sudo add-apt-repository -y ppa:boost-latest/ppa
-    fi
-  - sudo apt-get update -qq
-install:
-  - sudo apt-get install -y -qq autoconf automake libtool make g++ libpq-dev libxml2-dev libbz2-dev libproj0 proj-bin libproj-dev # core deps
-  - |-
-    if [ "${BOOST_PPA}" = "false" ]; then
-      sudo apt-get install -y -qq libboost1.48-all-dev
+  # BOOST_PPA is only set on linux
+  - if [ -z ${BOOST_PPA+x} ]; then
+      echo "Using system Boost";
     else
-      sudo apt-get install -y -qq boost${BOOST_PPA}
+      echo "Using Boost PPA";
+      sudo add-apt-repository -y ppa:boost-latest/ppa;
     fi
-  - sudo apt-get install -y -qq protobuf-c-compiler libprotobuf-c0-dev
-  - sudo apt-get install -y -qq libgeos-3.3.3 libgeos-dev libgeos++-dev
-  - |-
-    if [ "${USE_LUA}" = "true" ]; then
-      sudo apt-get install -y -qq lua5.2 liblua5.2-dev
+  - if [[ $(uname -s) == 'Linux' ]]; then
+      sudo apt-get update -qq;
     fi
+install:
+  - if [[ $(uname -s) == 'Linux' ]]; then
+      if [ -z ${BOOST_PPA+x} ]; then
+        sudo apt-get install -y -qq libboost1.48-all-dev;
+      else
+        sudo apt-get install -y -qq "boost${BOOST_PPA}";
+      fi;
+      if [[ "${USE_LUA}" = "true" ]]; then
+        sudo apt-get install -y -qq lua5.2 liblua5.2-dev;
+      fi;
+    fi;
 before_script:
   - xml2-config --version
   - geos-config --version
   - proj | head -n1
-  - |-
-    if [ "${USE_LUA}" = "true" ]; then
-      lua -v
-    fi
+  - if [ "${USE_LUA}" = "true" ]; then
+      lua -v;
+    fi;
 script:
   ./autogen.sh && ./configure && make -j2
 after_failure:
diff --git a/Makefile.am b/Makefile.am
index b4c0ef9..8ce3f4f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,33 +4,7 @@ AUTOMAKE_OPTIONS = subdir-objects
 bin_PROGRAMS = osm2pgsql nodecachefilereader
 noinst_LTLIBRARIES = libosm2pgsql.la
 
-osm2pgsql_SOURCES = osm2pgsql.cpp \
-	geometry-builder.hpp \
-	expire-tiles.hpp \
-	input.hpp \
-	middle-pgsql.hpp \
-	middle-ram.hpp \
-	middle.hpp \
-	node-persistent-cache.hpp \
-	node-ram-cache.hpp \
-	options.hpp \
-	osmdata.hpp \
-	osmtypes.hpp \
-	output-gazetteer.hpp \
-	output-null.hpp \
-	output-pgsql.hpp \
-	output.hpp \
-	parse.hpp \
-	parse-o5m.hpp \
-	parse-pbf.hpp \
-	parse-xml2.hpp \
-	pgsql.hpp \
-	rb.hpp \
-	reprojection.hpp \
-	sanitizer.hpp \
-	sprompt.hpp \
-	table.hpp \
-	util.hpp
+osm2pgsql_SOURCES = osm2pgsql.cpp
 
 osm2pgsql_LDADD = libosm2pgsql.la
 
@@ -62,7 +36,6 @@ libosm2pgsql_la_SOURCES = \
 	processor-line.cpp \
 	processor-point.cpp \
 	processor-polygon.cpp \
-	rb.cpp \
 	reprojection.cpp \
 	sprompt.cpp \
 	table.cpp \
diff --git a/UTF8sanitizer.cpp b/UTF8sanitizer.cpp
index c0f2753..604067d 100644
--- a/UTF8sanitizer.cpp
+++ b/UTF8sanitizer.cpp
@@ -1,10 +1,6 @@
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <zlib.h>
-#include <bzlib.h>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
 
 #include "sanitizer.hpp"
 #include "input.hpp"
diff --git a/configure.ac b/configure.ac
index 91a3d1d..278de33 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_INIT(osm2pgsql, 0.87.3)
+AC_INIT(osm2pgsql, 0.87.4)
 
 dnl Required autoconf version
 AC_PREREQ(2.61)
@@ -112,17 +112,21 @@ AX_BOOST_BASE([1.48], , [AC_MSG_ERROR([cannot find Boost libraries, which are ar
 AX_BOOST_SYSTEM
 AX_BOOST_FILESYSTEM
 AX_BOOST_THREAD
+if test "x$BOOST_SYSTEM_LIB" = "x" -o "x$BOOST_FILESYSTEM_LIB" = "x" -o "x$BOOST_THREAD_LIB" = "x"
+then
+    AC_MSG_ERROR([One or more of the mandatory Boost libraries not found.])
+fi
 
-dnl Check if Boost is recent enough for lockfree, and if it hasn't been overridden
-AC_ARG_WITH([lockfree],
-  [AS_HELP_STRING([--without-lockfree],
-    [disable lockfree queue])],
+dnl Boost json parser in 1.49 has a bug when compiled with C++11
+dnl see https://svn.boost.org/trac/boost/ticket/6785
+AC_ARG_WITH([cxx11],
+  [AS_HELP_STRING([--without-cxx11],
+    [do not check for C++11-capable compiler (for testing only)])],
     [],
-    [with_lockfree=yes])
+    [with_cxx11=yes])
 
-if test "x$with_lockfree" = "xyes"
-then
-  AX_BOOST_BASE([1.53], AC_DEFINE([HAVE_LOCKFREE], [1], [Using lockfree queue]), [])
+if test "x$with_cxx11" = "xyes"; then
+    AX_BOOST_BASE([1.50], [ AX_CXX_COMPILE_STDCXX_11(,optional) ], [])
 fi
 
 dnl Check for Lua libraries and headers
@@ -135,6 +139,13 @@ AX_PROG_LUA([5.0],[],[
     ],[AC_MSG_WARN([cannot find Lua includes])])
 ],[AC_MSG_WARN([cannot find Lua interpreter])])
 
+dnl Enable fixed point
+AC_ARG_WITH([fixed-point],
+  [AS_HELP_STRING([--without-fixed-point],
+    [use double instead of fixed point floats for coordinates])],
+    [],
+    [AC_DEFINE([FIXED_POINT], [1], [Store +-20,000km Mercator co-ordinates as fixed point 32bit number with maximum precision])])
+
 dnl Generate Makefile
 AC_OUTPUT(Makefile)
 
diff --git a/default.style b/default.style
index 690f3d1..30cd48c 100644
--- a/default.style
+++ b/default.style
@@ -86,9 +86,9 @@ node,way   admin_level  text         linear
 node,way   aerialway    text         linear
 node,way   aeroway      text         polygon
 node,way   amenity      text         polygon
-node,way   area         text         # hard coded support for area=1/yes => polygon is in osm2pgsql
+node,way   area         text         polygon # hard coded support for area=1/yes => polygon is in osm2pgsql
 node,way   barrier      text         linear
-node,way   bicycle      text
+node,way   bicycle      text         linear
 node,way   brand        text         linear
 node,way   bridge       text         linear
 node,way   boundary     text         linear
@@ -123,14 +123,14 @@ node,way   office       text         polygon
 node,way   oneway       text         linear
 node,way   operator     text         linear
 node,way   place        text         polygon
-node       poi          text
+node       poi          text         linear
 node,way   population   text         linear
 node,way   power        text         polygon
 node,way   power_source text         linear
 node,way   public_transport text     polygon
 node,way   railway      text         linear
 node,way   ref          text         linear
-node,way   religion     text
+node,way   religion     text         linear
 node,way   route        text         linear
 node,way   service      text         linear
 node,way   shop         text         polygon
@@ -147,7 +147,7 @@ node,way   wetland      text         polygon
 node,way   width        text         linear
 node,way   wood         text         linear
 node,way   z_order      int4         linear # This is calculated during import
-way        way_area     real                # This is calculated during import
+way        way_area     real         linear # This is calculated during import
 
 # Area tags
 # We don't make columns for these tags, but objects with them are areas.
diff --git a/docs/osm2pgsql.1 b/docs/osm2pgsql.1
index 4d96a5d..bde5149 100644
--- a/docs/osm2pgsql.1
+++ b/docs/osm2pgsql.1
@@ -78,9 +78,6 @@ Store data in degrees of latitude & longitude.
 \fB\-m\fR|\-\-merc
 Store data in proper spherical Mercator (the default).
 .TP
-\fB\-M\fR|\-\-oldmerc
-Store data in the legacy OSM Mercator format.
-.TP
 \fB\-E\fR|\-\-proj num
 Use projection EPSG:num
 .TP
@@ -246,9 +243,9 @@ Verbose output.
 .SH SUPPORTED PROJECTIONS
 Latlong             (\-l) SRS:  4326 (none)
 .br
-WGS84 Mercator      (  ) SRS:  3395 +proj=merc +datum=WGS84  +k=1.0 +units=m +over +no_defs
-.br
 Spherical Mercator  (\-m) SRS:900913 +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over
+.br
+EPSG-defined        (\-E) SRS: +init=epsg:(as given in parameter)
 .PP
 .SH SEE ALSO
 .BR proj (1),
diff --git a/empty.style b/empty.style
index 6c9919d..d06be71 100644
--- a/empty.style
+++ b/empty.style
@@ -34,7 +34,7 @@ node,way    water                   text    phstore
 node,way    waterway                text    phstore
 node,way    wetland                 text    phstore
 node,way    z_order                 int4    linear  # This is calculated during import
-way         way_area                real            # This is calculated during import
+way         way_area                real    linear  # This is calculated during import
 
 # Deleted tags
 # These are tags that are generally regarded as useless for most rendering.
diff --git a/expire-tiles.cpp b/expire-tiles.cpp
index 9e14fd8..3533339 100644
--- a/expire-tiles.cpp
+++ b/expire-tiles.cpp
@@ -8,15 +8,15 @@
  * https://subversion.nexusuk.org/trac/browser/openpistemap/trunk/scripts/expire_tiles.py
  */
 
-#include <libpq-fe.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include "output.hpp"
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <string>
+
+#include "expire-tiles.hpp"
 #include "options.hpp"
 #include "geometry-builder.hpp"
-#include "pgsql.hpp"
 #include "reprojection.hpp"
 #include "table.hpp"
 
diff --git a/expire-tiles.hpp b/expire-tiles.hpp
index 08d6839..64133b6 100644
--- a/expire-tiles.hpp
+++ b/expire-tiles.hpp
@@ -1,15 +1,15 @@
 #ifndef EXPIRE_TILES_H
 #define EXPIRE_TILES_H
 
-#include "options.hpp"
+#include "osmtypes.hpp"
 
 #include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
 
 class table_t;
+struct options_t;
 
 struct expire_tiles : public boost::noncopyable {
-    explicit expire_tiles(const struct options_t *options);
+    explicit expire_tiles(const options_t *options);
     ~expire_tiles();
 
     //TODO: copy constructor
@@ -57,7 +57,7 @@ private:
 
     int map_width;
     double tile_width;
-    const struct options_t *Options;
+    const options_t *Options;
     struct tile *dirty;
 };
 
diff --git a/geometry-builder.cpp b/geometry-builder.cpp
index 0aaf578..143a1cc 100644
--- a/geometry-builder.cpp
+++ b/geometry-builder.cpp
@@ -22,26 +22,29 @@
 
 #include <iostream>
 #include <algorithm>
-#include <cstring>
-#include <cstdlib>
 #include <cmath>
-#include <exception>
+#include <cstddef>
+#include <stdexcept>
+#include <memory>
+#include <new>
 
 #if defined(__CYGWIN__)
 #define GEOS_INLINE
 #endif
 
+#include <geos/geom/prep/PreparedGeometry.h>
 #include <geos/geom/prep/PreparedGeometryFactory.h>
-#include <geos/geom/prep/PreparedPolygon.h>
 #include <geos/geom/GeometryFactory.h>
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/CoordinateSequence.h>
 #include <geos/geom/CoordinateSequenceFactory.h>
 #include <geos/geom/Geometry.h>
+#include <geos/geom/GeometryCollection.h>
 #include <geos/geom/LineString.h>
 #include <geos/geom/LinearRing.h>
 #include <geos/geom/MultiLineString.h>
 #include <geos/geom/Polygon.h>
 #include <geos/geom/MultiPolygon.h>
-#include <geos/geom/Point.h>
 #include <geos/io/WKTReader.h>
 #include <geos/io/WKTWriter.h>
 #include <geos/util/GEOSException.h>
@@ -182,11 +185,12 @@ geometry_builder::maybe_wkts_t geometry_builder::get_wkt_split(const nodelist_t
                 const Coordinate this_pt = coords->getAt(i);
                 const Coordinate prev_pt = coords->getAt(i-1);
                 const double delta = this_pt.distance(prev_pt);
+                assert(!isnan(delta));
                 // figure out if the addition of this point would take the total
                 // length of the line in `segment` over the `split_at` distance.
-                const size_t splits = std::floor((distance + delta) / split_at);
 
-                if (splits > 0) {
+                if (distance + delta > split_at) {
+                  const size_t splits = std::floor((distance + delta) / split_at);
                   // use the splitting distance to split the current segment up
                   // into as many parts as necessary to keep each part below
                   // the `split_at` distance.
diff --git a/geometry-processor.cpp b/geometry-processor.cpp
index 4261693..49f8b22 100644
--- a/geometry-processor.cpp
+++ b/geometry-processor.cpp
@@ -2,20 +2,22 @@
 #include "processor-line.hpp"
 #include "processor-point.hpp"
 #include "processor-polygon.hpp"
-
+#include "middle.hpp"
+#include "options.hpp"
+#include "reprojection.hpp"
 
 #include <boost/make_shared.hpp>
 #include <boost/format.hpp>
+#include <boost/optional.hpp>
 #include <stdexcept>
 
 boost::shared_ptr<geometry_processor> geometry_processor::create(const std::string &type,
                                                                  const options_t *options) {
     boost::shared_ptr<geometry_processor> ptr;
     int srid = options->projection->project_getprojinfo()->srs;
-    double scale = options->scale;
 
     if (type == "point") {
-        ptr = boost::make_shared<processor_point>(srid, scale);
+        ptr = boost::make_shared<processor_point>(srid);
     }
     else if (type == "line") {
         ptr = boost::make_shared<processor_line>(srid);
diff --git a/geometry-processor.hpp b/geometry-processor.hpp
index 98e9077..336553c 100644
--- a/geometry-processor.hpp
+++ b/geometry-processor.hpp
@@ -1,10 +1,16 @@
 #ifndef GEOMETRY_PROCESSOR_HPP
 #define GEOMETRY_PROCESSOR_HPP
 
-#include "middle.hpp"
-#include "geometry-builder.hpp"
+#include <cstddef>
 #include <string>
-#include <boost/optional.hpp>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include "geometry-builder.hpp"
+#include "osmtypes.hpp"
+
+struct middle_query_t;
+struct middle_t;
+struct options_t;
 
 struct geometry_processor {
     // factory method for creating various types of geometry processors either by name or by geometry column type
diff --git a/input.cpp b/input.cpp
index 87c27e5..a56c45b 100644
--- a/input.cpp
+++ b/input.cpp
@@ -6,18 +6,15 @@
 #include <io.h>
 #define STDIN_FILENO 0
 #else
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <cstdio>
 #endif
 
+#include <cstdlib>
+#include <cstring>
 #include <fcntl.h>
 #include <zlib.h>
 #include <bzlib.h>
-#include <string.h>
 
-#include "sanitizer.hpp"
 #include "input.hpp"
 
 struct Input {
diff --git a/input.hpp b/input.hpp
index 6313181..61213b2 100644
--- a/input.hpp
+++ b/input.hpp
@@ -1,6 +1,7 @@
 #ifndef INPUT_H
 #define INPUT_H
 
+#include <libxml/xmlreader.h>
 struct Input;
 
 int readFile(struct Input *context, char * buffer, int len);
diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4
new file mode 100644
index 0000000..163a4c6
--- /dev/null
+++ b/m4/ax_cxx_compile_stdcxx_11.m4
@@ -0,0 +1,142 @@
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the C++11
+#   standard; if necessary, add switches to CXXFLAGS to enable support.
+#
+#   The first argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The second argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline C++11 support is required and that the macro
+#   should error out if no mode with that support is found.  If specified
+#   'optional', then configuration proceeds regardless, after defining
+#   HAVE_CXX11 if and only if a supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz at redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw at panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr at ices.utexas.edu>
+#   Copyright (c) 2014 Alexey Sokolov <sokolov at google.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 4
+
+m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
+  template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+    struct Base {
+    virtual void f() {}
+    };
+    struct Child : public Base {
+    virtual void f() override {}
+    };
+
+    typedef check<check<bool>> right_angle_brackets;
+
+    int a;
+    decltype(a) b;
+
+    typedef check<int> check_type;
+    check_type c;
+    check_type&& cr = static_cast<check_type&&>(c);
+
+    auto d = a;
+    auto l = [](){};
+]])
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
+  m4_if([$1], [], [],
+        [$1], [ext], [],
+        [$1], [noext], [],
+        [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
+  m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
+        [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
+        [$2], [optional], [ax_cxx_compile_cxx11_required=false],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
+  ax_cv_cxx_compile_cxx11,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+    [ax_cv_cxx_compile_cxx11=yes],
+    [ax_cv_cxx_compile_cxx11=no])])
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$1], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=gnu++11 -std=gnu++0x; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$1], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=c++11 -std=c++0x; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
+    fi
+  else
+    if test x$ac_success = xno; then
+      HAVE_CXX11=0
+      AC_MSG_NOTICE([No compiler with C++11 support was found])
+    else
+      HAVE_CXX11=1
+      AC_DEFINE(HAVE_CXX11,1,
+                [define if the compiler supports basic C++11 syntax])
+    fi
+
+    AC_SUBST(HAVE_CXX11)
+  fi
+])
diff --git a/middle-pgsql.cpp b/middle-pgsql.cpp
index 03b17c5..ab198e7 100644
--- a/middle-pgsql.cpp
+++ b/middle-pgsql.cpp
@@ -322,7 +322,9 @@ int middle_pgsql_t::local_nodes_set(const osmid_t& id, const double& lat,
       int length = strlen(tag_buf) + 64;
       char *buffer = (char *)alloca( length );
 #ifdef FIXED_POINT
-      if( snprintf( buffer, length, "%" PRIdOSMID "\t%d\t%d\t%s\n", id, util::double_to_fix(lat, out_options->scale), util::double_to_fix(lon, out_options->scale), tag_buf ) > (length-10) )
+      ramNode n(lon, lat);
+      if( snprintf(buffer, length, "%" PRIdOSMID "\t%d\t%d\t%s\n",
+                   id, n.int_lat(), n.int_lon(), tag_buf ) > (length-10) )
       { fprintf( stderr, "buffer overflow node id %" PRIdOSMID "\n", id); return 1; }
 #else
       if( snprintf( buffer, length, "%" PRIdOSMID "\t%.10f\t%.10f\t%s\n", id, lat, lon, tag_buf ) > (length-10) )
@@ -340,9 +342,10 @@ int middle_pgsql_t::local_nodes_set(const osmid_t& id, const double& lat,
     ptr += sprintf( ptr, "%" PRIdOSMID, id ) + 1;
     paramValues[1] = ptr;
 #ifdef FIXED_POINT
-    ptr += sprintf( ptr, "%d", util::double_to_fix(lat, out_options->scale) ) + 1;
+    ramNode n(lon, lat);
+    ptr += sprintf(ptr, "%d", n.int_lat()) + 1;
     paramValues[2] = ptr;
-    sprintf( ptr, "%d", util::double_to_fix(lon, out_options->scale) );
+    sprintf(ptr, "%d", n.int_lon());
 #else
     ptr += sprintf( ptr, "%.10f", lat ) + 1;
     paramValues[2] = ptr;
@@ -405,8 +408,11 @@ int middle_pgsql_t::local_nodes_get_list(nodelist_t &out, const idlist_t nds) co
         osmid_t id = strtoosmid(PQgetvalue(res, i, 0), NULL, 10);
         osmNode node;
 #ifdef FIXED_POINT
-        node.lat = util::fix_to_double(strtol(PQgetvalue(res, i, 1), NULL, 10), out_options->scale);
-        node.lon = util::fix_to_double(strtol(PQgetvalue(res, i, 2), NULL, 10), out_options->scale);
+        ramNode n((int) strtol(PQgetvalue(res, i, 2), NULL, 10),
+                  (int) strtol(PQgetvalue(res, i, 1), NULL, 10));
+
+        node.lat = n.lat();
+        node.lon = n.lon();
 #else
         node.lat = strtod(PQgetvalue(res, i, 1), NULL);
         node.lon = strtod(PQgetvalue(res, i, 2), NULL);
@@ -1060,7 +1066,7 @@ int middle_pgsql_t::start(const options_t *out_options_)
     build_indexes = 0;
 
     cache.reset(new node_ram_cache( out_options->alloc_chunkwise | ALLOC_LOSSY, out_options->cache, out_options->scale));
-    if (out_options->flat_node_cache_enabled) persistent_cache.reset(new node_persistent_cache(out_options, out_options->append, cache));
+    if (out_options->flat_node_cache_enabled) persistent_cache.reset(new node_persistent_cache(out_options, out_options->append, false, cache));
 
     fprintf(stderr, "Mid: pgsql, scale=%d cache=%d\n", out_options->scale, out_options->cache);
 
@@ -1364,7 +1370,7 @@ boost::shared_ptr<const middle_query_t> middle_pgsql_t::get_instance() const {
     // The persistent cache on the other hand is not thread-safe for reading,
     // so we create one per instance.
     if (out_options->flat_node_cache_enabled)
-        mid->persistent_cache.reset(new node_persistent_cache(out_options,1,cache));
+        mid->persistent_cache.reset(new node_persistent_cache(out_options, 1, true, cache));
 
     // We use a connection per table to enable the use of COPY */
     for(int i=0; i<num_tables; i++) {
diff --git a/middle-ram.cpp b/middle-ram.cpp
index fcaf290..4e79d03 100644
--- a/middle-ram.cpp
+++ b/middle-ram.cpp
@@ -9,20 +9,13 @@
 
 #include <stdexcept>
 #include <cstdio>
-#include <cstdlib>
 #include <cstring>
 #include <cassert>
 
-#include "osmtypes.hpp"
 #include "middle-ram.hpp"
 #include "node-ram-cache.hpp"
-#include "output-pgsql.hpp"
 #include "options.hpp"
-#include "util.hpp"
-
-/* Store +-20,000km Mercator co-ordinates as fixed point 32bit number with maximum precision */
-/* Scale is chosen such that 40,000 * SCALE < 2^32          */
-#define FIXED_POINT
+#include "id-tracker.hpp"
 
 /* Object storage now uses 2 levels of storage arrays.
  *
diff --git a/middle-ram.hpp b/middle-ram.hpp
index 2c68ea4..8eec63b 100644
--- a/middle-ram.hpp
+++ b/middle-ram.hpp
@@ -9,10 +9,14 @@
 #ifndef MIDDLE_RAM_H
 #define MIDDLE_RAM_H
 
+#include <memory>
+
 #include "middle.hpp"
-#include "node-ram-cache.hpp"
 #include <vector>
 
+struct node_ram_cache;
+struct options_t;
+
 struct middle_ram_t : public middle_t {
     middle_ram_t();
     virtual ~middle_ram_t();
diff --git a/middle.hpp b/middle.hpp
index ae685a8..104c653 100644
--- a/middle.hpp
+++ b/middle.hpp
@@ -8,8 +8,11 @@
 #define MIDDLE_H
 
 #include "osmtypes.hpp"
-#include "options.hpp"
-#include <vector>
+
+#include <cstddef>
+#include <boost/shared_ptr.hpp>
+
+struct options_t;
 
 struct middle_query_t {
     virtual ~middle_query_t() {}
diff --git a/multi.lua b/multi.lua
index 283b33b..550c0de 100644
--- a/multi.lua
+++ b/multi.lua
@@ -42,7 +42,7 @@ function building_rels (kv, num_keys)
   return generic_rels(building_interesting, kv)
 end
 
-function builing_rel_members (kv, keyvaluemembers, roles, membercount)
+function building_rel_members (kv, keyvaluemembers, roles, membercount)
   return generic_rel_members(building_interesting, kv, keyvaluemembers, roles, membercount, building_transform)
 end
 
@@ -268,4 +268,4 @@ function generic_rel_members (f, keyvals, keyvaluemembers, roles, membercount, t
   end
   tags =  t(keyvals)
   return filter, tags, membersuperseeded, boundary, polygon, roads
-end
\ No newline at end of file
+end
diff --git a/multi.style.json b/multi.style.json
index 400146c..3c36aee 100644
--- a/multi.style.json
+++ b/multi.style.json
@@ -53,7 +53,7 @@
     "tagtransform-node-function": "drop_all",
     "tagtransform-way-function": "building_ways",
     "tagtransform-relation-function": "building_rels",
-    "tagtransform-relation-member-function": "builing_rel_members",
+    "tagtransform-relation-member-function": "building_rel_members",
     "tags": [
       {"name": "name", "type": "text"},
       {"name": "name_en", "type": "text"},
diff --git a/node-persistent-cache-reader.cpp b/node-persistent-cache-reader.cpp
index 4ca6572..c2c8b68 100644
--- a/node-persistent-cache-reader.cpp
+++ b/node-persistent-cache-reader.cpp
@@ -1,18 +1,12 @@
-#include <stdio.h>
-#include <stdlib.h>
+#include <cstdio>
+#include <cstdlib>
 #include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <math.h>
+#include <cstring>
 #include <sys/wait.h>
 #include <sys/time.h>
+#include <boost/shared_ptr.hpp>
 
 #include "osmtypes.hpp"
-#include "output.hpp"
 #include "options.hpp"
 #include "node-persistent-cache.hpp"
 #include "node-ram-cache.hpp"
@@ -64,7 +58,7 @@ int main(int argc, char *argv[]) {
 
 
 	if (argc > 3) {
-                cache.reset(new node_persistent_cache(&options, 1, ram_cache));
+		cache.reset(new node_persistent_cache(&options, 1, true, ram_cache));
 		node_cnt = argc - 2;
 		for (i = 0; i < node_cnt; i++) {
 			osmids.push_back(strtoosmid(argv[2 + i], NULL, 10));
@@ -80,9 +74,9 @@ int main(int argc, char *argv[]) {
         setstate(state);
 
 	    printf("Testing mode\n");
-            cache.reset(new node_persistent_cache(&options, 1, ram_cache));
+	    cache.reset(new node_persistent_cache(&options, 1, true, ram_cache));
 	    test_get_node_list(cache, 10, 200, 0);
-            cache.reset();
+	    cache.reset();
 #ifdef HAVE_FORK
 	    printf("Testing using multiple processes\n");
 	    int noProcs = 4;
@@ -100,11 +94,11 @@ int main(int argc, char *argv[]) {
 	    gettimeofday(&start, NULL);
 	    initstate(start.tv_usec, state, 8);
 	    setstate(state);
-            cache.reset(new node_persistent_cache(&options, 1, ram_cache));
+	    cache.reset(new node_persistent_cache(&options, 1, true, ram_cache));
 	    test_get_node_list(cache, 10,200,p);
 
 	    if (pid == 0) {
-                cache.reset();
+	        cache.reset();
 	        fprintf(stderr,"Exiting process %i\n", p);
 	        exit(0);
 	    } else {
@@ -114,7 +108,7 @@ int main(int argc, char *argv[]) {
 	    fprintf(stderr, "\nAll child processes exited\n");
 #endif
 	} else {
-                cache.reset(new node_persistent_cache(&options, 1, ram_cache));
+		cache.reset(new node_persistent_cache(&options, 1, true, ram_cache));
 		if (strstr(argv[2],",") == NULL) {
 			cache->get(&node, strtoosmid(argv[2], NULL, 10));
 			printf("lat: %f / lon: %f\n", node.lat, node.lon);
@@ -139,8 +133,8 @@ int main(int argc, char *argv[]) {
 	}
 
 
-        cache.reset();
-        ram_cache.reset();
+    cache.reset();
+    ram_cache.reset();
 
     return 0;
 }
diff --git a/node-persistent-cache.cpp b/node-persistent-cache.cpp
index 17eca7d..61a4804 100644
--- a/node-persistent-cache.cpp
+++ b/node-persistent-cache.cpp
@@ -45,96 +45,35 @@
  #endif
 #endif
 
-void node_persistent_cache::writeout_dirty_nodes(osmid_t id)
+void node_persistent_cache::writeout_dirty_nodes()
 {
-    int i;
-
-    if (writeNodeBlock.dirty > 0)
-    {
-        if (lseek64(node_cache_fd,
-                (writeNodeBlock.block_offset << WRITE_NODE_BLOCK_SHIFT)
-                        * sizeof(struct ramNode)
-                    + sizeof(struct persistentCacheHeader), SEEK_SET) < 0) {
-            fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
-                    strerror(errno));
-            util::exit_nicely();
-
-        };
-        if (write(node_cache_fd, writeNodeBlock.nodes,
-                WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode))
-                < ssize_t(WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode)))
-        {
-            fprintf(stderr, "Failed to write out node cache: %s\n",
-                    strerror(errno));
-            util::exit_nicely();
-        }
-        cacheHeader.max_initialised_id = ((writeNodeBlock.block_offset + 1)
-                << WRITE_NODE_BLOCK_SHIFT) - 1;
-        writeNodeBlock.used = 0;
-        writeNodeBlock.dirty = 0;
-        if (lseek64(node_cache_fd, 0, SEEK_SET) < 0) {
-            fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
-                    strerror(errno));
-            util::exit_nicely();
-        };
-        if (write(node_cache_fd, &cacheHeader,
-                sizeof(struct persistentCacheHeader))
-                != sizeof(struct persistentCacheHeader))
-        {
-            fprintf(stderr, "Failed to update persistent cache header: %s\n",
-                    strerror(errno));
-            util::exit_nicely();
-        }
-        if (fsync(node_cache_fd) < 0) {
-            fprintf(stderr, "Info: Node cache could not be guaranteeded to be made durable. fsync failed: %s\n",
-                    strerror(errno));
-        };
-    }
-    if (id < 0)
+    for (int i = 0; i < READ_NODE_CACHE_SIZE; i++)
     {
-        for (i = 0; i < READ_NODE_CACHE_SIZE; i++)
+        if (readNodeBlockCache[i].dirty)
         {
-            if (readNodeBlockCache[i].dirty)
+            if (lseek64(node_cache_fd,
+                    (readNodeBlockCache[i].block_offset
+                            << READ_NODE_BLOCK_SHIFT)
+                            * sizeof(ramNode)
+                            + sizeof(persistentCacheHeader),
+                        SEEK_SET) < 0) {
+                fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
+                        strerror(errno));
+                util::exit_nicely();
+            };
+            if (write(node_cache_fd, readNodeBlockCache[i].nodes,
+                    READ_NODE_BLOCK_SIZE * sizeof(ramNode))
+                    < ssize_t(READ_NODE_BLOCK_SIZE * sizeof(ramNode)))
             {
-                if (lseek64(node_cache_fd,
-                        (readNodeBlockCache[i].block_offset
-                                << READ_NODE_BLOCK_SHIFT)
-                                * sizeof(struct ramNode)
-                                + sizeof(struct persistentCacheHeader),
-                            SEEK_SET) < 0) {
-                    fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
-                            strerror(errno));
-                    util::exit_nicely();
-                };
-                if (write(node_cache_fd, readNodeBlockCache[i].nodes,
-                        READ_NODE_BLOCK_SIZE * sizeof(struct ramNode))
-                        < ssize_t(READ_NODE_BLOCK_SIZE * sizeof(struct ramNode)))
-                {
-                    fprintf(stderr, "Failed to write out node cache: %s\n",
-                            strerror(errno));
-                    util::exit_nicely();
-                }
+                fprintf(stderr, "Failed to write out node cache: %s\n",
+                        strerror(errno));
+                util::exit_nicely();
             }
-            readNodeBlockCache[i].dirty = 0;
         }
+        readNodeBlockCache[i].dirty = 0;
     }
-
 }
 
-static void ramNodes_clear(struct ramNode * nodes, int size)
-{
-    int i;
-    for (i = 0; i < size; i++)
-    {
-#ifdef FIXED_POINT
-        nodes[i].lon = INT_MIN;
-        nodes[i].lat = INT_MIN;
-#else
-        nodes[i].lon = NAN;
-        nodes[i].lat = NAN;
-#endif
-    }
-}
 
 /**
  * Find the cache block with the lowest usage count for replacement
@@ -143,9 +82,8 @@ int node_persistent_cache::replace_block()
 {
     int min_used = INT_MAX;
     int block_id = -1;
-    int i;
 
-    for (i = 0; i < READ_NODE_CACHE_SIZE; i++)
+    for (int i = 0; i < READ_NODE_CACHE_SIZE; i++)
     {
         if (readNodeBlockCache[i].used < min_used)
         {
@@ -155,7 +93,7 @@ int node_persistent_cache::replace_block()
     }
     if (min_used > 0)
     {
-        for (i = 0; i < READ_NODE_CACHE_SIZE; i++)
+        for (int i = 0; i < READ_NODE_CACHE_SIZE; i++)
         {
             if (readNodeBlockCache[i].used > 1)
             {
@@ -200,33 +138,26 @@ void node_persistent_cache::add_to_cache_idx(cache_index_entry const &entry)
     readNodeBlockCacheIdx.insert(it, entry);
 }
 
+// A cache block with invalid nodes, just for writing out empty cache blocks
+static const ramNode nullNodes[READ_NODE_BLOCK_SIZE];
 /**
  * Initialise the persistent cache with NaN values to identify which IDs are valid or not
  */
 void node_persistent_cache::expand_cache(osmid_t block_offset)
 {
-    osmid_t i;
-    struct ramNode * dummyNodes = (struct ramNode *)malloc(
-            READ_NODE_BLOCK_SIZE * sizeof(struct ramNode));
-    if (!dummyNodes) {
-        fprintf(stderr, "Out of memory: Could not allocate node structure during cache expansion\n");
-        util::exit_nicely();
-    }
-    ramNodes_clear(dummyNodes, READ_NODE_BLOCK_SIZE);
     /* Need to expand the persistent node cache */
     if (lseek64(node_cache_fd,
-            cacheHeader.max_initialised_id * sizeof(struct ramNode)
-                + sizeof(struct persistentCacheHeader), SEEK_SET) < 0) {
+            cacheHeader.max_initialised_id * sizeof(ramNode)
+                + sizeof(persistentCacheHeader), SEEK_SET) < 0) {
         fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
                 strerror(errno));
         util::exit_nicely();
     };
-    for (i = cacheHeader.max_initialised_id >> READ_NODE_BLOCK_SHIFT;
+    for (osmid_t i = cacheHeader.max_initialised_id >> READ_NODE_BLOCK_SHIFT;
             i <= block_offset; i++)
     {
-        if (write(node_cache_fd, dummyNodes,
-                READ_NODE_BLOCK_SIZE * sizeof(struct ramNode))
-                < ssize_t(READ_NODE_BLOCK_SIZE * sizeof(struct ramNode)))
+        if (write(node_cache_fd, nullNodes, sizeof(nullNodes))
+                < ssize_t(sizeof(nullNodes)))
         {
             fprintf(stderr, "Failed to expand persistent node cache: %s\n",
                     strerror(errno));
@@ -247,7 +178,6 @@ void node_persistent_cache::expand_cache(osmid_t block_offset)
                 strerror(errno));
         util::exit_nicely();
     }
-    free(dummyNodes);
     fsync(node_cache_fd);
 }
 
@@ -257,19 +187,18 @@ void node_persistent_cache::nodes_prefetch_async(osmid_t id)
 #ifdef HAVE_POSIX_FADVISE
     osmid_t block_offset = id >> READ_NODE_BLOCK_SHIFT;
 
-    int block_id = find_block(block_offset);
-
-    if (block_id < 0)
-        {   /* The needed block isn't in cache already, so initiate loading */
-        writeout_dirty_nodes(id);
+    const int block_id = find_block(block_offset);
 
-        /* Make sure the node cache is correctly initialised for the block that will be read */
-        if (cacheHeader.max_initialised_id
-                < ((block_offset + 1) << READ_NODE_BLOCK_SHIFT))
-            expand_cache(block_offset);
+    if (block_id < 0) {
+        // The needed block isn't in cache already, so initiate loading
+        if (cacheHeader.max_initialised_id < id) {
+            fprintf(stderr, "Warning: reading node outside node cache. (%lu vs. %lu)\n",
+                    cacheHeader.max_initialised_id, id);
+            return;
+        }
 
-        if (posix_fadvise(node_cache_fd, (block_offset << READ_NODE_BLOCK_SHIFT) * sizeof(struct ramNode)
-                      + sizeof(struct persistentCacheHeader), READ_NODE_BLOCK_SIZE * sizeof(struct ramNode),
+        if (posix_fadvise(node_cache_fd, (block_offset << READ_NODE_BLOCK_SHIFT) * sizeof(ramNode)
+                      + sizeof(persistentCacheHeader), READ_NODE_BLOCK_SIZE * sizeof(ramNode),
                           POSIX_FADV_WILLNEED | POSIX_FADV_RANDOM) != 0) {
             fprintf(stderr, "Info: async prefetch of node cache failed. This might reduce performance\n");
         };
@@ -283,22 +212,21 @@ void node_persistent_cache::nodes_prefetch_async(osmid_t id)
  */
 int node_persistent_cache::load_block(osmid_t block_offset)
 {
-
-    int block_id = replace_block();
+    const int block_id = replace_block();
 
     if (readNodeBlockCache[block_id].dirty)
     {
         if (lseek64(node_cache_fd,
                 (readNodeBlockCache[block_id].block_offset
-                        << READ_NODE_BLOCK_SHIFT) * sizeof(struct ramNode)
+                        << READ_NODE_BLOCK_SHIFT) * sizeof(ramNode)
                     + sizeof(struct persistentCacheHeader), SEEK_SET) < 0) {
             fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
                     strerror(errno));
             util::exit_nicely();
         };
         if (write(node_cache_fd, readNodeBlockCache[block_id].nodes,
-                READ_NODE_BLOCK_SIZE * sizeof(struct ramNode))
-                < ssize_t(READ_NODE_BLOCK_SIZE * sizeof(struct ramNode)))
+                READ_NODE_BLOCK_SIZE * sizeof(ramNode))
+                < ssize_t(READ_NODE_BLOCK_SIZE * sizeof(ramNode)))
         {
             fprintf(stderr, "Failed to write out node cache: %s\n",
                     strerror(errno));
@@ -308,7 +236,7 @@ int node_persistent_cache::load_block(osmid_t block_offset)
     }
 
     remove_from_cache_idx(readNodeBlockCache[block_id].block_offset);
-    ramNodes_clear(readNodeBlockCache[block_id].nodes, READ_NODE_BLOCK_SIZE);
+    new(readNodeBlockCache[block_id].nodes) ramNode[READ_NODE_BLOCK_SIZE];
     readNodeBlockCache[block_id].block_offset = block_offset;
     readNodeBlockCache[block_id].used = READ_NODE_CACHE_SIZE;
 
@@ -321,22 +249,21 @@ int node_persistent_cache::load_block(osmid_t block_offset)
 
     /* Read the block into cache */
     if (lseek64(node_cache_fd,
-            (block_offset << READ_NODE_BLOCK_SHIFT) * sizeof(struct ramNode)
+            (block_offset << READ_NODE_BLOCK_SHIFT) * sizeof(ramNode)
                 + sizeof(struct persistentCacheHeader), SEEK_SET) < 0) {
         fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
                 strerror(errno));
         util::exit_nicely();
     };
     if (read(node_cache_fd, readNodeBlockCache[block_id].nodes,
-            READ_NODE_BLOCK_SIZE * sizeof(struct ramNode))
-            != READ_NODE_BLOCK_SIZE * sizeof(struct ramNode))
+            READ_NODE_BLOCK_SIZE * sizeof(ramNode))
+            != READ_NODE_BLOCK_SIZE * sizeof(ramNode))
     {
         fprintf(stderr, "Failed to read from node cache: %s\n",
                 strerror(errno));
         exit(1);
     }
-    add_to_cache_idx(cache_index_entry(readNodeBlockCache[block_id].block_offset,
-                                       block_id));
+    add_to_cache_idx(cache_index_entry(block_offset, block_id));
 
     return block_id;
 }
@@ -344,8 +271,8 @@ int node_persistent_cache::load_block(osmid_t block_offset)
 void node_persistent_cache::nodes_set_create_writeout_block()
 {
     if (write(node_cache_fd, writeNodeBlock.nodes,
-              WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode))
-        < ssize_t(WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode)))
+              WRITE_NODE_BLOCK_SIZE * sizeof(ramNode))
+        < ssize_t(WRITE_NODE_BLOCK_SIZE * sizeof(ramNode)))
     {
         fprintf(stderr, "Failed to write out node cache: %s\n",
                 strerror(errno));
@@ -355,31 +282,31 @@ void node_persistent_cache::nodes_set_create_writeout_block()
     /* writing out large files can cause trouble on some operating systems.
      * For one, if to much dirty data is in RAM, the whole OS can stall until
      * enough dirty data is written out which can take a while. It can also interfere
-     * with outher disk caching operations and might push things out to swap. By forcing the OS to
+     * with other disk caching operations and might push things out to swap. By forcing the OS to
      * immediately write out the data and blocking after a while, we ensure that no more
      * than a couple of 10s of MB are dirty in RAM at a time.
      * Secondly, the nodes are stored in an additional ram cache during import. Keeping the
      * node cache file in buffer cache therefore duplicates the data wasting 16GB of ram.
      * Therefore tell the OS not to cache the node-persistent-cache during initial import.
      * */
-    if (sync_file_range(node_cache_fd, writeNodeBlock.block_offset*WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode) +
-                        sizeof(struct persistentCacheHeader), WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode),
+    if (sync_file_range(node_cache_fd, writeNodeBlock.block_offset*WRITE_NODE_BLOCK_SIZE * sizeof(ramNode) +
+                        sizeof(persistentCacheHeader), WRITE_NODE_BLOCK_SIZE * sizeof(ramNode),
                         SYNC_FILE_RANGE_WRITE) < 0) {
         fprintf(stderr, "Info: Sync_file_range writeout has an issue. This shouldn't be anything to worry about.: %s\n",
                 strerror(errno));
     };
 
     if (writeNodeBlock.block_offset > 16) {
-        if(sync_file_range(node_cache_fd, (writeNodeBlock.block_offset - 16)*WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode) +
-                           sizeof(struct persistentCacheHeader), WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode),
+        if(sync_file_range(node_cache_fd, (writeNodeBlock.block_offset - 16)*WRITE_NODE_BLOCK_SIZE * sizeof(ramNode) +
+                           sizeof(persistentCacheHeader), WRITE_NODE_BLOCK_SIZE * sizeof(ramNode),
                             SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER) < 0) {
             fprintf(stderr, "Info: Sync_file_range block has an issue. This shouldn't be anything to worry about.: %s\n",
                 strerror(errno));
 
         }
 #ifdef HAVE_POSIX_FADVISE
-        if (posix_fadvise(node_cache_fd, (writeNodeBlock.block_offset - 16)*WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode) +
-                          sizeof(struct persistentCacheHeader), WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode), POSIX_FADV_DONTNEED) !=0 ) {
+        if (posix_fadvise(node_cache_fd, (writeNodeBlock.block_offset - 16)*WRITE_NODE_BLOCK_SIZE * sizeof(ramNode) +
+                          sizeof(persistentCacheHeader), WRITE_NODE_BLOCK_SIZE * sizeof(ramNode), POSIX_FADV_DONTNEED) !=0 ) {
             fprintf(stderr, "Info: Posix_fadvise failed. This shouldn't be anything to worry about.: %s\n",
                 strerror(errno));
         };
@@ -390,18 +317,16 @@ void node_persistent_cache::nodes_set_create_writeout_block()
 
 int node_persistent_cache::set_create(osmid_t id, double lat, double lon)
 {
-    osmid_t block_offset = id >> WRITE_NODE_BLOCK_SHIFT;
-    int i;
+    assert(!append_mode);
+    assert(!read_mode);
 
-    if (cache_already_written)
-        return 0;
+    osmid_t block_offset = id >> WRITE_NODE_BLOCK_SHIFT;
 
     if (writeNodeBlock.block_offset != block_offset)
     {
         if (writeNodeBlock.dirty)
         {
             nodes_set_create_writeout_block();
-            writeNodeBlock.used = 0;
             writeNodeBlock.dirty = 0;
             /* After writing out the node block, the file pointer is at the next block level */
             writeNodeBlock.block_offset++;
@@ -416,25 +341,18 @@ int node_persistent_cache::set_create(osmid_t id, double lat, double lon)
             util::exit_nicely();
         }
 
+        new(writeNodeBlock.nodes) ramNode[WRITE_NODE_BLOCK_SIZE];
+
         /* We need to fill the intermediate node cache with node nodes to identify which nodes are valid */
-        for (i = writeNodeBlock.block_offset; i < block_offset; i++)
+        while (writeNodeBlock.block_offset < block_offset)
         {
-            ramNodes_clear(writeNodeBlock.nodes, WRITE_NODE_BLOCK_SIZE);
             nodes_set_create_writeout_block();
+            writeNodeBlock.block_offset++;
         }
 
-        ramNodes_clear(writeNodeBlock.nodes, WRITE_NODE_BLOCK_SIZE);
-        writeNodeBlock.used = 0;
-        writeNodeBlock.block_offset = block_offset;
     }
-#ifdef FIXED_POINT
-    writeNodeBlock.nodes[id & WRITE_NODE_BLOCK_MASK].lat = util::double_to_fix(lat, scale_);
-    writeNodeBlock.nodes[id & WRITE_NODE_BLOCK_MASK].lon = util::double_to_fix(lon, scale_);
-#else
-    writeNodeBlock.nodes[id & WRITE_NODE_BLOCK_MASK].lat = lat;
-    writeNodeBlock.nodes[id & WRITE_NODE_BLOCK_MASK].lon = lon;
-#endif
-    writeNodeBlock.used++;
+
+    writeNodeBlock.nodes[id & WRITE_NODE_BLOCK_MASK] = ramNode(lon, lat);
     writeNodeBlock.dirty = 1;
 
     return 0;
@@ -442,6 +360,8 @@ int node_persistent_cache::set_create(osmid_t id, double lat, double lon)
 
 int node_persistent_cache::set_append(osmid_t id, double lat, double lon)
 {
+    assert(!read_mode);
+
     osmid_t block_offset = id >> READ_NODE_BLOCK_SHIFT;
 
     int block_id = find_block(block_offset);
@@ -449,25 +369,10 @@ int node_persistent_cache::set_append(osmid_t id, double lat, double lon)
     if (block_id < 0)
         block_id = load_block(block_offset);
 
-#ifdef FIXED_POINT
     if (isnan(lat) && isnan(lon))
-    {
-        readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lat =
-                INT_MIN;
-        readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lon =
-                INT_MIN;
-    }
+        readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK] = ramNode();
     else
-    {
-        readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lat =
-                util::double_to_fix(lat, scale_);
-        readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lon =
-                util::double_to_fix(lon, scale_);
-    }
-#else
-    readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lat = lat;
-    readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lon = lon;
-#endif
+        readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK] = ramNode(lon, lat);
     readNodeBlockCache[block_id].used++;
     readNodeBlockCache[block_id].dirty = 1;
 
@@ -481,61 +386,40 @@ int node_persistent_cache::set(osmid_t id, double lat, double lon)
         set_create(id, lat, lon);
 }
 
-int node_persistent_cache::get(struct osmNode *out, osmid_t id)
+int node_persistent_cache::get(osmNode *out, osmid_t id)
 {
+    set_read_mode();
+
     osmid_t block_offset = id >> READ_NODE_BLOCK_SHIFT;
 
     int block_id = find_block(block_offset);
 
     if (block_id < 0)
     {
-        writeout_dirty_nodes(id);
         block_id = load_block(block_offset);
     }
 
     readNodeBlockCache[block_id].used++;
 
-#ifdef FIXED_POINT
-    if ((readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lat
-            == INT_MIN)
-            && (readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lon
-                    == INT_MIN))
-    {
+    if (!readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].is_valid())
         return 1;
-    }
-    else
-    {
-        out->lat =
-                util::fix_to_double(readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lat, scale_);
-        out->lon =
-                util::fix_to_double(readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lon, scale_);
-        return 0;
-    }
-#else
-    if ((isnan(readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lat)) &&
-            (isnan(readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lon)))
-    {
-        return 1;
-    }
-    else
-    {
-        out->lat = readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lat;
-        out->lon = readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lon;
-        return 0;
-    }
-#endif
+
+    out->lat = readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lat();
+    out->lon = readNodeBlockCache[block_id].nodes[id & READ_NODE_BLOCK_MASK].lon();
 
     return 0;
 }
 
 int node_persistent_cache::get_list(nodelist_t &out, const idlist_t nds)
 {
+    set_read_mode();
+
     out.assign(nds.size(), osmNode());
 
-    bool need_fetch = false;;
+    bool need_fetch = false;
     for (size_t i = 0; i < nds.size(); ++i) {
         /* Check cache first */
-        if (ram_cache && (ram_cache->get(&out[i], nds[i]) != 0)) {
+        if (ram_cache->get(&out[i], nds[i]) != 0) {
             /* In order to have a higher OS level I/O queue depth
                issue posix_fadvise(WILLNEED) requests for all I/O */
             nodes_prefetch_async(nds[i]);
@@ -562,14 +446,45 @@ int node_persistent_cache::get_list(nodelist_t &out, const idlist_t nds)
     return wrtidx;
 }
 
+void node_persistent_cache::set_read_mode()
+{
+    if (read_mode)
+        return;
+
+    if (writeNodeBlock.dirty > 0) {
+        assert(!append_mode);
+        fprintf(stderr, "Switching to read mode\n");
+        nodes_set_create_writeout_block();
+        writeNodeBlock.dirty = 0;
+        writeNodeBlock.block_offset++;
+        cacheHeader.max_initialised_id = (writeNodeBlock.block_offset
+                << WRITE_NODE_BLOCK_SHIFT) - 1;
+
+        /* write out the header */
+        if (lseek64(node_cache_fd, 0, SEEK_SET) < 0) {
+            fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
+                    strerror(errno));
+            util::exit_nicely();
+        };
+        if (write(node_cache_fd, &cacheHeader, sizeof(persistentCacheHeader))
+                != sizeof(persistentCacheHeader)) {
+            fprintf(stderr, "Failed to update persistent cache header: %s\n",
+                    strerror(errno));
+            util::exit_nicely();
+        }
+    }
+
+    read_mode = true;
+
+    fprintf(stderr, "Switching to read mode done\n");
+}
+
 node_persistent_cache::node_persistent_cache(const options_t *options, int append,
-                                             boost::shared_ptr<node_ram_cache> ptr)
+                                             bool ro, boost::shared_ptr<node_ram_cache> ptr)
     : node_cache_fd(0), node_cache_fname(NULL), append_mode(0), cacheHeader(),
-      writeNodeBlock(), readNodeBlockCache(NULL),
-      scale_(0), cache_already_written(0), ram_cache(ptr)
+      writeNodeBlock(), readNodeBlockCache(NULL), read_mode(ro), ram_cache(ptr)
 {
     int i, err;
-    scale_ = options->scale;
     append_mode = append;
     if (options->flat_node_file) {
         node_cache_fname = options->flat_node_file->c_str();
@@ -595,7 +510,7 @@ node_persistent_cache::node_persistent_cache(const options_t *options, int appen
     }
     else
     {
-        if (cache_already_written)
+        if (read_mode)
         {
             node_cache_fd = open(node_cache_fname, O_RDWR, S_IRUSR | S_IWUSR);
         }
@@ -616,12 +531,17 @@ node_persistent_cache::node_persistent_cache(const options_t *options, int appen
                     strerror(errno));
             util::exit_nicely();
         };
-        if (cache_already_written == 0)
+
+        writeNodeBlock.block_offset = 0;
+        writeNodeBlock.dirty = 0;
+        writeNodeBlock.nodes = 0;
+
+        if (!read_mode)
         {
 
             #ifdef HAVE_POSIX_FALLOCATE
             if ((err = posix_fallocate(node_cache_fd, 0,
-                    sizeof(struct ramNode) * MAXIMUM_INITIAL_ID)) != 0)
+                    sizeof(ramNode) * MAXIMUM_INITIAL_ID)) != 0)
             {
                 if (err == ENOSPC) {
                     fprintf(stderr, "Failed to allocate space for node cache file: No space on disk\n");
@@ -636,16 +556,11 @@ node_persistent_cache::node_persistent_cache(const options_t *options, int appen
             }
             fprintf(stderr, "Allocated space for persistent node cache file\n");
             #endif
-            writeNodeBlock.nodes = (struct ramNode *)malloc(
-                    WRITE_NODE_BLOCK_SIZE * sizeof(struct ramNode));
+            writeNodeBlock.nodes = new ramNode[WRITE_NODE_BLOCK_SIZE];
             if (!writeNodeBlock.nodes) {
                 fprintf(stderr, "Out of memory: Failed to allocate node writeout buffer\n");
                 util::exit_nicely();
             }
-            ramNodes_clear(writeNodeBlock.nodes, WRITE_NODE_BLOCK_SIZE);
-            writeNodeBlock.block_offset = 0;
-            writeNodeBlock.used = 0;
-            writeNodeBlock.dirty = 0;
             cacheHeader.format_version = PERSISTENT_CACHE_FORMAT_VERSION;
             cacheHeader.id_size = sizeof(osmid_t);
             cacheHeader.max_initialised_id = 0;
@@ -691,16 +606,14 @@ node_persistent_cache::node_persistent_cache(const options_t *options, int appen
 
     fprintf(stderr,"Maximum node in persistent node cache: %" PRIdOSMID "\n", cacheHeader.max_initialised_id);
 
-    readNodeBlockCache = (struct ramNodeBlock *)malloc(
-            READ_NODE_CACHE_SIZE * sizeof(struct ramNodeBlock));
+    readNodeBlockCache = new ramNodeBlock [READ_NODE_CACHE_SIZE];
     if (!readNodeBlockCache) {
         fprintf(stderr, "Out of memory: Failed to allocate node read cache\n");
         util::exit_nicely();
     }
     for (i = 0; i < READ_NODE_CACHE_SIZE; i++)
     {
-        readNodeBlockCache[i].nodes = (struct ramNode *)malloc(
-                READ_NODE_BLOCK_SIZE * sizeof(struct ramNode));
+        readNodeBlockCache[i].nodes = new ramNode[READ_NODE_BLOCK_SIZE];
         if (!readNodeBlockCache[i].nodes) {
             fprintf(stderr, "Out of memory: Failed to allocate node read cache\n");
             util::exit_nicely();
@@ -713,8 +626,13 @@ node_persistent_cache::node_persistent_cache(const options_t *options, int appen
 
 node_persistent_cache::~node_persistent_cache()
 {
-    int i;
-    writeout_dirty_nodes(-1);
+    if (writeNodeBlock.dirty > 0)
+        nodes_set_create_writeout_block();
+
+    writeout_dirty_nodes();
+
+    if (writeNodeBlock.nodes)
+        delete[] writeNodeBlock.nodes;
 
     if (lseek64(node_cache_fd, 0, SEEK_SET) < 0) {
         fprintf(stderr, "Failed to seek to correct position in node cache: %s\n",
@@ -738,10 +656,11 @@ node_persistent_cache::~node_persistent_cache()
                 strerror(errno));
     }
 
-    for (i = 0; i < READ_NODE_CACHE_SIZE; i++)
-    {
-        free(readNodeBlockCache[i].nodes);
+    if (readNodeBlockCache) {
+        for (int i = 0; i < READ_NODE_CACHE_SIZE; i++)
+        {
+            delete[] readNodeBlockCache[i].nodes;
+        }
+        delete[] readNodeBlockCache;
     }
-    free(readNodeBlockCache);
-    readNodeBlockCache = NULL;
 }
diff --git a/node-persistent-cache.hpp b/node-persistent-cache.hpp
index a0c2a48..2363d11 100644
--- a/node-persistent-cache.hpp
+++ b/node-persistent-cache.hpp
@@ -51,12 +51,12 @@ inline bool operator<(osmid_t a, cache_index_entry const &b)
 
 struct node_persistent_cache : public boost::noncopyable
 {
-    node_persistent_cache(const struct options_t *options, const int append,
-                          boost::shared_ptr<node_ram_cache> ptr);
+    node_persistent_cache(const struct options_t *options, int append,
+                          bool ro, boost::shared_ptr<node_ram_cache> ptr);
     ~node_persistent_cache();
 
     int set(osmid_t id, double lat, double lon);
-    int get(struct osmNode *out, osmid_t id);
+    int get(osmNode *out, osmid_t id);
     int get_list(nodelist_t &out, const idlist_t nds);
 
 private:
@@ -64,7 +64,7 @@ private:
     int set_append(osmid_t id, double lat, double lon);
     int set_create(osmid_t id, double lat, double lon);
 
-    void writeout_dirty_nodes(osmid_t id);
+    void writeout_dirty_nodes();
     int replace_block();
     int find_block(osmid_t block_offset);
     void expand_cache(osmid_t block_offset);
@@ -74,20 +74,20 @@ private:
 
     void remove_from_cache_idx(osmid_t block_offset);
     void add_to_cache_idx(cache_index_entry const &entry);
+    void set_read_mode();
 
     int node_cache_fd;
     const char * node_cache_fname;
     int append_mode;
 
-    struct persistentCacheHeader cacheHeader;
-    struct ramNodeBlock writeNodeBlock; /* larger node block for more efficient initial sequential writing of node cache */
-    struct ramNodeBlock * readNodeBlockCache;
+    persistentCacheHeader cacheHeader;
+    ramNodeBlock writeNodeBlock; /* larger node block for more efficient initial sequential writing of node cache */
+    ramNodeBlock * readNodeBlockCache;
 
     typedef std::vector<cache_index_entry> cache_index;
     cache_index readNodeBlockCacheIdx;
 
-    int scale_;
-    int cache_already_written;
+    bool read_mode;
 
     boost::shared_ptr<node_ram_cache> ram_cache;
 };
diff --git a/node-ram-cache.cpp b/node-ram-cache.cpp
index 7a467ba..167f6b7 100644
--- a/node-ram-cache.cpp
+++ b/node-ram-cache.cpp
@@ -5,21 +5,14 @@
 
 #include "config.h"
 
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
 
 #include "osmtypes.hpp"
-#include "middle.hpp"
 #include "node-ram-cache.hpp"
 #include "util.hpp"
 
-
-
-
-
 /* Here we use a similar storage structure as middle-ram, except we allow
  * the array to be lossy so we can cap the total memory usage. Hence it is a
  * combination of a sparse array with a priority queue
@@ -65,6 +58,8 @@
 
 #define SAFETY_MARGIN 1024*PER_BLOCK*sizeof(ramNode)
 
+int ramNode::scale;
+
 static int id2block(osmid_t id)
 {
     /* + NUM_BLOCKS/2 allows for negative IDs */
@@ -99,21 +94,20 @@ void node_ram_cache::percolate_up( int pos )
     }
 }
 
-ramNode *node_ram_cache::next_chunk(size_t count, size_t size) {
+ramNode *node_ram_cache::next_chunk() {
     if ( (allocStrategy & ALLOC_DENSE_CHUNK) == 0 ) {
-        static size_t pos = 0;
-        char *result;
-        pos += count * size;
-        result = blockCache + cacheSize - pos + SAFETY_MARGIN;
+        // allocate starting from the upper end of the block cache
+        blockCachePos += PER_BLOCK * sizeof(ramNode);
+        char *result = blockCache + cacheSize - blockCachePos + SAFETY_MARGIN;
 
-        return (ramNode *)result;
+        return new(result) ramNode[PER_BLOCK];
     } else {
-        return (ramNode *)calloc(PER_BLOCK, sizeof(ramNode));
+        return new ramNode[PER_BLOCK];
     }
 }
 
 
-int node_ram_cache::set_sparse(osmid_t id, double lat, double lon) {
+int node_ram_cache::set_sparse(osmid_t id, const ramNode &coord) {
     if ((sizeSparseTuples > maxSparseTuples) || ( cacheUsed > cacheSize)) {
         if ((allocStrategy & ALLOC_LOSSY) > 0)
             return 1;
@@ -123,20 +117,15 @@ int node_ram_cache::set_sparse(osmid_t id, double lat, double lon) {
         }
     }
     sparseBlock[sizeSparseTuples].id = id;
-#ifdef FIXED_POINT
-    sparseBlock[sizeSparseTuples].coord.lat = util::double_to_fix(lat, scale_);
-    sparseBlock[sizeSparseTuples].coord.lon = util::double_to_fix(lon, scale_);
-#else
-    sparseBlock[sizeSparseTuples].coord.lat = lat;
-    sparseBlock[sizeSparseTuples].coord.lon = lon;
-#endif
+    sparseBlock[sizeSparseTuples].coord = coord;
+
     sizeSparseTuples++;
     cacheUsed += sizeof(ramNodeID);
     storedNodes++;
     return 0;
 }
 
-int node_ram_cache::set_dense(osmid_t id, double lat, double lon) {
+int node_ram_cache::set_dense(osmid_t id, const ramNode &coord) {
     int block  = id2block(id);
     int offset = id2offset(id);
     int i = 0;
@@ -160,32 +149,25 @@ int node_ram_cache::set_dense(osmid_t id, double lat, double lon) {
                     /* We've just finished with the previous block, so we need to percolate it up the queue to its correct position */
                     /* Upto log(usedBlocks) iterations */
                     percolate_up( usedBlocks-1 );
-                    blocks[block].nodes = next_chunk(PER_BLOCK, sizeof(ramNode));
+                    blocks[block].nodes = next_chunk();
                 } else {
                     /* previous block was not dense enough, so push it into the sparse node cache instead */
                     for (i = 0; i < (1 << BLOCK_SHIFT); i++) {
-                        if (queue[usedBlocks -1]->nodes[i].lat || queue[usedBlocks -1]->nodes[i].lon) {
-                            set_sparse(block2id(queue[usedBlocks - 1]->block_offset,i),
-#ifdef FIXED_POINT
-                                                       util::fix_to_double(queue[usedBlocks -1]->nodes[i].lat, scale_),
-                                                       util::fix_to_double(queue[usedBlocks -1]->nodes[i].lon, scale_)
-#else
-                                                       queue[usedBlocks -1]->nodes[i].lat,
-                                                       queue[usedBlocks -1]->nodes[i].lon
-#endif
-                                                       );
+                        if (queue[usedBlocks -1]->nodes[i].is_valid()) {
+                            set_sparse(block2id(queue[usedBlocks - 1]->block_offset, i),
+                                       queue[usedBlocks -1]->nodes[i]);
+                            queue[usedBlocks -1]->nodes[i] = ramNode(); // invalidate
                         }
                     }
-                    /* reuse previous block, as it's content is now in the dense representation */
+                    /* reuse previous block, as its content is now in the sparse representation */
                     storedNodes -= queue[usedBlocks - 1]->used;
                     blocks[block].nodes = queue[usedBlocks - 1]->nodes;
                     blocks[queue[usedBlocks - 1]->block_offset].nodes = NULL;
-                    memset( blocks[block].nodes, 0, PER_BLOCK * sizeof(ramNode) );
                     usedBlocks--;
                     cacheUsed -= PER_BLOCK * sizeof(ramNode);
                 }
             } else {
-                blocks[block].nodes = next_chunk(PER_BLOCK, sizeof(ramNode));
+                blocks[block].nodes = next_chunk();
             }
 
             blocks[block].used = 0;
@@ -232,7 +214,7 @@ int node_ram_cache::set_dense(osmid_t id, double lat, double lon) {
             /* Now the head of the queue is the smallest, so it becomes our replacement candidate */
             blocks[block].nodes = queue[0]->nodes;
             blocks[block].used = 0;
-            memset( blocks[block].nodes, 0, PER_BLOCK * sizeof(ramNode) );
+            new(blocks[block].nodes) ramNode[PER_BLOCK];
 
             /* Clear old head block and point to new block */
             storedNodes -= queue[0]->used;
@@ -260,13 +242,7 @@ int node_ram_cache::set_dense(osmid_t id, double lat, double lon) {
         }
     }
 
-#ifdef FIXED_POINT
-    blocks[block].nodes[offset].lat = util::double_to_fix(lat, scale_);
-    blocks[block].nodes[offset].lon = util::double_to_fix(lon, scale_);
-#else
-    blocks[block].nodes[offset].lat = lat;
-    blocks[block].nodes[offset].lon = lon;
-#endif
+    blocks[block].nodes[offset] = coord;
     blocks[block].used++;
     storedNodes++;
     return 0;
@@ -280,13 +256,8 @@ int node_ram_cache::get_sparse(osmNode *out, osmid_t id) {
 
     while (minPos <= maxPos) {
         if ( sparseBlock[pivotPos].id == id ) {
-#ifdef FIXED_POINT
-            out->lat = util::fix_to_double(sparseBlock[pivotPos].coord.lat, scale_);
-            out->lon = util::fix_to_double(sparseBlock[pivotPos].coord.lon, scale_);
-#else
-            out->lat = sparseBlock[pivotPos].coord.lat;
-            out->lon = sparseBlock[pivotPos].coord.lon;
-#endif
+            out->lat = sparseBlock[pivotPos].coord.lat();
+            out->lon = sparseBlock[pivotPos].coord.lon();
             return 0;
         }
         if ( (pivotPos == minPos) || (pivotPos == maxPos)) return 1;
@@ -310,16 +281,11 @@ int node_ram_cache::get_dense(osmNode *out, osmid_t id) {
     if (!blocks[block].nodes)
         return 1;
 
-    if (!blocks[block].nodes[offset].lat && !blocks[block].nodes[offset].lon)
+    if (!blocks[block].nodes[offset].is_valid())
         return 1;
 
-#ifdef FIXED_POINT
-    out->lat = util::fix_to_double(blocks[block].nodes[offset].lat, scale_);
-    out->lon = util::fix_to_double(blocks[block].nodes[offset].lon, scale_);
-#else
-    out->lat = blocks[block].nodes[offset].lat;
-    out->lon = blocks[block].nodes[offset].lon;
-#endif
+    out->lat = blocks[block].nodes[offset].lat();
+    out->lon = blocks[block].nodes[offset].lon();
 
     return 0;
 }
@@ -327,12 +293,14 @@ int node_ram_cache::get_dense(osmNode *out, osmid_t id) {
 
 node_ram_cache::node_ram_cache( int strategy, int cacheSizeMB, int fixpointscale )
     : allocStrategy(ALLOC_DENSE), blocks(NULL), usedBlocks(0),
-      maxBlocks(0), blockCache(NULL), queue(NULL), scale_(fixpointscale), sparseBlock(NULL),
+      maxBlocks(0), blockCache(NULL), queue(NULL), sparseBlock(NULL),
       maxSparseTuples(0), sizeSparseTuples(0), cacheUsed(0),
       cacheSize(0), storedNodes(0), totalNodes(0), nodesCacheHits(0),
       nodesCacheLookups(0), warn_node_order(0) {
 
+    ramNode::scale = fixpointscale;
     blockCache = 0;
+    blockCachePos = 0;
     cacheUsed = 0;
     cacheSize = (int64_t)cacheSizeMB*(1024*1024);
     /* How much we can fit, and make sure it's odd */
@@ -361,7 +329,7 @@ node_ram_cache::node_ram_cache( int strategy, int cacheSizeMB, int fixpointscale
             }
         } else {
             fprintf(stderr, "Allocating dense node cache in one big chunk\n");
-            blockCache = (char *)calloc(maxBlocks + 1024,PER_BLOCK * sizeof(ramNode));
+            blockCache = (char *)malloc((maxBlocks + 1024) * PER_BLOCK * sizeof(ramNode));
             if (!queue || !blockCache) {
                 fprintf(stderr, "Out of memory for dense node cache, reduce --cache size\n");
                 util::exit_nicely();
@@ -379,7 +347,7 @@ node_ram_cache::node_ram_cache( int strategy, int cacheSizeMB, int fixpointscale
     if ((allocStrategy & ALLOC_SPARSE) > 0 ) {
         fprintf(stderr, "Allocating memory for sparse node cache\n");
         if (!blockCache) {
-            sparseBlock = (ramNodeID *)calloc(maxSparseTuples,sizeof(ramNodeID));
+            sparseBlock = (ramNodeID *)malloc(maxSparseTuples * sizeof(ramNodeID));
         } else {
             fprintf(stderr, "Sharing dense sparse\n");
             sparseBlock = (ramNodeID *)blockCache;
@@ -398,7 +366,6 @@ node_ram_cache::node_ram_cache( int strategy, int cacheSizeMB, int fixpointscale
 }
 
 node_ram_cache::~node_ram_cache() {
-  int i;
   fprintf( stderr, "node cache: stored: %" PRIdOSMID "(%.2f%%), storage efficiency: %.2f%% (dense blocks: %i, sparse nodes: %li), hit rate: %.2f%%\n",
            storedNodes, 100.0f*storedNodes/totalNodes, 100.0f*storedNodes*sizeof(ramNode)/cacheUsed,
            usedBlocks, sizeSparseTuples,
@@ -406,8 +373,8 @@ node_ram_cache::~node_ram_cache() {
 
   if ( (allocStrategy & ALLOC_DENSE) > 0 ) {
       if ( (allocStrategy & ALLOC_DENSE_CHUNK) > 0 ) {
-          for( i=0; i<usedBlocks; i++ ) {
-              free(queue[i]->nodes);
+          for(int i = 0; i < usedBlocks; ++i) {
+              delete[] queue[i]->nodes;
               queue[i]->nodes = NULL;
           }
       } else {
@@ -429,10 +396,10 @@ int node_ram_cache::set(osmid_t id, double lat, double lon, const taglist_t &) {
      * get pushed to the sparse cache if a block is sparse and ALLOC_SPARSE is set
      */
     if ( (allocStrategy & ALLOC_DENSE) > 0 ) {
-        return set_dense(id, lat, lon);
+        return set_dense(id, ramNode(lon, lat));
     }
     if ( (allocStrategy & ALLOC_SPARSE) > 0 )
-        return set_sparse(id, lat, lon);
+        return set_sparse(id, ramNode(lon, lat));
     return 1;
 }
 
@@ -440,13 +407,13 @@ int node_ram_cache::get(osmNode *out, osmid_t id) {
     nodesCacheLookups++;
 
     if ((allocStrategy & ALLOC_DENSE) > 0) {
-        if (get_dense(out,id) == 0) {
+        if (get_dense(out, id) == 0) {
             nodesCacheHits++;
             return 0;
         }
     }
     if ((allocStrategy & ALLOC_SPARSE) > 0) {
-        if (get_sparse(out,id) == 0) {
+        if (get_sparse(out, id) == 0) {
             nodesCacheHits++;
             return 0;
         }
diff --git a/node-ram-cache.hpp b/node-ram-cache.hpp
index 8c64eb3..0404904 100644
--- a/node-ram-cache.hpp
+++ b/node-ram-cache.hpp
@@ -8,8 +8,12 @@
 #ifndef NODE_RAM_CACHE_H
 #define NODE_RAM_CACHE_H
 
+#include "config.h"
 #include "osmtypes.hpp"
 
+#include <cstddef>
+#include <climits>
+#include <stdint.h>
 #include <boost/noncopyable.hpp>
 
 #define ALLOC_SPARSE 1
@@ -17,26 +21,70 @@
 #define ALLOC_DENSE_CHUNK 4
 #define ALLOC_LOSSY 8
 
-/* Store +-20,000km Mercator co-ordinates as fixed point 32bit number with maximum precision */
-#define FIXED_POINT
-
-struct ramNode {
+/**
+ * A set of coordinates, for caching in RAM or on disk.
+ *
+ * If FIXED_POINT is enabled, it uses internally a more efficient
+ * representation as integer.
+ */ 
+class ramNode {
+public:
 #ifdef FIXED_POINT
-    int lon;
-    int lat;
+    static int scale;
+
+    /// Default constructor creates an invalid node
+    ramNode() : _lon(INT_MIN), _lat(INT_MIN) {}
+    /**
+     * Standard constructor takes geographic coordinates and saves them
+     * in the internal node representation.
+     */
+    ramNode(double lon, double lat) : _lon(dbl2fix(lon)), _lat(dbl2fix(lat)) {}
+    /**
+     * Internal constructor which takes already encoded nodes.
+     *
+     * Used by middle-pgsql which stores encoded nodes in the DB.
+     */
+    ramNode(int lon, int lat) : _lon(lon), _lat(lat) {}
+
+    /// Return true if the node currently stores valid coordinates.
+    bool is_valid() const { return _lon != INT_MIN; }
+    /// Return longitude (converting from internal representation)
+    double lon() const { return fix2dbl(_lon); }
+    /// Return latitude (converting from internal representation)
+    double lat() const { return fix2dbl(_lat); }
+    /// Return internal representation of longitude (for external storage).
+    int int_lon() const { return _lon; }
+    /// Return internal representation of latitude (for external storage).
+    int int_lat() const { return _lat; }
+
+private:
+    int _lon;
+    int _lat;
+
+    int dbl2fix(const double x) const { return x * scale + 0.4; }
+    double fix2dbl(const int x) const { return (double)x / scale; }
 #else
-    double lon;
-    double lat;
+public:
+    ramNode() : _lat(NAN), _lon(NAN) {}
+    ramNode(double _lon, double _lat) : _lon(lon), _lat(lat) {}
+
+    bool is_valid() const ( return !isnan(_lon); }
+    double lon() const { return _lon; }
+    double lat() const { return _lat; }
+private:
+    double _lon;
+    double _lat;
+
 #endif
 };
 
 struct ramNodeID {
     osmid_t id;
-    struct ramNode coord;
+    ramNode coord;
 };
 
 struct ramNodeBlock {
-    struct ramNode    *nodes;
+    ramNode *nodes;
     osmid_t block_offset;
     int used;
     int dirty;
@@ -52,25 +100,24 @@ struct node_ram_cache : public boost::noncopyable
 
 private:
     void percolate_up( int pos );
-    struct ramNode *next_chunk(size_t count, size_t size);
-    int set_sparse(osmid_t id, double lat, double lon);
-    int set_dense(osmid_t id, double lat, double lon);
+    ramNode *next_chunk();
+    int set_sparse(osmid_t id, const ramNode &coord);
+    int set_dense(osmid_t id, const ramNode& coord);
     int get_sparse(osmNode *out, osmid_t id);
     int get_dense(osmNode *out, osmid_t id);
 
     int allocStrategy;
 
-    struct ramNodeBlock *blocks;
+    ramNodeBlock *blocks;
     int usedBlocks;
     /* Note: maxBlocks *must* be odd, to make sure the priority queue has no nodes with only one child */
     int maxBlocks;
     char *blockCache;
+    size_t blockCachePos;
 
-    struct ramNodeBlock **queue;
-
-    int scale_;
+    ramNodeBlock **queue;
 
-    struct ramNodeID *sparseBlock;
+    ramNodeID *sparseBlock;
     int64_t maxSparseTuples;
     int64_t sizeSparseTuples;
 
diff --git a/options.cpp b/options.cpp
index eea61bc..19462b4 100644
--- a/options.cpp
+++ b/options.cpp
@@ -29,7 +29,6 @@ namespace
         {"prefix",   1, 0, 'p'},
         {"proj",     1, 0, 'E'},
         {"merc",     0, 0, 'm'},
-        {"oldmerc",  0, 0, 'M'},
         {"utf8-sanitize", 0, 0, 'u'},
         {"cache",    1, 0, 'C'},
         {"username", 1, 0, 'U'},
@@ -128,7 +127,6 @@ namespace
     Obsolete options:\n\
        -u|--utf8-sanitize   Repair bad UTF8 input data (present in planet\n\
                         dumps prior to August 2007). Adds about 10% overhead.\n\
-       -M|--oldmerc     Store data in the legacy OSM mercator format\n\
     \n\
     Performance options:\n\
        -i|--tablespace-index    The name of the PostgreSQL tablespace where\n\
@@ -326,9 +324,6 @@ options_t options_t::parse(int argc, char *argv[])
         case 'm':
             options.projection.reset(new reprojection(PROJ_SPHERE_MERC));
             break;
-        case 'M':
-            options.projection.reset(new reprojection(PROJ_MERC));
-            break;
         case 'E':
             options.projection.reset(new reprojection(-atoi(optarg)));
             break;
diff --git a/osm2pgsql.cpp b/osm2pgsql.cpp
index fadb41c..aa5674e 100644
--- a/osm2pgsql.cpp
+++ b/osm2pgsql.cpp
@@ -24,6 +24,8 @@
 */
 
 #include "config.h"
+#include "osmtypes.hpp"
+#include "reprojection.hpp"
 #include "options.hpp"
 #include "parse.hpp"
 #include "middle.hpp"
@@ -31,10 +33,12 @@
 #include "osmdata.hpp"
 #include "util.hpp"
 
-#include <unistd.h>
-#include <assert.h>
 #include <time.h>
 #include <stdexcept>
+#include <string>
+#include <vector>
+#include <cstdio>
+#include <cstdlib>
 
 #include <libpq-fe.h>
 #include <boost/format.hpp>
diff --git a/osmdata.cpp b/osmdata.cpp
index aa03556..95c25b5 100644
--- a/osmdata.cpp
+++ b/osmdata.cpp
@@ -1,6 +1,7 @@
 #include "osmdata.hpp"
 #include "output.hpp"
 #include "middle.hpp"
+#include "node-ram-cache.hpp"
 
 #include <boost/foreach.hpp>
 #include <boost/make_shared.hpp>
@@ -13,10 +14,6 @@
 #include <utility>
 #include <cstdio>
 
-#ifdef HAVE_LOCKFREE
-#include <boost/atomic.hpp>
-#endif
-
 osmdata_t::osmdata_t(boost::shared_ptr<middle_t> mid_, const boost::shared_ptr<output_t>& out_): mid(mid_)
 {
     outs.push_back(out_);
@@ -38,9 +35,12 @@ osmdata_t::~osmdata_t()
 int osmdata_t::node_add(osmid_t id, double lat, double lon, const taglist_t &tags) {
     mid->nodes_set(id, lat, lon, tags);
 
+    // guarantee that we use the same values as in the node cache
+    ramNode n(lon, lat);
+
     int status = 0;
     BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
-        status |= out->node_add(id, lat, lon, tags);
+        status |= out->node_add(id, n.lat(), n.lon(), tags);
     }
     return status;
 }
@@ -71,9 +71,12 @@ int osmdata_t::node_modify(osmid_t id, double lat, double lon, const taglist_t &
     slim->nodes_delete(id);
     slim->nodes_set(id, lat, lon, tags);
 
+    // guarantee that we use the same values as in the node cache
+    ramNode n(lon, lat);
+
     int status = 0;
     BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
-        status |= out->node_modify(id, lat, lon, tags);
+        status |= out->node_modify(id, n.lat(), n.lon(), tags);
     }
 
     slim->node_changed(id);
@@ -169,7 +172,6 @@ struct pending_threaded_processor : public middle_t::pending_processor {
     typedef std::vector<boost::shared_ptr<output_t> > output_vec_t;
     typedef std::pair<boost::shared_ptr<const middle_query_t>, output_vec_t> clone_t;
 
-#ifndef HAVE_LOCKFREE
     static void do_jobs(output_vec_t const& outputs, pending_queue_t& queue, size_t& ids_done, boost::mutex& mutex, int append, bool ways) {
         while (true) {
             //get the job off the queue synchronously
@@ -196,29 +198,13 @@ struct pending_threaded_processor : public middle_t::pending_processor {
             mutex.unlock();
         }
     }
-#else
-    static void do_jobs(output_vec_t const& outputs, pending_queue_t& queue, boost::atomic_size_t& ids_done, int append, bool ways) {
-        pending_job_t job;
-        while (queue.pop(job)) {
-            if(ways)
-                outputs.at(job.output_id)->pending_way(job.osm_id, append);
-            else
-                outputs.at(job.output_id)->pending_relation(job.osm_id, append);
-            ++ids_done;
-        }
-    }
-#endif
 
     //starts up count threads and works on the queue
     pending_threaded_processor(boost::shared_ptr<middle_query_t> mid, const output_vec_t& outs, size_t thread_count, size_t job_count, int append)
-#ifndef HAVE_LOCKFREE
         //note that we cant hint to the stack how large it should be ahead of time
         //we could use a different datastructure like a deque or vector but then
         //the outputs the enqueue jobs would need the version check for the push(_back) method
         : outs(outs), ids_queued(0), append(append), queue(), ids_done(0) {
-#else
-        : outs(outs), ids_queued(0), append(append), queue(job_count), ids_done(0) {
-#endif
 
         //clone all the things we need
         clones.reserve(thread_count);
@@ -258,11 +244,7 @@ struct pending_threaded_processor : public middle_t::pending_processor {
 
         //make the threads and start them
         for (size_t i = 0; i < clones.size(); ++i) {
-#ifndef HAVE_LOCKFREE
             workers.create_thread(boost::bind(do_jobs, boost::cref(clones[i].second), boost::ref(queue), boost::ref(ids_done), boost::ref(mutex), append, true));
-#else
-            workers.create_thread(boost::bind(do_jobs, boost::cref(clones[i].second), boost::ref(queue), boost::ref(ids_done), append, true));
-#endif
         }
 
         //TODO: print out partial progress
@@ -309,11 +291,7 @@ struct pending_threaded_processor : public middle_t::pending_processor {
 
         //make the threads and start them
         for (size_t i = 0; i < clones.size(); ++i) {
-#ifndef HAVE_LOCKFREE
             workers.create_thread(boost::bind(do_jobs, boost::cref(clones[i].second), boost::ref(queue), boost::ref(ids_done), boost::ref(mutex), append, false));
-#else
-            workers.create_thread(boost::bind(do_jobs, boost::cref(clones[i].second), boost::ref(queue), boost::ref(ids_done), append, false));
-#endif
         }
 
         //TODO: print out partial progress
@@ -355,14 +333,10 @@ private:
     //job queue
     pending_queue_t queue;
 
-#ifndef HAVE_LOCKFREE
     //how many ids within the job have been processed
     size_t ids_done;
     //so the threads can manage some of the shared state
     boost::mutex mutex;
-#else
-    boost::atomic_size_t ids_done;
-#endif
 };
 
 } // anonymous namespace
diff --git a/output-multi.cpp b/output-multi.cpp
index eeb9edb..49f44a0 100644
--- a/output-multi.cpp
+++ b/output-multi.cpp
@@ -1,9 +1,13 @@
 #include "output-multi.hpp"
 #include "taginfo_impl.hpp"
+#include "table.hpp"
+#include "tagtransform.hpp"
+#include "options.hpp"
+#include "middle.hpp"
+#include "id-tracker.hpp"
+#include "geometry-builder.hpp"
+#include "expire-tiles.hpp"
 
-#include <boost/format.hpp>
-#include <boost/foreach.hpp>
-#include <boost/make_shared.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 #include <vector>
 
@@ -19,7 +23,7 @@ output_multi_t::output_multi_t(const std::string &name,
       m_osm_type(m_processor->interests(geometry_processor::interest_node) ? OSMTYPE_NODE : OSMTYPE_WAY),
       m_table(new table_t(m_options.conninfo, name, m_processor->column_type(),
                           m_export_list->normal_columns(m_osm_type),
-                          m_options.hstore_columns, m_processor->srid(), m_options.scale,
+                          m_options.hstore_columns, m_processor->srid(),
                           m_options.append, m_options.slim, m_options.droptemp,
                           m_options.hstore_mode, m_options.enable_hstore_index,
                           m_options.tblsmain_data, m_options.tblsmain_index)),
diff --git a/output-multi.hpp b/output-multi.hpp
index fd4f4d9..b2f17ec 100644
--- a/output-multi.hpp
+++ b/output-multi.hpp
@@ -7,22 +7,28 @@
 #ifndef OUTPUT_MULTI_HPP
 #define OUTPUT_MULTI_HPP
 
+#include "osmtypes.hpp"
 #include "output.hpp"
-#include "tagtransform.hpp"
-#include "table.hpp"
 #include "geometry-processor.hpp"
-#include "id-tracker.hpp"
-#include "expire-tiles.hpp"
 
-#include <vector>
+#include <cstddef>
+#include <string>
 #include <boost/scoped_ptr.hpp>
-#include <boost/variant.hpp>
+#include <boost/shared_ptr.hpp>
+
+class table_t;
+class tagtransform;
+struct expire_tiles;
+struct export_list;
+struct id_tracker;
+struct middle_query_t;
+struct options_t;
 
 class output_multi_t : public output_t {
 public:
     output_multi_t(const std::string &name,
                    boost::shared_ptr<geometry_processor> processor_,
-                   const struct export_list &export_list_,
+                   const export_list &export_list_,
                    const middle_query_t* mid_, const options_t &options_);
     output_multi_t(const output_multi_t& other);
     virtual ~output_multi_t();
diff --git a/output-null.cpp b/output-null.cpp
index 5cd18e2..92a1521 100644
--- a/output-null.cpp
+++ b/output-null.cpp
@@ -1,15 +1,8 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <boost/make_shared.hpp>
-
 #include "osmtypes.hpp"
 #include "output-null.hpp"
-#include "options.hpp"
+
+struct middle_query_t;
+struct options_t;
 
 void output_null_t::cleanup() {
 }
diff --git a/output-pgsql.cpp b/output-pgsql.cpp
index b75ab82..8800d49 100644
--- a/output-pgsql.cpp
+++ b/output-pgsql.cpp
@@ -719,7 +719,7 @@ output_pgsql_t::output_pgsql_t(const middle_query_t* mid_, const options_t &opti
         //have a different tablespace/hstores/etc per table
         m_tables.push_back(boost::shared_ptr<table_t>(
             new table_t(
-                m_options.conninfo, name, type, columns, m_options.hstore_columns, SRID, m_options.scale,
+                m_options.conninfo, name, type, columns, m_options.hstore_columns, SRID,
                 m_options.append, m_options.slim, m_options.droptemp, m_options.hstore_mode,
                 m_options.enable_hstore_index, m_options.tblsmain_data, m_options.tblsmain_index
             )
diff --git a/output.hpp b/output.hpp
index 2e5c7cb..bf93f5d 100644
--- a/output.hpp
+++ b/output.hpp
@@ -10,14 +10,15 @@
 #ifndef OUTPUT_H
 #define OUTPUT_H
 
+#include "options.hpp"
 #include "middle.hpp"
 #include "id-tracker.hpp"
 #include "expire-tiles.hpp"
 
 #include <boost/noncopyable.hpp>
 #include <boost/version.hpp>
-
 #include <utility>
+#include <stack>
 
 struct pending_job_t {
     osmid_t osm_id;
@@ -27,13 +28,7 @@ struct pending_job_t {
     pending_job_t(osmid_t id, size_t oid) : osm_id(id), output_id(oid) {}
 };
 
-#ifndef HAVE_LOCKFREE
-#include <stack>
 typedef std::stack<pending_job_t> pending_queue_t;
-#else
-#include <boost/lockfree/queue.hpp>
-typedef boost::lockfree::queue<pending_job_t> pending_queue_t;
-#endif
 
 class output_t : public boost::noncopyable {
 public:
diff --git a/parse-o5m.cpp b/parse-o5m.cpp
index 1e3ca36..5162469 100644
--- a/parse-o5m.cpp
+++ b/parse-o5m.cpp
@@ -29,9 +29,10 @@
 // to get the print format specifiers in the inttypes.h header.
 #define __STDC_FORMAT_MACROS
 #include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
+#include <stdint.h>
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
 #include <unistd.h>
 #include <time.h>
 #include <fcntl.h>
@@ -41,7 +42,9 @@
 #endif
 
 #include "parse-o5m.hpp"
-#include "output.hpp"
+#include "osmdata.hpp"
+#include "osmtypes.hpp"
+#include "reprojection.hpp"
 
 #define inline
 
diff --git a/parse-o5m.hpp b/parse-o5m.hpp
index d7d3f2c..31774e5 100644
--- a/parse-o5m.hpp
+++ b/parse-o5m.hpp
@@ -26,6 +26,9 @@
 #define PARSE_O5M_H
 
 #include "parse.hpp"
+#include <boost/shared_ptr.hpp>
+
+struct reprojection;
 
 class parse_o5m_t: public parse_t
 {
@@ -33,7 +36,7 @@ public:
 	parse_o5m_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
 				const double minlon, const double minlat, const double maxlon, const double maxlat);
 	virtual ~parse_o5m_t();
-	virtual int streamFile(const char *filename, const int sanitize, osmdata_t *osmdata);
+	int streamFile(const char *filename, const int sanitize, osmdata_t *osmdata);
 protected:
 	parse_o5m_t();
 };
diff --git a/parse-pbf.cpp b/parse-pbf.cpp
index e64f603..6405b8e 100644
--- a/parse-pbf.cpp
+++ b/parse-pbf.cpp
@@ -22,9 +22,15 @@
 #-----------------------------------------------------------------------------
 */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "config.h"
+
+#ifdef BUILD_READER_PBF
+
+#include <cassert>
+#include <cstdlib>
+#include <stdint.h>
+#include <cstdio>
+#include <cstring>
 #ifdef _WIN32
 #include <winsock2.h>
 #else
@@ -33,13 +39,12 @@
 #include <time.h>
 
 #include <zlib.h>
-
-#include "config.h"
-
-#ifdef BUILD_READER_PBF
+#include <string>
 
 #include "parse-pbf.hpp"
-#include "output.hpp"
+#include "osmdata.hpp"
+#include "osmtypes.hpp"
+#include "reprojection.hpp"
 
 #define MAX_BLOCK_HEADER_SIZE 64*1024
 #define MAX_BLOB_SIZE 32*1024*1024
diff --git a/parse-pbf.hpp b/parse-pbf.hpp
index 024fecc..8a2fc98 100644
--- a/parse-pbf.hpp
+++ b/parse-pbf.hpp
@@ -25,8 +25,6 @@
 #ifndef PARSE_PBF_H
 #define PARSE_PBF_H
 
-#include "parse.hpp"
-
 #include "config.h"
 
 #ifdef BUILD_READER_PBF
@@ -35,6 +33,14 @@ extern "C" {
 #include "osmformat.pb-c.h"
 }
 
+#include "parse.hpp"
+
+#include <cstddef>
+#include <boost/shared_ptr.hpp>
+
+struct reprojection;
+class osmdata_t;
+
 class parse_pbf_t: public parse_t
 {
 public:
diff --git a/parse-xml2.cpp b/parse-xml2.cpp
index 8718f76..49fe259 100644
--- a/parse-xml2.cpp
+++ b/parse-xml2.cpp
@@ -22,17 +22,20 @@
 #-----------------------------------------------------------------------------
 */
 
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
 #include <time.h>
 
 #include "sanitizer.hpp"
 #include "input.hpp"
 
 #include "parse-xml2.hpp"
-#include "output.hpp"
+#include "osmtypes.hpp"
+#include "osmdata.hpp"
 #include "util.hpp"
+#include "reprojection.hpp"
 
 /* Parses the action="foo" tags in JOSM change files. Obvisouly not useful from osmChange files */
 actions_t parse_xml2_t::ParseAction( xmlTextReaderPtr reader)
diff --git a/parse-xml2.hpp b/parse-xml2.hpp
index 55d6112..d9cd263 100644
--- a/parse-xml2.hpp
+++ b/parse-xml2.hpp
@@ -40,7 +40,6 @@
 
 #include "parse.hpp"
 
-#include <libxml/xmlstring.h>
 #include <libxml/xmlreader.h>
 
 class parse_xml2_t: public parse_t
diff --git a/parse.cpp b/parse.cpp
index cf760ca..f02d463 100644
--- a/parse.cpp
+++ b/parse.cpp
@@ -1,13 +1,17 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdexcept>
+#include "config.h"
+#include "parse.hpp"
 #include "parse-o5m.hpp"
 #ifdef BUILD_READER_PBF
 #  include "parse-pbf.hpp"
 #endif
 #include "parse-xml2.hpp"
-#include "util.hpp"
+
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <stdexcept>
+#include <algorithm>
+
 
 #define INIT_MAX_MEMBERS 64
 #define INIT_MAX_NODES  4096
diff --git a/parse.hpp b/parse.hpp
index 718cb30..6e3aeb2 100644
--- a/parse.hpp
+++ b/parse.hpp
@@ -1,13 +1,10 @@
 #ifndef PARSE_H
 #define PARSE_H
 
-#include <time.h>
-
-#include "config.h"
 #include "osmtypes.hpp"
-#include "reprojection.hpp"
-#include "osmdata.hpp"
 
+#include <time.h>
+#include <string>
 #include <boost/shared_ptr.hpp>
 #include <boost/optional.hpp>
 
@@ -15,6 +12,8 @@ typedef enum { FILETYPE_NONE, FILETYPE_OSM, FILETYPE_OSMCHANGE, FILETYPE_PLANETD
 typedef enum { ACTION_NONE, ACTION_CREATE, ACTION_MODIFY, ACTION_DELETE } actions_t;
 
 class parse_t;
+class osmdata_t;
+struct reprojection;
 
 class parse_delegate_t
 {
diff --git a/pgsql-id-tracker.cpp b/pgsql-id-tracker.cpp
index 890eff6..bcd54af 100644
--- a/pgsql-id-tracker.cpp
+++ b/pgsql-id-tracker.cpp
@@ -1,7 +1,9 @@
 #include "pgsql-id-tracker.hpp"
 
+#include <cassert>
+#include <cstdio>
+#include <limits>
 #include <libpq-fe.h>
-#include <string>
 #include <boost/format.hpp>
 
 #include "osmtypes.hpp"
diff --git a/pgsql-id-tracker.hpp b/pgsql-id-tracker.hpp
index 1726149..4a140ee 100644
--- a/pgsql-id-tracker.hpp
+++ b/pgsql-id-tracker.hpp
@@ -3,6 +3,9 @@
 
 #include "id-tracker.hpp"
 
+#include <string>
+#include <boost/smart_ptr/scoped_ptr.hpp>
+
 struct pgsql_id_tracker : public id_tracker {
     pgsql_id_tracker(const std::string &conninfo,
                      const std::string &prefix,
diff --git a/pgsql.cpp b/pgsql.cpp
index 9c164b2..847ab8a 100644
--- a/pgsql.cpp
+++ b/pgsql.cpp
@@ -1,11 +1,9 @@
 /* Helper functions for the postgresql connections */
 #include "pgsql.hpp"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <libpq-fe.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstdarg>
 #include <boost/format.hpp>
 #include <boost/foreach.hpp>
 
diff --git a/processor-line.cpp b/processor-line.cpp
index cc540a8..7ac7cd8 100644
--- a/processor-line.cpp
+++ b/processor-line.cpp
@@ -1,7 +1,5 @@
 #include "processor-line.hpp"
 
-#include <boost/format.hpp>
-
 processor_line::processor_line(int srid) : geometry_processor(srid, "LINESTRING", interest_way)
 {
 }
diff --git a/processor-point.cpp b/processor-point.cpp
index bd84f06..4eab45d 100644
--- a/processor-point.cpp
+++ b/processor-point.cpp
@@ -1,22 +1,17 @@
+#include "config.h" // for FIXED_POINT
 #include "processor-point.hpp"
 #include "util.hpp"
 
 #include <boost/format.hpp>
 
-processor_point::processor_point(int srid, double scale)
-    : geometry_processor(srid, "POINT", interest_node),
-      m_scale(scale) {
+processor_point::processor_point(int srid)
+    : geometry_processor(srid, "POINT", interest_node) {
 }
 
 processor_point::~processor_point() {
 }
 
 geometry_builder::maybe_wkt_t processor_point::process_node(double lat, double lon) {
-#ifdef FIXED_POINT
-    // guarantee that we use the same values as in the node cache
-    lon = util::fix_to_double(util::double_to_fix(lon, m_scale), m_scale);
-    lat = util::fix_to_double(util::double_to_fix(lat, m_scale), m_scale);
-#endif
     geometry_builder::maybe_wkt_t wkt(new geometry_builder::wkt_t());
     wkt->geom = (boost::format("POINT(%.15g %.15g)") % lon % lat).str();
     return wkt;
diff --git a/processor-point.hpp b/processor-point.hpp
index 088ef97..55b9ebd 100644
--- a/processor-point.hpp
+++ b/processor-point.hpp
@@ -4,13 +4,10 @@
 #include "geometry-processor.hpp"
 
 struct processor_point : public geometry_processor {
-    processor_point(int srid, double scale);
+    processor_point(int srid);
     virtual ~processor_point();
 
     geometry_builder::maybe_wkt_t process_node(double lat, double lon);
-
-private:
-    double m_scale; // <-- used only when FIXED_POINT is defined, which seems like never?
 };
 
 #endif /* PROCESSOR_POINT_HPP */
diff --git a/processor-polygon.cpp b/processor-polygon.cpp
index e91d55f..95b9ff1 100644
--- a/processor-polygon.cpp
+++ b/processor-polygon.cpp
@@ -1,7 +1,5 @@
 #include "processor-polygon.hpp"
 
-#include <boost/format.hpp>
-
 processor_polygon::processor_polygon(int srid, bool enable_multi) : geometry_processor(srid, "GEOMETRY", interest_way | interest_relation), enable_multi(enable_multi)
 {
 }
diff --git a/rb.cpp b/rb.cpp
deleted file mode 100644
index 084e7fd..0000000
--- a/rb.cpp
+++ /dev/null
@@ -1,930 +0,0 @@
-/* Produced by texiweb from libavl.w. */
-
-/* libavl - library for manipulation of binary trees.
-   Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc.
-
-   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 2 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, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
-
-   The author may be contacted at <blp at gnu.org> on the Internet, or
-   write to Ben Pfaff, Stanford University, Computer Science Dept., 353
-   Serra Mall, Stanford CA 94305, USA.
-*/
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "rb.hpp"
-
-/* Creates and returns a new table
-   with comparison function |compare| using parameter |param|
-   and memory allocator |allocator|.
-   Returns |NULL| if memory allocation failed. */
-struct rb_table *
-rb_create (rb_comparison_func *compare, void *param,
-            struct libavl_allocator *allocator)
-{
-  struct rb_table *tree;
-
-  assert (compare != NULL);
-
-  if (allocator == NULL)
-    allocator = &rb_allocator_default;
-
-  tree = (struct rb_table *)allocator->libavl_malloc (allocator, sizeof *tree);
-  if (tree == NULL)
-    return NULL;
-
-  tree->rb_root = NULL;
-  tree->rb_compare = compare;
-  tree->rb_param = param;
-  tree->rb_alloc = allocator;
-  tree->rb_count = 0;
-  tree->rb_generation = 0;
-
-  return tree;
-}
-
-/* Search |tree| for an item matching |item|, and return it if found.
-   Otherwise return |NULL|. */
-void *
-rb_find (const struct rb_table *tree, const void *item)
-{
-  const struct rb_node *p;
-
-  assert (tree != NULL && item != NULL);
-  for (p = tree->rb_root; p != NULL; )
-    {
-      int cmp = tree->rb_compare (item, p->rb_data, tree->rb_param);
-
-      if (cmp < 0)
-        p = p->rb_link[0];
-      else if (cmp > 0)
-        p = p->rb_link[1];
-      else /* |cmp == 0| */
-        return p->rb_data;
-    }
-
-  return NULL;
-}
-
-/* Inserts |item| into |tree| and returns a pointer to |item|'s address.
-   If a duplicate item is found in the tree,
-   returns a pointer to the duplicate without inserting |item|.
-   Returns |NULL| in case of memory allocation failure. */
-void **
-rb_probe (struct rb_table *tree, void *item)
-{
-  struct rb_node *pa[RB_MAX_HEIGHT]; /* Nodes on stack. */
-  unsigned char da[RB_MAX_HEIGHT];   /* Directions moved from stack nodes. */
-  int k;                             /* Stack height. */
-
-  struct rb_node *p; /* Traverses tree looking for insertion point. */
-  struct rb_node *n; /* Newly inserted node. */
-
-  assert (tree != NULL && item != NULL);
-
-  pa[0] = (struct rb_node *) &tree->rb_root;
-  da[0] = 0;
-  k = 1;
-  for (p = tree->rb_root; p != NULL; p = p->rb_link[da[k - 1]])
-    {
-      int cmp = tree->rb_compare (item, p->rb_data, tree->rb_param);
-      if (cmp == 0)
-        return &p->rb_data;
-
-      pa[k] = p;
-      da[k++] = cmp > 0;
-    }
-
-  n = pa[k - 1]->rb_link[da[k - 1]] =
-      (struct rb_node *)tree->rb_alloc->libavl_malloc (tree->rb_alloc, sizeof *n);
-  if (n == NULL)
-    return NULL;
-
-  n->rb_data = item;
-  n->rb_link[0] = n->rb_link[1] = NULL;
-  n->rb_color = RB_RED;
-  tree->rb_count++;
-  tree->rb_generation++;
-
-  while (k >= 3 && pa[k - 1]->rb_color == RB_RED)
-    {
-      if (da[k - 2] == 0)
-        {
-          struct rb_node *y = pa[k - 2]->rb_link[1];
-          if (y != NULL && y->rb_color == RB_RED)
-            {
-              pa[k - 1]->rb_color = y->rb_color = RB_BLACK;
-              pa[k - 2]->rb_color = RB_RED;
-              k -= 2;
-            }
-          else
-            {
-              struct rb_node *x;
-
-              if (da[k - 1] == 0)
-                y = pa[k - 1];
-              else
-                {
-                  x = pa[k - 1];
-                  y = x->rb_link[1];
-                  x->rb_link[1] = y->rb_link[0];
-                  y->rb_link[0] = x;
-                  pa[k - 2]->rb_link[0] = y;
-                }
-
-              x = pa[k - 2];
-              x->rb_color = RB_RED;
-              y->rb_color = RB_BLACK;
-
-              x->rb_link[0] = y->rb_link[1];
-              y->rb_link[1] = x;
-              pa[k - 3]->rb_link[da[k - 3]] = y;
-              break;
-            }
-        }
-      else
-        {
-          struct rb_node *y = pa[k - 2]->rb_link[0];
-          if (y != NULL && y->rb_color == RB_RED)
-            {
-              pa[k - 1]->rb_color = y->rb_color = RB_BLACK;
-              pa[k - 2]->rb_color = RB_RED;
-              k -= 2;
-            }
-          else
-            {
-              struct rb_node *x;
-
-              if (da[k - 1] == 1)
-                y = pa[k - 1];
-              else
-                {
-                  x = pa[k - 1];
-                  y = x->rb_link[0];
-                  x->rb_link[0] = y->rb_link[1];
-                  y->rb_link[1] = x;
-                  pa[k - 2]->rb_link[1] = y;
-                }
-
-              x = pa[k - 2];
-              x->rb_color = RB_RED;
-              y->rb_color = RB_BLACK;
-
-              x->rb_link[1] = y->rb_link[0];
-              y->rb_link[0] = x;
-              pa[k - 3]->rb_link[da[k - 3]] = y;
-              break;
-            }
-        }
-    }
-  tree->rb_root->rb_color = RB_BLACK;
-
-
-  return &n->rb_data;
-}
-
-/* Inserts |item| into |table|.
-   Returns |NULL| if |item| was successfully inserted
-   or if a memory allocation error occurred.
-   Otherwise, returns the duplicate item. */
-void *
-rb_insert (struct rb_table *table, void *item)
-{
-  void **p = rb_probe (table, item);
-  return p == NULL || *p == item ? NULL : *p;
-}
-
-/* Inserts |item| into |table|, replacing any duplicate item.
-   Returns |NULL| if |item| was inserted without replacing a duplicate,
-   or if a memory allocation error occurred.
-   Otherwise, returns the item that was replaced. */
-void *
-rb_replace (struct rb_table *table, void *item)
-{
-  void **p = rb_probe (table, item);
-  if (p == NULL || *p == item)
-    return NULL;
-  else
-    {
-      void *r = *p;
-      *p = item;
-      return r;
-    }
-}
-
-/* Deletes from |tree| and returns an item matching |item|.
-   Returns a null pointer if no matching item found. */
-void *
-rb_delete (struct rb_table *tree, const void *item)
-{
-  struct rb_node *pa[RB_MAX_HEIGHT]; /* Nodes on stack. */
-  unsigned char da[RB_MAX_HEIGHT];   /* Directions moved from stack nodes. */
-  int k;                             /* Stack height. */
-
-  struct rb_node *p;    /* The node to delete, or a node part way to it. */
-  int cmp;              /* Result of comparison between |item| and |p|. */
-
-  assert (tree != NULL && item != NULL);
-
-  k = 0;
-  p = (struct rb_node *) &tree->rb_root;
-  for (cmp = -1; cmp != 0;
-       cmp = tree->rb_compare (item, p->rb_data, tree->rb_param))
-    {
-      int dir = cmp > 0;
-
-      pa[k] = p;
-      da[k++] = dir;
-
-      p = p->rb_link[dir];
-      if (p == NULL)
-        return NULL;
-    }
-  item = p->rb_data;
-
-  if (p->rb_link[1] == NULL)
-    pa[k - 1]->rb_link[da[k - 1]] = p->rb_link[0];
-  else
-    {
-      enum rb_color t;
-      struct rb_node *r = p->rb_link[1];
-
-      if (r->rb_link[0] == NULL)
-        {
-          r->rb_link[0] = p->rb_link[0];
-          t = r->rb_color;
-          r->rb_color = p->rb_color;
-          p->rb_color = t;
-          pa[k - 1]->rb_link[da[k - 1]] = r;
-          da[k] = 1;
-          pa[k++] = r;
-        }
-      else
-        {
-          struct rb_node *s;
-          int j = k++;
-
-          for (;;)
-            {
-              da[k] = 0;
-              pa[k++] = r;
-              s = r->rb_link[0];
-              if (s->rb_link[0] == NULL)
-                break;
-
-              r = s;
-            }
-
-          da[j] = 1;
-          pa[j] = s;
-          pa[j - 1]->rb_link[da[j - 1]] = s;
-
-          s->rb_link[0] = p->rb_link[0];
-          r->rb_link[0] = s->rb_link[1];
-          s->rb_link[1] = p->rb_link[1];
-
-          t = s->rb_color;
-          s->rb_color = p->rb_color;
-          p->rb_color = t;
-        }
-    }
-
-  if (p->rb_color == RB_BLACK)
-    {
-      for (;;)
-        {
-          struct rb_node *x = pa[k - 1]->rb_link[da[k - 1]];
-          if (x != NULL && x->rb_color == RB_RED)
-            {
-              x->rb_color = RB_BLACK;
-              break;
-            }
-          if (k < 2)
-            break;
-
-          if (da[k - 1] == 0)
-            {
-              struct rb_node *w = pa[k - 1]->rb_link[1];
-
-              if (w->rb_color == RB_RED)
-                {
-                  w->rb_color = RB_BLACK;
-                  pa[k - 1]->rb_color = RB_RED;
-
-                  pa[k - 1]->rb_link[1] = w->rb_link[0];
-                  w->rb_link[0] = pa[k - 1];
-                  pa[k - 2]->rb_link[da[k - 2]] = w;
-
-                  pa[k] = pa[k - 1];
-                  da[k] = 0;
-                  pa[k - 1] = w;
-                  k++;
-
-                  w = pa[k - 1]->rb_link[1];
-                }
-
-              if ((w->rb_link[0] == NULL
-                   || w->rb_link[0]->rb_color == RB_BLACK)
-                  && (w->rb_link[1] == NULL
-                      || w->rb_link[1]->rb_color == RB_BLACK))
-                w->rb_color = RB_RED;
-              else
-                {
-                  if (w->rb_link[1] == NULL
-                      || w->rb_link[1]->rb_color == RB_BLACK)
-                    {
-                      struct rb_node *y = w->rb_link[0];
-                      y->rb_color = RB_BLACK;
-                      w->rb_color = RB_RED;
-                      w->rb_link[0] = y->rb_link[1];
-                      y->rb_link[1] = w;
-                      w = pa[k - 1]->rb_link[1] = y;
-                    }
-
-                  w->rb_color = pa[k - 1]->rb_color;
-                  pa[k - 1]->rb_color = RB_BLACK;
-                  w->rb_link[1]->rb_color = RB_BLACK;
-
-                  pa[k - 1]->rb_link[1] = w->rb_link[0];
-                  w->rb_link[0] = pa[k - 1];
-                  pa[k - 2]->rb_link[da[k - 2]] = w;
-                  break;
-                }
-            }
-          else
-            {
-              struct rb_node *w = pa[k - 1]->rb_link[0];
-
-              if (w->rb_color == RB_RED)
-                {
-                  w->rb_color = RB_BLACK;
-                  pa[k - 1]->rb_color = RB_RED;
-
-                  pa[k - 1]->rb_link[0] = w->rb_link[1];
-                  w->rb_link[1] = pa[k - 1];
-                  pa[k - 2]->rb_link[da[k - 2]] = w;
-
-                  pa[k] = pa[k - 1];
-                  da[k] = 1;
-                  pa[k - 1] = w;
-                  k++;
-
-                  w = pa[k - 1]->rb_link[0];
-                }
-
-              if ((w->rb_link[0] == NULL
-                   || w->rb_link[0]->rb_color == RB_BLACK)
-                  && (w->rb_link[1] == NULL
-                      || w->rb_link[1]->rb_color == RB_BLACK))
-                w->rb_color = RB_RED;
-              else
-                {
-                  if (w->rb_link[0] == NULL
-                      || w->rb_link[0]->rb_color == RB_BLACK)
-                    {
-                      struct rb_node *y = w->rb_link[1];
-                      y->rb_color = RB_BLACK;
-                      w->rb_color = RB_RED;
-                      w->rb_link[1] = y->rb_link[0];
-                      y->rb_link[0] = w;
-                      w = pa[k - 1]->rb_link[0] = y;
-                    }
-
-                  w->rb_color = pa[k - 1]->rb_color;
-                  pa[k - 1]->rb_color = RB_BLACK;
-                  w->rb_link[0]->rb_color = RB_BLACK;
-
-                  pa[k - 1]->rb_link[0] = w->rb_link[1];
-                  w->rb_link[1] = pa[k - 1];
-                  pa[k - 2]->rb_link[da[k - 2]] = w;
-                  break;
-                }
-            }
-
-          k--;
-        }
-
-    }
-
-  tree->rb_alloc->libavl_free (tree->rb_alloc, p);
-  tree->rb_count--;
-  tree->rb_generation++;
-  return (void *) item;
-}
-
-/* Refreshes the stack of parent pointers in |trav|
-   and updates its generation number. */
-static void
-trav_refresh (struct rb_traverser *trav)
-{
-  assert (trav != NULL);
-
-  trav->rb_generation = trav->rb_table->rb_generation;
-
-  if (trav->rb_node != NULL)
-    {
-      rb_comparison_func *cmp = trav->rb_table->rb_compare;
-      void *param = trav->rb_table->rb_param;
-      struct rb_node *node = trav->rb_node;
-      struct rb_node *i;
-
-      trav->rb_height = 0;
-      for (i = trav->rb_table->rb_root; i != node; )
-        {
-          assert (trav->rb_height < RB_MAX_HEIGHT);
-          assert (i != NULL);
-
-          trav->rb_stack[trav->rb_height++] = i;
-          i = i->rb_link[cmp (node->rb_data, i->rb_data, param) > 0];
-        }
-    }
-}
-
-/* Initializes |trav| for use with |tree|
-   and selects the null node. */
-void
-rb_t_init (struct rb_traverser *trav, struct rb_table *tree)
-{
-  trav->rb_table = tree;
-  trav->rb_node = NULL;
-  trav->rb_height = 0;
-  trav->rb_generation = tree->rb_generation;
-}
-
-/* Initializes |trav| for |tree|
-   and selects and returns a pointer to its least-valued item.
-   Returns |NULL| if |tree| contains no nodes. */
-void *
-rb_t_first (struct rb_traverser *trav, struct rb_table *tree)
-{
-  struct rb_node *x;
-
-  assert (tree != NULL && trav != NULL);
-
-  trav->rb_table = tree;
-  trav->rb_height = 0;
-  trav->rb_generation = tree->rb_generation;
-
-  x = tree->rb_root;
-  if (x != NULL)
-    while (x->rb_link[0] != NULL)
-      {
-        assert (trav->rb_height < RB_MAX_HEIGHT);
-        trav->rb_stack[trav->rb_height++] = x;
-        x = x->rb_link[0];
-      }
-  trav->rb_node = x;
-
-  return x != NULL ? x->rb_data : NULL;
-}
-
-/* Initializes |trav| for |tree|
-   and selects and returns a pointer to its greatest-valued item.
-   Returns |NULL| if |tree| contains no nodes. */
-void *
-rb_t_last (struct rb_traverser *trav, struct rb_table *tree)
-{
-  struct rb_node *x;
-
-  assert (tree != NULL && trav != NULL);
-
-  trav->rb_table = tree;
-  trav->rb_height = 0;
-  trav->rb_generation = tree->rb_generation;
-
-  x = tree->rb_root;
-  if (x != NULL)
-    while (x->rb_link[1] != NULL)
-      {
-        assert (trav->rb_height < RB_MAX_HEIGHT);
-        trav->rb_stack[trav->rb_height++] = x;
-        x = x->rb_link[1];
-      }
-  trav->rb_node = x;
-
-  return x != NULL ? x->rb_data : NULL;
-}
-
-/* Searches for |item| in |tree|.
-   If found, initializes |trav| to the item found and returns the item
-   as well.
-   If there is no matching item, initializes |trav| to the null item
-   and returns |NULL|. */
-void *
-rb_t_find (struct rb_traverser *trav, struct rb_table *tree, void *item)
-{
-  struct rb_node *p, *q;
-
-  assert (trav != NULL && tree != NULL && item != NULL);
-  trav->rb_table = tree;
-  trav->rb_height = 0;
-  trav->rb_generation = tree->rb_generation;
-  for (p = tree->rb_root; p != NULL; p = q)
-    {
-      int cmp = tree->rb_compare (item, p->rb_data, tree->rb_param);
-
-      if (cmp < 0)
-        q = p->rb_link[0];
-      else if (cmp > 0)
-        q = p->rb_link[1];
-      else /* |cmp == 0| */
-        {
-          trav->rb_node = p;
-          return p->rb_data;
-        }
-
-      assert (trav->rb_height < RB_MAX_HEIGHT);
-      trav->rb_stack[trav->rb_height++] = p;
-    }
-
-  trav->rb_height = 0;
-  trav->rb_node = NULL;
-  return NULL;
-}
-
-/* Attempts to insert |item| into |tree|.
-   If |item| is inserted successfully, it is returned and |trav| is
-   initialized to its location.
-   If a duplicate is found, it is returned and |trav| is initialized to
-   its location.  No replacement of the item occurs.
-   If a memory allocation failure occurs, |NULL| is returned and |trav|
-   is initialized to the null item. */
-void *
-rb_t_insert (struct rb_traverser *trav, struct rb_table *tree, void *item)
-{
-  void **p;
-
-  assert (trav != NULL && tree != NULL && item != NULL);
-
-  p = rb_probe (tree, item);
-  if (p != NULL)
-    {
-      trav->rb_table = tree;
-      trav->rb_node =
-        ((struct rb_node *)
-         ((char *) p - offsetof (struct rb_node, rb_data)));
-      trav->rb_generation = tree->rb_generation - 1;
-      return *p;
-    }
-  else
-    {
-      rb_t_init (trav, tree);
-      return NULL;
-    }
-}
-
-/* Initializes |trav| to have the same current node as |src|. */
-void *
-rb_t_copy (struct rb_traverser *trav, const struct rb_traverser *src)
-{
-  assert (trav != NULL && src != NULL);
-
-  if (trav != src)
-    {
-      trav->rb_table = src->rb_table;
-      trav->rb_node = src->rb_node;
-      trav->rb_generation = src->rb_generation;
-      if (trav->rb_generation == trav->rb_table->rb_generation)
-        {
-          trav->rb_height = src->rb_height;
-          memcpy (trav->rb_stack, (const void *) src->rb_stack,
-                  sizeof *trav->rb_stack * trav->rb_height);
-        }
-    }
-
-  return trav->rb_node != NULL ? trav->rb_node->rb_data : NULL;
-}
-
-/* Returns the next data item in inorder
-   within the tree being traversed with |trav|,
-   or if there are no more data items returns |NULL|. */
-void *
-rb_t_next (struct rb_traverser *trav)
-{
-  struct rb_node *x;
-
-  assert (trav != NULL);
-
-  if (trav->rb_generation != trav->rb_table->rb_generation)
-    trav_refresh (trav);
-
-  x = trav->rb_node;
-  if (x == NULL)
-    {
-      return rb_t_first (trav, trav->rb_table);
-    }
-  else if (x->rb_link[1] != NULL)
-    {
-      assert (trav->rb_height < RB_MAX_HEIGHT);
-      trav->rb_stack[trav->rb_height++] = x;
-      x = x->rb_link[1];
-
-      while (x->rb_link[0] != NULL)
-        {
-          assert (trav->rb_height < RB_MAX_HEIGHT);
-          trav->rb_stack[trav->rb_height++] = x;
-          x = x->rb_link[0];
-        }
-    }
-  else
-    {
-      struct rb_node *y;
-
-      do
-        {
-          if (trav->rb_height == 0)
-            {
-              trav->rb_node = NULL;
-              return NULL;
-            }
-
-          y = x;
-          x = trav->rb_stack[--trav->rb_height];
-        }
-      while (y == x->rb_link[1]);
-    }
-  trav->rb_node = x;
-
-  return x->rb_data;
-}
-
-/* Returns the previous data item in inorder
-   within the tree being traversed with |trav|,
-   or if there are no more data items returns |NULL|. */
-void *
-rb_t_prev (struct rb_traverser *trav)
-{
-  struct rb_node *x;
-
-  assert (trav != NULL);
-
-  if (trav->rb_generation != trav->rb_table->rb_generation)
-    trav_refresh (trav);
-
-  x = trav->rb_node;
-  if (x == NULL)
-    {
-      return rb_t_last (trav, trav->rb_table);
-    }
-  else if (x->rb_link[0] != NULL)
-    {
-      assert (trav->rb_height < RB_MAX_HEIGHT);
-      trav->rb_stack[trav->rb_height++] = x;
-      x = x->rb_link[0];
-
-      while (x->rb_link[1] != NULL)
-        {
-          assert (trav->rb_height < RB_MAX_HEIGHT);
-          trav->rb_stack[trav->rb_height++] = x;
-          x = x->rb_link[1];
-        }
-    }
-  else
-    {
-      struct rb_node *y;
-
-      do
-        {
-          if (trav->rb_height == 0)
-            {
-              trav->rb_node = NULL;
-              return NULL;
-            }
-
-          y = x;
-          x = trav->rb_stack[--trav->rb_height];
-        }
-      while (y == x->rb_link[0]);
-    }
-  trav->rb_node = x;
-
-  return x->rb_data;
-}
-
-/* Returns |trav|'s current item. */
-void *
-rb_t_cur (struct rb_traverser *trav)
-{
-  assert (trav != NULL);
-
-  return trav->rb_node != NULL ? trav->rb_node->rb_data : NULL;
-}
-
-/* Replaces the current item in |trav| by |new| and returns the item replaced.
-   |trav| must not have the null item selected.
-   The new item must not upset the ordering of the tree. */
-void *
-rb_t_replace (struct rb_traverser *trav, void *new_)
-{
-  void *old;
-
-  assert (trav != NULL && trav->rb_node != NULL && new_ != NULL);
-  old = trav->rb_node->rb_data;
-  trav->rb_node->rb_data = new_;
-  return old;
-}
-
-/* Destroys |new| with |rb_destroy (new, destroy)|,
-   first setting right links of nodes in |stack| within |new|
-   to null pointers to avoid touching uninitialized data. */
-static void
-copy_error_recovery (struct rb_node **stack, int height,
-                     struct rb_table *new_, rb_item_func *destroy)
-{
-  assert (stack != NULL && height >= 0 && new_ != NULL);
-
-  for (; height > 2; height -= 2)
-    stack[height - 1]->rb_link[1] = NULL;
-  rb_destroy (new_, destroy);
-}
-
-/* Copies |org| to a newly created tree, which is returned.
-   If |copy != NULL|, each data item in |org| is first passed to |copy|,
-   and the return values are inserted into the tree,
-   with |NULL| return values taken as indications of failure.
-   On failure, destroys the partially created new tree,
-   applying |destroy|, if non-null, to each item in the new tree so far,
-   and returns |NULL|.
-   If |allocator != NULL|, it is used for allocation in the new tree.
-   Otherwise, the same allocator used for |org| is used. */
-struct rb_table *
-rb_copy (const struct rb_table *org, rb_copy_func *copy,
-          rb_item_func *destroy, struct libavl_allocator *allocator)
-{
-  struct rb_node *stack[2 * (RB_MAX_HEIGHT + 1)];
-  int height = 0;
-
-  struct rb_table *new_;
-  const struct rb_node *x;
-  struct rb_node *y;
-
-  assert (org != NULL);
-  new_ = rb_create (org->rb_compare, org->rb_param,
-                    allocator != NULL ? allocator : org->rb_alloc);
-  if (new_ == NULL)
-    return NULL;
-  new_->rb_count = org->rb_count;
-  if (new_->rb_count == 0)
-    return new_;
-
-  x = (const struct rb_node *) &org->rb_root;
-  y = (struct rb_node *) &new_->rb_root;
-  for (;;)
-    {
-      while (x->rb_link[0] != NULL)
-        {
-          assert (height < 2 * (RB_MAX_HEIGHT + 1));
-
-          y->rb_link[0] =
-              (struct rb_node *)
-              new_->rb_alloc->libavl_malloc (new_->rb_alloc,
-                                             sizeof *y->rb_link[0]);
-          if (y->rb_link[0] == NULL)
-            {
-              if (y != (struct rb_node *) &new_->rb_root)
-                {
-                  y->rb_data = NULL;
-                  y->rb_link[1] = NULL;
-                }
-
-              copy_error_recovery (stack, height, new_, destroy);
-              return NULL;
-            }
-
-          stack[height++] = (struct rb_node *) x;
-          stack[height++] = y;
-          x = x->rb_link[0];
-          y = y->rb_link[0];
-        }
-      y->rb_link[0] = NULL;
-
-      for (;;)
-        {
-          y->rb_color = x->rb_color;
-          if (copy == NULL)
-            y->rb_data = x->rb_data;
-          else
-            {
-              y->rb_data = copy (x->rb_data, org->rb_param);
-              if (y->rb_data == NULL)
-                {
-                  y->rb_link[1] = NULL;
-                  copy_error_recovery (stack, height, new_, destroy);
-                  return NULL;
-                }
-            }
-
-          if (x->rb_link[1] != NULL)
-            {
-              y->rb_link[1] =
-                  (struct rb_node *)
-                  new_->rb_alloc->libavl_malloc (new_->rb_alloc,
-                                                 sizeof *y->rb_link[1]);
-              if (y->rb_link[1] == NULL)
-                {
-                  copy_error_recovery (stack, height, new_, destroy);
-                  return NULL;
-                }
-
-              x = x->rb_link[1];
-              y = y->rb_link[1];
-              break;
-            }
-          else
-            y->rb_link[1] = NULL;
-
-          if (height <= 2)
-            return new_;
-
-          y = stack[--height];
-          x = stack[--height];
-        }
-    }
-}
-
-/* Frees storage allocated for |tree|.
-   If |destroy != NULL|, applies it to each data item in inorder. */
-void
-rb_destroy (struct rb_table *tree, rb_item_func *destroy)
-{
-  struct rb_node *p, *q;
-
-  assert (tree != NULL);
-
-  for (p = tree->rb_root; p != NULL; p = q)
-    if (p->rb_link[0] == NULL)
-      {
-        q = p->rb_link[1];
-        if (destroy != NULL && p->rb_data != NULL)
-          destroy (p->rb_data, tree->rb_param);
-        tree->rb_alloc->libavl_free (tree->rb_alloc, p);
-      }
-    else
-      {
-        q = p->rb_link[0];
-        p->rb_link[0] = q->rb_link[1];
-        q->rb_link[1] = p;
-      }
-
-  tree->rb_alloc->libavl_free (tree->rb_alloc, tree);
-}
-
-/* Allocates |size| bytes of space using |malloc()|.
-   Returns a null pointer if allocation fails. */
-void *
-rb_malloc (struct libavl_allocator *allocator, size_t size)
-{
-  assert (allocator != NULL && size > 0);
-  return malloc (size);
-}
-
-/* Frees |block|. */
-void
-rb_free (struct libavl_allocator *allocator, void *block)
-{
-  assert (allocator != NULL && block != NULL);
-  free (block);
-}
-
-/* Default memory allocator that uses |malloc()| and |free()|. */
-struct libavl_allocator rb_allocator_default =
-  {
-    rb_malloc,
-    rb_free
-  };
-
-#undef NDEBUG
-#include <assert.h>
-
-/* Asserts that |rb_insert()| succeeds at inserting |item| into |table|. */
-void
-(rb_assert_insert) (struct rb_table *table, void *item)
-{
-  void **p = rb_probe (table, item);
-  assert (p != NULL && *p == item);
-}
-
-/* Asserts that |rb_delete()| really removes |item| from |table|,
-   and returns the removed item. */
-void *
-(rb_assert_delete) (struct rb_table *table, void *item)
-{
-  void *p = rb_delete (table, item);
-  assert (p != NULL);
-  return p;
-}
diff --git a/rb.hpp b/rb.hpp
deleted file mode 100644
index b16feab..0000000
--- a/rb.hpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/* Produced by texiweb from libavl.w. */
-
-/* libavl - library for manipulation of binary trees.
-   Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc.
-
-   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 2 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, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
-
-   The author may be contacted at <blp at gnu.org> on the Internet, or
-   write to Ben Pfaff, Stanford University, Computer Science Dept., 353
-   Serra Mall, Stanford CA 94305, USA.
-*/
-
-#ifndef RB_H
-#define RB_H 1
-
-#include <stddef.h>
-
-/* Function types. */
-typedef int rb_comparison_func (const void *rb_a, const void *rb_b,
-                                 void *rb_param);
-typedef void rb_item_func (void *rb_item, void *rb_param);
-typedef void *rb_copy_func (void *rb_item, void *rb_param);
-
-#ifndef LIBAVL_ALLOCATOR
-#define LIBAVL_ALLOCATOR
-/* Memory allocator. */
-struct libavl_allocator
-  {
-    void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size);
-    void (*libavl_free) (struct libavl_allocator *, void *libavl_block);
-  };
-#endif
-
-/* Default memory allocator. */
-extern struct libavl_allocator rb_allocator_default;
-void *rb_malloc (struct libavl_allocator *, size_t);
-void rb_free (struct libavl_allocator *, void *);
-
-/* Maximum RB height. */
-#ifndef RB_MAX_HEIGHT
-#define RB_MAX_HEIGHT 48
-#endif
-
-/* Tree data structure. */
-struct rb_table
-  {
-    struct rb_node *rb_root;          /* Tree's root. */
-    rb_comparison_func *rb_compare;   /* Comparison function. */
-    void *rb_param;                    /* Extra argument to |rb_compare|. */
-    struct libavl_allocator *rb_alloc; /* Memory allocator. */
-    size_t rb_count;                   /* Number of items in tree. */
-    unsigned long rb_generation;       /* Generation number. */
-  };
-
-/* Color of a red-black node. */
-enum rb_color
-  {
-    RB_BLACK,   /* Black. */
-    RB_RED      /* Red. */
-  };
-
-/* A red-black tree node. */
-struct rb_node
-  {
-    struct rb_node *rb_link[2];   /* Subtrees. */
-    void *rb_data;                /* Pointer to data. */
-    enum rb_color rb_color;       /* Color. */
-  };
-
-/* RB traverser structure. */
-struct rb_traverser
-  {
-    struct rb_table *rb_table;        /* Tree being traversed. */
-    struct rb_node *rb_node;          /* Current node in tree. */
-    struct rb_node *rb_stack[RB_MAX_HEIGHT];
-                                        /* All the nodes above |rb_node|. */
-    size_t rb_height;                  /* Number of nodes in |rb_parent|. */
-    unsigned long rb_generation;       /* Generation number. */
-  };
-
-/* Table functions. */
-struct rb_table *rb_create (rb_comparison_func *, void *,
-                              struct libavl_allocator *);
-struct rb_table *rb_copy (const struct rb_table *, rb_copy_func *,
-                            rb_item_func *, struct libavl_allocator *);
-void rb_destroy (struct rb_table *, rb_item_func *);
-void **rb_probe (struct rb_table *, void *);
-void *rb_insert (struct rb_table *, void *);
-void *rb_replace (struct rb_table *, void *);
-void *rb_delete (struct rb_table *, const void *);
-void *rb_find (const struct rb_table *, const void *);
-void rb_assert_insert (struct rb_table *, void *);
-void *rb_assert_delete (struct rb_table *, void *);
-
-#define rb_count(table) ((size_t) (table)->rb_count)
-
-/* Table traverser functions. */
-void rb_t_init (struct rb_traverser *, struct rb_table *);
-void *rb_t_first (struct rb_traverser *, struct rb_table *);
-void *rb_t_last (struct rb_traverser *, struct rb_table *);
-void *rb_t_find (struct rb_traverser *, struct rb_table *, void *);
-void *rb_t_insert (struct rb_traverser *, struct rb_table *, void *);
-void *rb_t_copy (struct rb_traverser *, const struct rb_traverser *);
-void *rb_t_next (struct rb_traverser *);
-void *rb_t_prev (struct rb_traverser *);
-void *rb_t_cur (struct rb_traverser *);
-void *rb_t_replace (struct rb_traverser *, void *);
-
-#endif /* rb.h */
diff --git a/reprojection.cpp b/reprojection.cpp
index a2a7ebb..276f61d 100644
--- a/reprojection.cpp
+++ b/reprojection.cpp
@@ -7,11 +7,11 @@
 
 #include "config.h"
 
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
 #include <proj_api.h>
-#include <math.h>
+#include <cmath>
 
 #include "reprojection.hpp"
 
@@ -34,11 +34,6 @@ const struct Projection_Info Projection_Infos[] = {
         /*proj4text*/ "+init=epsg:4326",
         /*srs      */ 4326,
         /*option   */ "-l" ),
-    /*PROJ_MERC*/ Projection_Info(
-        /*descr    */ "WGS84 Mercator",
-        /*proj4text*/ "+proj=merc +datum=WGS84  +k=1/*0 +units=m +over +no_defs",
-        /*srs      */ 3395,
-        /*option   */ "-M" ),
     /*PROJ_SPHERE_MERC*/ Projection_Info(
         /*descr    */ "Spherical Mercator",
         /*proj4text*/ "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs",
diff --git a/reprojection.hpp b/reprojection.hpp
index 0d9a03c..91093de 100644
--- a/reprojection.hpp
+++ b/reprojection.hpp
@@ -19,7 +19,7 @@ struct Projection_Info {
     const char *option;
 };
 
-enum Projection { PROJ_LATLONG = 0, PROJ_MERC, PROJ_SPHERE_MERC,   PROJ_COUNT };
+enum Projection { PROJ_LATLONG = 0, PROJ_SPHERE_MERC, PROJ_COUNT };
 
 struct reprojection : public boost::noncopyable
 {
diff --git a/sanitizer.hpp b/sanitizer.hpp
index beb24a4..82ad083 100644
--- a/sanitizer.hpp
+++ b/sanitizer.hpp
@@ -1,7 +1,6 @@
 #ifndef SANITIZER_H
 #define SANITIZER_H
 
-#include <libxml/xmlstring.h>
 #include <libxml/xmlreader.h>
 
 xmlTextReaderPtr sanitizerOpen(const char *name);
diff --git a/style.lua b/style.lua
index c0a646e..c42c689 100644
--- a/style.lua
+++ b/style.lua
@@ -1,8 +1,12 @@
+-- For documentation of Lua tag transformations, see docs/lua.md.
+
+-- Objects with any of the following keys will be treated as polygon
 polygon_keys = { 'building', 'landuse', 'amenity', 'harbour', 'historic', 'leisure', 
       'man_made', 'military', 'natural', 'office', 'place', 'power',
       'public_transport', 'shop', 'sport', 'tourism', 'waterway',
       'wetland', 'water', 'aeroway' }
 
+-- Objects without any of the following keys will be deleted
 generic_keys = {'access','addr:housename','addr:housenumber','addr:interpolation','admin_level','aerialway','aeroway','amenity','area','barrier',
    'bicycle','brand','bridge','boundary','building','capital','construction','covered','culvert','cutting','denomination','disused','ele',
    'embarkment','foot','generation:source','harbour','highway','historic','hours','intermittent','junction','landuse','layer','leisure','lock',
@@ -10,26 +14,37 @@ generic_keys = {'access','addr:housename','addr:housenumber','addr:interpolation
    'railway','ref','religion','route','service','shop','sport','surface','toll','tourism','tower:type', 'tracktype','tunnel','water','waterway',
    'wetland','width','wood','type'}
 
+-- The following keys will be deleted
+delete_tags = { 'FIXME', 'note', 'source' }
+
+-- Array used to specify z_order per key/value combination.
+-- Each element has the form {key, value, z_order, is_road}.
+-- If is_road=1, the object will be added to planet_osm_roads.
+zordering_tags = {{ 'railway', nil, 5, 1}, { 'boundary', 'administrative', 0, 1}, 
+   { 'bridge', 'yes', 10, 0 }, { 'bridge', 'true', 10, 0 }, { 'bridge', 1, 10, 0 },
+   { 'tunnel', 'yes', -10, 0}, { 'tunnel', 'true', -10, 0}, { 'tunnel', 1, -10, 0}, 
+   { 'highway', 'minor', 3, 0}, { 'highway', 'road', 3, 0 }, { 'highway', 'unclassified', 3, 0 },
+   { 'highway', 'residential', 3, 0 }, { 'highway', 'tertiary_link', 4, 0}, { 'highway', 'tertiary', 4, 0},
+   { 'highway', 'secondary_link', 6, 1}, { 'highway', 'secondary', 6, 1},
+   { 'highway', 'primary_link', 7, 1}, { 'highway', 'primary', 7, 1},
+   { 'highway', 'trunk_link', 8, 1}, { 'highway', 'trunk', 8, 1},
+   { 'highway', 'motorway_link', 9, 1}, { 'highway', 'motorway', 9, 1},
+}
+
 function add_z_order(keyvalues)
+   -- The default z_order is 0
    z_order = 0
+
+   -- Add the value of the layer key times 10 to z_order
    if (keyvalues["layer"] ~= nil and tonumber(keyvalues["layer"])) then
       z_order = 10*keyvalues["layer"]
    end
 
-   
-   zordering_tags = {{ 'railway', nil, 5, 1}, { 'boundary', 'administrative', 0, 1}, 
-      { 'bridge', 'yes', 10, 0 }, { 'bridge', 'true', 10, 0 }, { 'bridge', 1, 10, 0 },
-      { 'tunnel', 'yes', -10, 0}, { 'tunnel', 'true', -10, 0}, { 'tunnel', 1, -10, 0}, 
-      { 'highway', 'minor', 3, 0}, { 'highway', 'road', 3, 0 }, { 'highway', 'unclassified', 3, 0 },
-      { 'highway', 'residential', 3, 0 }, { 'highway', 'tertiary_link', 4, 0}, { 'highway', 'tertiary', 4, 0},
-      { 'highway', 'secondary_link', 6, 1}, { 'highway', 'secondary', 6, 1},
-      { 'highway', 'primary_link', 7, 1}, { 'highway', 'primary', 7, 1},
-      { 'highway', 'trunk_link', 8, 1}, { 'highway', 'trunk', 8, 1},
-      { 'highway', 'motorway_link', 9, 1}, { 'highway', 'motorway', 9, 1},
-}
-   
+   -- Increase or decrease z_order based on the specific key/value combination as specified in zordering_tags
    for i,k in ipairs(zordering_tags) do
+      -- If the value in zordering_tags is specified, match key and value. Otherwise, match key only.
       if ((k[2]  and keyvalues[k[1]] == k[2]) or (k[2] == nil and keyvalues[k[1]] ~= nil)) then
+         -- If the fourth component of the element of zordering_tags is 1, add the object to planet_osm_roads
          if (k[4] == 1) then
             roads = 1
          end
@@ -37,27 +52,29 @@ function add_z_order(keyvalues)
       end
    end
 
+   -- Add z_order as key/value combination
    keyvalues["z_order"] = z_order
 
    return keyvalues, roads
-
 end
 
-function filter_tags_generic(keyvalues, nokeys)
-   filter = 0
-   tagcount = 0
+-- Filtering on nodes, ways, and relations
+function filter_tags_generic(keyvalues, numberofkeys)
+   filter = 0   -- Will object be filtered out?
 
-   if nokeys == 0 then
+   -- Filter out objects with 0 tags
+   if numberofkeys == 0 then
       filter = 1
       return filter, keyvalues
    end
 
-   delete_tags = { 'FIXME', 'note', 'source' }
-
+   -- Delete tags listed in delete_tags
    for i,k in ipairs(delete_tags) do
       keyvalues[k] = nil
    end
    
+   -- Filter out objects that do not have any of the keys in generic_keys
+   tagcount = 0
    for k,v in pairs(keyvalues) do
       for i, k2 in ipairs(generic_keys) do if k2 == k then tagcount = tagcount + 1; end end
    end
@@ -68,17 +85,20 @@ function filter_tags_generic(keyvalues, nokeys)
    return filter, keyvalues
 end
 
-function filter_tags_node (keyvalues, nokeys)
-   return filter_tags_generic(keyvalues, nokeys)
+-- Filtering on nodes
+function filter_tags_node (keyvalues, numberofkeys)
+   return filter_tags_generic(keyvalues, numberofkeys)
 end
 
-function filter_basic_tags_rel (keyvalues, nokeys)
-
-   filter, keyvalues = filter_tags_generic(keyvalues, nokeys)
+-- Filtering on relations
+function filter_basic_tags_rel (keyvalues, numberofkeys)
+   -- Filter out objects that are filtered out by filter_tags_generic
+   filter, keyvalues = filter_tags_generic(keyvalues, numberofkeys)
    if filter == 1 then
       return filter, keyvalues
    end
 
+   -- Filter out all relations except route, multipolygon and boundary relations
    if ((keyvalues["type"] ~= "route") and (keyvalues["type"] ~= "multipolygon") and (keyvalues["type"] ~= "boundary")) then
       filter = 1
       return filter, keyvalues
@@ -87,66 +107,74 @@ function filter_basic_tags_rel (keyvalues, nokeys)
    return filter, keyvalues
 end
 
-function filter_tags_way (keyvalues, nokeys)
-   filter = 0
-   poly = 0
-   tagcount = 0
-   roads = 0
+-- Filtering on ways
+function filter_tags_way (keyvalues, numberofkeys)
+   filter = 0  -- Will object be filtered out?
+   polygon = 0 -- Will object be treated as polygon?
+   roads = 0   -- Will object be added to planet_osm_roads?
 
-   filter, keyvalues = filter_tags_generic(keyvalues, nokeys)
+   -- Filter out objects that are filtered out by filter_tags_generic
+   filter, keyvalues = filter_tags_generic(keyvalues, numberofkeys)
    if filter == 1 then
-      return filter, keyvalues, poly, roads
+      return filter, keyvalues, polygon, roads
    end
 
-
+  -- Treat objects with a key in polygon_keys as polygon
    for i,k in ipairs(polygon_keys) do
       if keyvalues[k] then
-         poly=1
+         polygon=1
          break
       end
    end
    
-
+   -- Treat objects tagged as area=yes, area=1, or area=true as polygon,
+   -- and treat objects tagged as area=no, area=0, or area=false not as polygon
    if ((keyvalues["area"] == "yes") or (keyvalues["area"] == "1") or (keyvalues["area"] == "true")) then
-      poly = 1;
+      polygon = 1;
    elseif ((keyvalues["area"] == "no") or (keyvalues["area"] == "0") or (keyvalues["area"] == "false")) then
-      poly = 0;
+      polygon = 0;
    end
 
+   -- Add z_order key/value combination and determine if the object should also be added to planet_osm_roads
    keyvalues, roads = add_z_order(keyvalues)
 
-
-   return filter, keyvalues, poly, roads
+   return filter, keyvalues, polygon, roads
 end
 
 function filter_tags_relation_member (keyvalues, keyvaluemembers, roles, membercount)
-   
-   filter = 0
-   boundary = 0
-   polygon = 0
-   roads = 0
-   membersuperseeded = {}
+   filter = 0     -- Will object be filtered out?
+   linestring = 0 -- Will object be treated as linestring?
+   polygon = 0    -- Will object be treated as polygon?
+   roads = 0      -- Will object be added to planet_osm_roads?
+   membersuperseded = {}
    for i = 1, membercount do
-      membersuperseeded[i] = 0
+      membersuperseded[i] = 0 -- Will member be ignored when handling areas?
    end
 
    type = keyvalues["type"]
+
+   -- Remove type key
    keyvalues["type"] = nil
   
-
+   -- Relations with type=boundary are treated as linestring
    if (type == "boundary") then
-      boundary = 1
+      linestring = 1
    end
+   -- Relations with type=multipolygon and boundary=* are treated as linestring
    if ((type == "multipolygon") and keyvalues["boundary"]) then
-      boundary = 1
+      linestring = 1
+   -- For multipolygons...
    elseif (type == "multipolygon") then
+      -- Treat as polygon
       polygon = 1
       polytagcount = 0;
+      -- Count the number of polygon tags of the object
       for i,k in ipairs(polygon_keys) do
          if keyvalues[k] then
             polytagcount = polytagcount + 1
          end
       end
+      -- If there are no polygon tags, add tags from all outer elements to the multipolygon itself
       if (polytagcount == 0) then
          for i = 1,membercount do
             if (roles[i] == "outer") then
@@ -156,23 +184,28 @@ function filter_tags_relation_member (keyvalues, keyvaluemembers, roles, memberc
             end
          end
       end
+      -- For any member of the multipolygon, set membersuperseded to 1 (i.e. don't deal with it as area as well),
+      -- except when the member has a key/value combination such that
+      --   1) the key occurs in generic_keys
+      --   2) the key/value combination is not also a key/value combination of the multipolygon itself
       for i = 1,membercount do
-         superseeded = 1
+         superseded = 1
          for k,v in pairs(keyvaluemembers[i]) do
             if ((keyvalues[k] == nil) or (keyvalues[k] ~= v)) then
                for j,k2 in ipairs(generic_keys) do
                   if (k == k2) then
-                     superseeded = 0;
+                     superseded = 0;
                      break
                   end
                end
             end
          end
-         membersuperseeded[i] = superseeded
+         membersuperseded[i] = superseded
       end
    end
 
+   -- Add z_order key/value combination and determine if the object should also be added to planet_osm_roads
    keyvalues, roads = add_z_order(keyvalues)
 
-   return filter, keyvalues, membersuperseeded, boundary, polygon, roads
+   return filter, keyvalues, membersuperseded, linestring, polygon, roads
 end
diff --git a/table.cpp b/table.cpp
index 84cd7e9..8c7a882 100644
--- a/table.cpp
+++ b/table.cpp
@@ -2,18 +2,23 @@
 #include "options.hpp"
 #include "util.hpp"
 
-#include <string.h>
+#include <exception>
+#include <algorithm>
+#include <cstring>
+#include <cstdio>
 #include <utility>
+#include <time.h>
 
 using std::string;
+typedef boost::format fmt;
 
 #define BUFFER_SEND_SIZE 1024
 
 
 table_t::table_t(const string& conninfo, const string& name, const string& type, const columns_t& columns, const hstores_t& hstore_columns,
-    const int srid, const int scale, const bool append, const bool slim, const bool drop_temp, const int hstore_mode,
+    const int srid, const bool append, const bool slim, const bool drop_temp, const int hstore_mode,
     const bool enable_hstore_index, const boost::optional<string>& table_space, const boost::optional<string>& table_space_index) :
-    conninfo(conninfo), name(name), type(type), sql_conn(NULL), copyMode(false), srid((fmt("%1%") % srid).str()), scale(scale),
+    conninfo(conninfo), name(name), type(type), sql_conn(NULL), copyMode(false), srid((fmt("%1%") % srid).str()),
     append(append), slim(slim), drop_temp(drop_temp), hstore_mode(hstore_mode), enable_hstore_index(enable_hstore_index),
     columns(columns), hstore_columns(hstore_columns), table_space(table_space), table_space_index(table_space_index)
 {
@@ -31,7 +36,7 @@ table_t::table_t(const string& conninfo, const string& name, const string& type,
 }
 
 table_t::table_t(const table_t& other):
-    conninfo(other.conninfo), name(other.name), type(other.type), sql_conn(NULL), copyMode(false), buffer(), srid(other.srid), scale(other.scale),
+    conninfo(other.conninfo), name(other.name), type(other.type), sql_conn(NULL), copyMode(false), buffer(), srid(other.srid),
     append(other.append), slim(other.slim), drop_temp(other.drop_temp), hstore_mode(other.hstore_mode), enable_hstore_index(other.enable_hstore_index),
     columns(other.columns), hstore_columns(other.hstore_columns), copystr(other.copystr), table_space(other.table_space),
     table_space_index(other.table_space_index), single_fmt(other.single_fmt), point_fmt(other.point_fmt), del_fmt(other.del_fmt)
@@ -295,12 +300,6 @@ void table_t::stop_copy()
 
 void table_t::write_node(const osmid_t id, const taglist_t &tags, double lat, double lon)
 {
-#ifdef FIXED_POINT
-    // guarantee that we use the same values as in the node cache
-    lon = util::fix_to_double(util::double_to_fix(lon, scale), scale);
-    lat = util::fix_to_double(util::double_to_fix(lat, scale), scale);
-#endif
-
     write_wkt(id, tags, (point_fmt % lon % lat).str().c_str());
 }
 
diff --git a/table.hpp b/table.hpp
index c51970c..91e41ce 100644
--- a/table.hpp
+++ b/table.hpp
@@ -4,21 +4,23 @@
 #include "pgsql.hpp"
 #include "osmtypes.hpp"
 
+#include <cstddef>
 #include <string>
 #include <vector>
+#include <utility>
 
 #include <boost/optional.hpp>
 #include <boost/format.hpp>
+#include <boost/shared_ptr.hpp>
 
 typedef std::vector<std::string> hstores_t;
 typedef std::vector<std::pair<std::string, std::string> > columns_t;
-typedef boost::format fmt;
 
 class table_t
 {
     public:
         table_t(const std::string& conninfo, const std::string& name, const std::string& type, const columns_t& columns, const hstores_t& hstore_columns, const int srid,
-                const int scale, const bool append, const bool slim, const bool droptemp, const int hstore_mode, const bool enable_hstore_index,
+                const bool append, const bool slim, const bool droptemp, const int hstore_mode, const bool enable_hstore_index,
                 const boost::optional<std::string>& table_space, const boost::optional<std::string>& table_space_index);
         table_t(const table_t& other);
         ~table_t();
@@ -72,7 +74,6 @@ class table_t
         bool copyMode;
         std::string buffer;
         std::string srid;
-        int scale;
         bool append;
         bool slim;
         bool drop_temp;
@@ -84,7 +85,7 @@ class table_t
         boost::optional<std::string> table_space;
         boost::optional<std::string> table_space_index;
 
-        fmt single_fmt, point_fmt, del_fmt;
+        boost::format single_fmt, point_fmt, del_fmt;
 };
 
 #endif
diff --git a/tagtransform.cpp b/tagtransform.cpp
index 45bee84..208b33c 100644
--- a/tagtransform.cpp
+++ b/tagtransform.cpp
@@ -1,16 +1,24 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
 #include <stdexcept>
-#include "osmtypes.hpp"
+#include <vector>
+#include <boost/format.hpp>
+
 #include "tagtransform.hpp"
-#include "output-pgsql.hpp"
 #include "options.hpp"
 #include "config.h"
 #include "wildcmp.hpp"
 #include "taginfo_impl.hpp"
 
+#ifdef HAVE_LUA
+extern "C" {
+    #include <lualib.h>
+    #include <lauxlib.h>
+}
+#endif
+
 
 static const struct {
     int offset;
diff --git a/tagtransform.hpp b/tagtransform.hpp
index a64b688..00547ac 100644
--- a/tagtransform.hpp
+++ b/tagtransform.hpp
@@ -2,14 +2,17 @@
 #ifndef TAGTRANSFORM_H
 #define TAGTRANSFORM_H
 
-#include "output.hpp"
-#include "taginfo.hpp"
+#include "config.h"
+#include "osmtypes.hpp"
+
+#include <string>
+
+struct options_t;
+struct export_list;
 
 #ifdef HAVE_LUA
 extern "C" {
-	#include <lua.h>
-	#include <lualib.h>
-	#include <lauxlib.h>
+    #include <lua.h>
 }
 #endif
 
diff --git a/tests/middle-tests.cpp b/tests/middle-tests.cpp
index 0e20623..e6df830 100644
--- a/tests/middle-tests.cpp
+++ b/tests/middle-tests.cpp
@@ -4,46 +4,135 @@
 #include <string.h>
 #include <cassert>
 #include <list>
+#include <tuple>
 
 #include "osmtypes.hpp"
 #include "tests/middle-tests.hpp"
 
+#define BLOCK_SHIFT 10
+#define PER_BLOCK  (((osmid_t)1) << BLOCK_SHIFT)
+
+struct expected_node {
+  osmid_t id;
+  double lon;
+  double lat;
+
+  expected_node() : id(0), lon(NAN), lat(NAN) {}
+
+  expected_node(osmid_t id, double x, double y) : id(id), lon(x), lat(y) {}
+};
+
+typedef std::vector<expected_node> expected_nodelist_t;
+
+#define ALLOWED_ERROR 10e-9
+bool node_okay(osmNode node, expected_node expected) {
+  if ((node.lat > expected.lat + ALLOWED_ERROR) || (node.lat < expected.lat - ALLOWED_ERROR)) {
+    std::cerr << "ERROR: Node should have lat=" << expected.lat << ", but got back "
+              << node.lat << " from middle.\n";
+    return false;
+  }
+  if ((node.lon > expected.lon + ALLOWED_ERROR) || (node.lon < expected.lon - ALLOWED_ERROR)) {
+    std::cerr << "ERROR: Node should have lon=" << expected.lon << ", but got back "
+              << node.lon << " from middle.\n";
+    return false;
+  }
+  return true;
+}
+
 int test_node_set(middle_t *mid)
 {
   idlist_t ids;
-  osmid_t id = 1234;
-  double lat = 12.3456789;
-  double lon = 98.7654321;
+  expected_node expected(1234, 12.3456789, 98.7654321);
   taglist_t tags;
   nodelist_t nodes;
-  int status = 0;
 
   // set the node
-  status = mid->nodes_set(id, lat, lon, tags);
-  if (status != 0) { std::cerr << "ERROR: Unable to set node.\n"; return 1; }
+  if (mid->nodes_set(expected.id, expected.lat, expected.lon, tags) != 0) { std::cerr << "ERROR: Unable to set node.\n"; return 1; }
 
   // get it back
-  ids.push_back(id);
-  int count = mid->nodes_get_list(nodes, ids);
-  if (count != 1) { std::cerr << "ERROR: Unable to get node list.\n"; return 1; }
+  ids.push_back(expected.id);
+  if (mid->nodes_get_list(nodes, ids) != ids.size()) { std::cerr << "ERROR: Unable to get node list.\n"; return 1; }
+  if (nodes.size() != ids.size()) { std::cerr << "ERROR: Mismatch in returned node list size.\n"; return 1; }
 
   // check that it's the same
-  if (nodes[0].lon != lon) {
-    std::cerr << "ERROR: Node should have lon=" << lon << ", but got back "
-              << nodes[0].lon << " from middle.\n";
+  if (!node_okay(nodes[0], expected)) {
     return 1;
   }
-  if (nodes[0].lat != lat) {
-    std::cerr << "ERROR: Node should have lat=" << lat << ", but got back "
-              << nodes[0].lat << " from middle.\n";
-    return 1;
+
+  return 0;
+}
+
+inline double test_lat(osmid_t id) {
+  return 1 + 1e-5 * id;
+}
+
+int test_nodes_comprehensive_set(middle_t *mid)
+{
+  taglist_t tags;
+
+  expected_nodelist_t expected_nodes;
+  expected_nodes.reserve(PER_BLOCK*8+1);
+
+  // 2 dense blocks, the second partially filled at the star
+  for (osmid_t id = 0; id < (PER_BLOCK+(PER_BLOCK >> 1) + 1); ++id)
+  {
+    expected_nodes.emplace_back(id, test_lat(id), 0.0);
   }
 
-  // clean up for next test
-  if (dynamic_cast<slim_middle_t *>(mid)) {
-    dynamic_cast<slim_middle_t *>(mid)->nodes_delete(id);
+  // 1 dense block, 75% filled
+  for (osmid_t id = PER_BLOCK*2; id < PER_BLOCK*3; ++id)
+  {
+    if ((id % 4 == 0) || (id % 4 == 1) || (id % 4 == 2))
+      expected_nodes.emplace_back(id, test_lat(id), 0.0);
   }
 
+  // 1 dense block, sparsly filled
+  for (osmid_t id = PER_BLOCK*3; id < PER_BLOCK*4; ++id)
+  {
+    if (id % 4 == 0)
+      expected_nodes.emplace_back(id, test_lat(id), 0.0);
+  }
+
+  // A lone sparse node
+  expected_nodes.emplace_back(PER_BLOCK*5, test_lat(PER_BLOCK*5), 0.0);
+
+  // A dense block of alternating positions of zero/non-zero
+  for (osmid_t id = PER_BLOCK*6; id < PER_BLOCK*7; ++id)
+  {
+    if (id % 2 == 0)
+      expected_nodes.emplace_back(id, 0.0, 0.0);
+    else
+      expected_nodes.emplace_back(id, test_lat(id), 0.0);
+  }
+  expected_nodes.emplace_back(PER_BLOCK*8, 0.0, 0.0);
+  expected_nodes.emplace_back(PER_BLOCK*8+1, 0.0, 0.0);
+
+  // Load up the nodes into the middle
+  idlist_t ids;
+  ids.reserve(expected_nodes.size());
+
+  for (expected_nodelist_t::iterator node = expected_nodes.begin(); node != expected_nodes.end(); ++node)
+  {
+    if (mid->nodes_set(node->id, node->lat, node->lon, tags) != 0)
+    {
+      std::cerr << "ERROR: Unable to set node " << node->id << "with lat="
+                << node->lat << " lon=" << node->lon << std::endl;
+      return 1;
+    }
+    ids.push_back(node->id);
+  }
+
+  nodelist_t nodes;
+  if (mid->nodes_get_list(nodes, ids) != ids.size()) { std::cerr << "ERROR: Unable to get node list.\n"; return 1; }
+
+  if (nodes.size() != ids.size()) { std::cerr << "ERROR: Mismatch in returned node list size.\n"; return 1; }
+
+  for (size_t i = 0; i < nodes.size(); ++i)
+  {
+    if (!node_okay(nodes[i], expected_nodes[i])) {
+      return 1;
+    }
+  }
   return 0;
 }
 
@@ -157,18 +246,5 @@ int test_way_set(middle_t *mid)
       }
   }
 
-  // clean up for next test
-  if (dynamic_cast<slim_middle_t *>(mid)) {
-      slim_middle_t *slim = dynamic_cast<slim_middle_t *>(mid);
-
-      for (size_t i = 0; i < nds.size(); ++i) {
-          slim->nodes_delete(nds[i]);
-      }
-      slim->ways_delete(way_id);
-  }
-
-  // commit the torn-down data
-  mid->commit();
-
   return 0;
 }
diff --git a/tests/middle-tests.hpp b/tests/middle-tests.hpp
index 0193912..a8c1b09 100644
--- a/tests/middle-tests.hpp
+++ b/tests/middle-tests.hpp
@@ -6,6 +6,9 @@
 // tests that a single node can be set and retrieved. returns 0 on success.
 int test_node_set(middle_t *mid);
 
+// tests various combinations of nodes being set and retrieved to trigger different cache strategies. returns 0 on success.
+int test_nodes_comprehensive_set(middle_t *mid);
+
 // tests that a single way and supporting nodes can be set and retrieved.
 // returns 0 on success.
 int test_way_set(middle_t *mid);
diff --git a/tests/regression-test.py b/tests/regression-test.py
index 9244b2a..617fd50 100755
--- a/tests/regression-test.py
+++ b/tests/regression-test.py
@@ -115,7 +115,7 @@ sql_test_statements=[
     ( 65, 'Multipolygon non copying of tags from outer with polygon tags on relation (presence of way)',
       'SELECT round(ST_Area(way)) FROM planet_osm_polygon WHERE osm_id = 83 and "landuse" = \'farmland\'', 24859),
     ( 66, 'Multipolygon diff moved point of outer way case (Tags from outer way)',
-      'SELECT round(ST_Area(way)) FROM planet_osm_polygon WHERE osm_id = -15 and landuse = \'residential\' and name = \'Name_way\'', 24751),
+      'SELECT round(ST_Area(way)) FROM planet_osm_polygon WHERE osm_id = -15 and landuse = \'residential\' and name = \'Name_way\'', 24750),
     ( 67, 'Multipolygon diff moved point of inner way case (Tags from relation)',
       'SELECT round(ST_Area(way)) FROM planet_osm_polygon WHERE osm_id = -1 and landuse = \'residential\' and name = \'Name_rel\'', 13949),
     ( 68, 'Multipolygon point of inner way case (Tags from relation)',
diff --git a/tests/test-expire-tiles.cpp b/tests/test-expire-tiles.cpp
index 4bc0b43..258f6fe 100644
--- a/tests/test-expire-tiles.cpp
+++ b/tests/test-expire-tiles.cpp
@@ -1,4 +1,5 @@
 #include "expire-tiles.hpp"
+#include "options.hpp"
 
 #include <stdio.h>
 #include <string.h>
diff --git a/tests/test-middle-pgsql.cpp b/tests/test-middle-pgsql.cpp
index c926e12..191f81d 100644
--- a/tests/test-middle-pgsql.cpp
+++ b/tests/test-middle-pgsql.cpp
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "osmtypes.hpp"
-#include "middle.hpp"
 #include "output-null.hpp"
 #include "options.hpp"
 #include "middle-pgsql.hpp"
@@ -22,59 +21,83 @@
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
 
-int main(int argc, char *argv[]) {
-  boost::scoped_ptr<pg::tempdb> db;
-
-  try {
-    db.reset(new pg::tempdb);
-  } catch (const std::exception &e) {
-    std::cerr << "Unable to setup database: " << e.what() << "\n";
-    return 77; // <-- code to skip this test.
-  }
+void run_tests(options_t options, const std::string cache_type) {
+  options.append = 0;
+  options.create = 1;
+  {
+    middle_pgsql_t mid_pgsql;
+    output_null_t out_test(&mid_pgsql, options);
 
-  struct middle_pgsql_t mid_pgsql;
-  options_t options;
-  options.conninfo = db->conninfo().c_str();
-  options.scale = 10000000;
-  options.num_procs = 1;
-  options.prefix = "osm2pgsql_test";
-  options.tblsslim_index = "tablespacetest";
-  options.tblsslim_data = "tablespacetest";
-  options.slim = 1;
+    mid_pgsql.start(&options);
 
-  struct output_null_t out_test(&mid_pgsql, options);
+    if (test_node_set(&mid_pgsql) != 0) { throw std::runtime_error("test_node_set failed."); }
 
-  try {
-    // start an empty table to make the middle create the
-    // tables it needs. we then run the test in "append" mode.
-    mid_pgsql.start(&options);
     mid_pgsql.commit();
     mid_pgsql.stop();
-
-    options.append = 1; /* <- needed because we're going to change the
-                         *    data and check that the updates fire. */
+  }
+  {
+    middle_pgsql_t mid_pgsql;
+    output_null_t out_test(&mid_pgsql, options);
 
     mid_pgsql.start(&options);
 
-    int status = 0;
+    if (test_nodes_comprehensive_set(&mid_pgsql) != 0) { throw std::runtime_error("test_nodes_comprehensive_set failed."); }
 
-    status = test_node_set(&mid_pgsql);
-    if (status != 0) { mid_pgsql.stop(); throw std::runtime_error("test_node_set failed."); }
+    mid_pgsql.commit();
+    mid_pgsql.stop();
+  }
+  {
+    middle_pgsql_t mid_pgsql;
+    output_null_t out_test(&mid_pgsql, options);
 
-    status = test_way_set(&mid_pgsql);
-    if (status != 0) { mid_pgsql.stop(); throw std::runtime_error("test_way_set failed."); }
+    mid_pgsql.start(&options);
+    mid_pgsql.commit();
+    mid_pgsql.stop();
+    // Switch to append mode because this tests updates
+    options.append = 1;
+    options.create = 0;
+    mid_pgsql.start(&options);
+    if (test_way_set(&mid_pgsql) != 0) { throw std::runtime_error("test_way_set failed."); }
 
     mid_pgsql.commit();
     mid_pgsql.stop();
+  }
+}
+int main(int argc, char *argv[]) {
+  boost::scoped_ptr<pg::tempdb> db;
 
-    return 0;
+  try {
+    db.reset(new pg::tempdb);
+  } catch (const std::exception &e) {
+    std::cerr << "Unable to setup database: " << e.what() << "\n";
+    return 77; // <-- code to skip this test.
+  }
 
+  try {
+    options_t options;
+    options.conninfo = db->conninfo().c_str();
+    options.scale = 10000000;
+    options.cache = 1;
+    options.num_procs = 1;
+    options.prefix = "osm2pgsql_test";
+    options.slim = 1;
+
+    options.alloc_chunkwise = ALLOC_SPARSE | ALLOC_DENSE; // what you get with optimized
+    run_tests(options, "optimized");
+    options.alloc_chunkwise = ALLOC_SPARSE;
+    run_tests(options, "sparse");
+
+    options.alloc_chunkwise = ALLOC_DENSE;
+    run_tests(options, "dense");
+
+    options.alloc_chunkwise = ALLOC_DENSE | ALLOC_DENSE_CHUNK; // what you get with chunk
+    run_tests(options, "chunk");
   } catch (const std::exception &e) {
     std::cerr << "ERROR: " << e.what() << std::endl;
-
+    return 1;
   } catch (...) {
     std::cerr << "UNKNOWN ERROR" << std::endl;
+    return 1;
   }
-
-  return 1;
+  return 0;
 }
diff --git a/tests/test-middle-ram.cpp b/tests/test-middle-ram.cpp
index 59a2b63..8e51482 100644
--- a/tests/test-middle-ram.cpp
+++ b/tests/test-middle-ram.cpp
@@ -6,45 +6,69 @@
 #include <stdexcept>
 
 #include "osmtypes.hpp"
-#include "middle.hpp"
 #include "output-null.hpp"
 #include "options.hpp"
 #include "middle-ram.hpp"
-#include "node-ram-cache.hpp"
 
 #include "tests/middle-tests.hpp"
 
-int main(int argc, char *argv[]) {
-  try {
-    options_t options;
-    options.scale = 10000000;
-    options.alloc_chunkwise = ALLOC_SPARSE | ALLOC_DENSE;
-    options.cache = 1;
-
-    struct middle_ram_t mid_ram;
-    struct output_null_t out_test(&mid_ram, options);
+void run_tests(const options_t options, const std::string cache_type) {
+  {
+    middle_ram_t mid_ram;
+    output_null_t out_test(&mid_ram, options);
 
     mid_ram.start(&options);
 
-    int status = 0;
+    if (test_node_set(&mid_ram) != 0) { throw std::runtime_error("test_node_set failed with " + cache_type + " cache."); }
+    mid_ram.commit();
+    mid_ram.stop();
+  }
+  {
+    middle_ram_t mid_ram;
+    output_null_t out_test(&mid_ram, options);
+
+    mid_ram.start(&options);
 
-    status = test_node_set(&mid_ram);
-    if (status != 0) { throw std::runtime_error("test_node_set failed."); }
+    if (test_nodes_comprehensive_set(&mid_ram) != 0) { throw std::runtime_error("test_nodes_comprehensive_set failed with " + cache_type + " cache."); }
+    mid_ram.commit();
+    mid_ram.stop();
+  }
+  {
+    middle_ram_t mid_ram;
+    output_null_t out_test(&mid_ram, options);
 
-    status = test_way_set(&mid_ram);
-    if (status != 0) { throw std::runtime_error("test_node_set failed."); }
+    mid_ram.start(&options);
 
+    if (test_way_set(&mid_ram) != 0) { throw std::runtime_error("test_way_set failed with " + cache_type + " cache."); }
     mid_ram.commit();
     mid_ram.stop();
+  }
+}
+
+int main(int argc, char *argv[]) {
+  try {
+    options_t options;
+    options.scale = 10000000;
+    options.cache = 1; // Non-zero cache is needed to test
 
-    return 0;
+    options.alloc_chunkwise = ALLOC_SPARSE | ALLOC_DENSE; // what you get with optimized
+    run_tests(options, "optimized");
 
+    options.alloc_chunkwise = ALLOC_SPARSE;
+    run_tests(options, "sparse");
+
+    options.alloc_chunkwise = ALLOC_DENSE;
+    run_tests(options, "dense");
+
+    options.alloc_chunkwise = ALLOC_DENSE | ALLOC_DENSE_CHUNK; // what you get with chunk
+    run_tests(options, "chunk");
   } catch (const std::exception &e) {
     std::cerr << "ERROR: " << e.what() << std::endl;
-
+    return 1;
   } catch (...) {
     std::cerr << "UNKNOWN ERROR" << std::endl;
+    return 1;
   }
 
-  return 1;
+  return 0;
 }
diff --git a/tests/test-output-multi-line-storage.cpp b/tests/test-output-multi-line-storage.cpp
index fa9d750..41541a0 100644
--- a/tests/test-output-multi-line-storage.cpp
+++ b/tests/test-output-multi-line-storage.cpp
@@ -8,10 +8,10 @@
 #include <memory>
 
 #include "osmtypes.hpp"
+#include "osmdata.hpp"
 #include "middle.hpp"
 #include "output-multi.hpp"
 #include "options.hpp"
-#include "middle-pgsql.hpp"
 #include "taginfo_impl.hpp"
 #include "parse.hpp"
 
diff --git a/tests/test-output-multi-line.cpp b/tests/test-output-multi-line.cpp
index b740a97..cf53067 100644
--- a/tests/test-output-multi-line.cpp
+++ b/tests/test-output-multi-line.cpp
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "osmtypes.hpp"
-#include "middle.hpp"
+#include "osmdata.hpp"
 #include "output-multi.hpp"
 #include "options.hpp"
 #include "middle-pgsql.hpp"
diff --git a/tests/test-output-multi-point-multi-table.cpp b/tests/test-output-multi-point-multi-table.cpp
index b904075..d35f5bb 100644
--- a/tests/test-output-multi-point-multi-table.cpp
+++ b/tests/test-output-multi-point-multi-table.cpp
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "osmtypes.hpp"
-#include "middle.hpp"
+#include "osmdata.hpp"
 #include "output-multi.hpp"
 #include "options.hpp"
 #include "middle-pgsql.hpp"
diff --git a/tests/test-output-multi-point.cpp b/tests/test-output-multi-point.cpp
index 809717d..36e102a 100644
--- a/tests/test-output-multi-point.cpp
+++ b/tests/test-output-multi-point.cpp
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "osmtypes.hpp"
-#include "middle.hpp"
+#include "osmdata.hpp"
 #include "output-multi.hpp"
 #include "options.hpp"
 #include "middle-pgsql.hpp"
diff --git a/tests/test-output-multi-poly-trivial.cpp b/tests/test-output-multi-poly-trivial.cpp
index dc609cd..611ff36 100644
--- a/tests/test-output-multi-poly-trivial.cpp
+++ b/tests/test-output-multi-poly-trivial.cpp
@@ -8,10 +8,10 @@
 #include <memory>
 
 #include "osmtypes.hpp"
+#include "osmdata.hpp"
 #include "middle.hpp"
 #include "output-multi.hpp"
 #include "options.hpp"
-#include "middle-pgsql.hpp"
 #include "taginfo_impl.hpp"
 #include "parse.hpp"
 
diff --git a/tests/test-output-multi-polygon.cpp b/tests/test-output-multi-polygon.cpp
index 067e759..38be794 100644
--- a/tests/test-output-multi-polygon.cpp
+++ b/tests/test-output-multi-polygon.cpp
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "osmtypes.hpp"
-#include "middle.hpp"
+#include "osmdata.hpp"
 #include "output-multi.hpp"
 #include "options.hpp"
 #include "middle-pgsql.hpp"
diff --git a/tests/test-output-multi-tags.cpp b/tests/test-output-multi-tags.cpp
index af9221b..00b6d4e 100644
--- a/tests/test-output-multi-tags.cpp
+++ b/tests/test-output-multi-tags.cpp
@@ -11,7 +11,7 @@
 #include "middle.hpp"
 #include "output-multi.hpp"
 #include "options.hpp"
-#include "middle-pgsql.hpp"
+#include "osmdata.hpp"
 #include "taginfo_impl.hpp"
 #include "parse.hpp"
 
diff --git a/tests/test-output-pgsql.cpp b/tests/test-output-pgsql.cpp
index 1ef7eba..42f490a 100644
--- a/tests/test-output-pgsql.cpp
+++ b/tests/test-output-pgsql.cpp
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "osmtypes.hpp"
-#include "middle.hpp"
+#include "osmdata.hpp"
 #include "output-pgsql.hpp"
 #include "options.hpp"
 #include "middle-pgsql.hpp"
@@ -264,7 +264,7 @@ void test_clone() {
     options.slim = 1;
     options.style = "default.style";
 
-    struct output_pgsql_t out_test(mid_pgsql.get(), options);
+    output_pgsql_t out_test(mid_pgsql.get(), options);
 
     //TODO: make the middle testable too
     //boost::shared_ptr<middle_t> mid_clone = mid_pgsql->get_instance();
diff --git a/tests/test-parse-options.cpp b/tests/test-parse-options.cpp
index bfe910a..2efb23e 100644
--- a/tests/test-parse-options.cpp
+++ b/tests/test-parse-options.cpp
@@ -138,7 +138,6 @@ int get_random_proj(std::vector<std::string>& args)
     switch(proj)
     {
     case PROJ_LATLONG:
-    case PROJ_MERC:
     case PROJ_SPHERE_MERC:
         args.push_back(reprojection(proj).project_getprojinfo()->option);
         break;
diff --git a/tests/test-parse-xml2.cpp b/tests/test-parse-xml2.cpp
index 00b38af..e18f2d8 100644
--- a/tests/test-parse-xml2.cpp
+++ b/tests/test-parse-xml2.cpp
@@ -7,6 +7,7 @@
 #include <boost/make_shared.hpp>
 
 #include "osmtypes.hpp"
+#include "osmdata.hpp"
 #include "parse-xml2.hpp"
 #include "output.hpp"
 #include "options.hpp"
diff --git a/util.hpp b/util.hpp
index 06d570f..1c1f54b 100644
--- a/util.hpp
+++ b/util.hpp
@@ -2,12 +2,7 @@
 #define UTIL_H
 
 namespace util {
-	inline int double_to_fix(const double x, const int scale) {
-		return x * scale + 0.4;
-	}
-	inline double fix_to_double(const int x, const int scale) {
-		return (double)x / scale;
-	}
+
 	void exit_nicely();
 }
 

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



More information about the Pkg-grass-devel mailing list