diff --git a/.gitignore b/.gitignore index 28677dcf8..a4cd9b6e5 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ tests/test-output-multi-polygon tests/test-output-multi-poly-trivial tests/test-output-pgsql tests/test-output-pgsql-tablespace +tests/test-output-pgsql-z_order tests/test-expire-tiles tests/*.log tests/*.trs diff --git a/Makefile.am b/Makefile.am index cd80ce8a2..c91d408b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,6 +59,7 @@ check_PROGRAMS = \ tests/test-output-multi-polygon \ tests/test-output-multi-poly-trivial \ tests/test-output-pgsql \ + tests/test-output-pgsql-z_order \ tests/test-output-pgsql-tablespace \ tests/test-pgsql-escape \ tests/test-parse-options \ @@ -90,6 +91,8 @@ tests_test_output_pgsql_SOURCES = tests/test-output-pgsql.cpp tests/common-pg.cp tests_test_output_pgsql_LDADD = libosm2pgsql.la tests_test_output_pgsql_tablespace_SOURCES = tests/test-output-pgsql-tablespace.cpp tests/common-pg.cpp tests_test_output_pgsql_tablespace_LDADD = libosm2pgsql.la +tests_test_output_pgsql_z_order_SOURCES = tests/test-output-pgsql-z_order.cpp tests/common-pg.cpp +tests_test_output_pgsql_z_order_LDADD = libosm2pgsql.la tests_test_pgsql_escape_SOURCES = tests/test-pgsql-escape.cpp tests_test_pgsql_escape_LDADD = libosm2pgsql.la tests_test_parse_options_SOURCES = tests/test-parse-options.cpp @@ -155,6 +158,7 @@ tests_test_output_multi_polygon_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_multi_poly_trivial_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_pgsql_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_pgsql_tablespace_LDADD += $(GLOBAL_LDFLAGS) +tests_test_output_pgsql_z_order_LDADD += $(GLOBAL_LDFLAGS) tests_test_pgsql_escape_LDADD += $(GLOBAL_LDFLAGS) tests_test_parse_options_LDADD += $(GLOBAL_LDFLAGS) tests_test_expire_tiles_LDADD += $(GLOBAL_LDFLAGS) diff --git a/docs/migrations.md b/docs/migrations.md index 10457c83a..87fd87f68 100644 --- a/docs/migrations.md +++ b/docs/migrations.md @@ -4,6 +4,15 @@ Some osm2pgsql changes have slightly changed the database schema it expects. If updating an old database, a migration may be needed. The migrations here assume the default `planet_osm` prefix. +## 0.87.5-dev z_order changes ## + +0.87.5-dev z_order code was changed. To migrate to the new z_order numbering run + +```sql +UPDATE planet_osm_line SET z_order = z_order * 10; +UPDATE planet_osm_roads SET z_order = z_order * 10; +``` + ## 0.87.0 pending removal ## 0.87.0 moved the in-database tracking of pending ways and relations to diff --git a/tagtransform.cpp b/tagtransform.cpp index 572cc0e4e..7b806d354 100644 --- a/tagtransform.cpp +++ b/tagtransform.cpp @@ -25,20 +25,31 @@ static const struct { const char *highway; int roads; } layers[] = { - { 3, "minor", 0 }, - { 3, "road", 0 }, - { 3, "unclassified", 0 }, - { 3, "residential", 0 }, - { 4, "tertiary_link", 0 }, - { 4, "tertiary", 0 }, - { 6, "secondary_link",1 }, - { 6, "secondary", 1 }, - { 7, "primary_link", 1 }, - { 7, "primary", 1 }, - { 8, "trunk_link", 1 }, - { 8, "trunk", 1 }, - { 9, "motorway_link", 1 }, - { 9, "motorway", 1 } + { 10, "steps", 0 }, + { 10, "cycleway", 0 }, + { 10, "bridleway", 0 }, + { 10, "footway", 0 }, + { 10, "path", 0 }, + { 11, "track", 0 }, + { 15, "service", 0 }, + + { 24, "tertiary_link", 0 }, + { 25, "secondary_link",1 }, + { 27, "primary_link", 1 }, + { 28, "trunk_link", 1 }, + { 29, "motorway_link", 1 }, + + { 30, "raceway", 0 }, + { 31, "pedestrian", 0 }, + { 32, "living_street", 0 }, + { 33, "road", 0 }, + { 33, "unclassified", 0 }, + { 33, "residential", 0 }, + { 34, "tertiary", 0 }, + { 36, "secondary", 1 }, + { 37, "primary", 1 }, + { 38, "trunk", 1 }, + { 39, "motorway", 1 } }; static const unsigned int nLayers = (sizeof(layers)/sizeof(*layers)); @@ -56,12 +67,11 @@ void add_z_order(taglist_t &tags, int *roads) int z_order = 0; int l = layer ? strtol(layer->c_str(), NULL, 10) : 0; - z_order = 10 * l; + z_order = 100 * l; *roads = 0; if (highway) { for (unsigned i = 0; i < nLayers; i++) { - //if (layers[i].highway == *highway) { if (!strcmp(layers[i].highway, highway->c_str())) { z_order += layers[i].offset; *roads = layers[i].roads; @@ -71,7 +81,7 @@ void add_z_order(taglist_t &tags, int *roads) } if (railway && !railway->empty()) { - z_order += 5; + z_order += 35; *roads = 1; } /* Administrative boundaries are rendered at low zooms so we prefer to use the roads table */ @@ -79,10 +89,10 @@ void add_z_order(taglist_t &tags, int *roads) *roads = 1; if (bridge) - z_order += 10; + z_order += 100; if (tunnel) - z_order -= 10; + z_order -= 100; char z[13]; snprintf(z, sizeof(z), "%d", z_order); diff --git a/tests/test-output-pgsql-z_order.cpp b/tests/test-output-pgsql-z_order.cpp new file mode 100644 index 000000000..c940f4422 --- /dev/null +++ b/tests/test-output-pgsql-z_order.cpp @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "osmtypes.hpp" +#include "osmdata.hpp" +#include "output-pgsql.hpp" +#include "options.hpp" +#include "middle-pgsql.hpp" +#include "middle-ram.hpp" +#include "taginfo_impl.hpp" +#include "parse.hpp" + +#include +#include +#include + +#include +#include + +#include "tests/middle-tests.hpp" +#include "tests/common-pg.hpp" + +namespace { + +struct skip_test : public std::exception { + const char *what() { return "Test skipped."; } +}; + +void run_test(const char* test_name, void (*testfunc)()) { + try { + fprintf(stderr, "%s\n", test_name); + testfunc(); + + } catch (const skip_test &) { + exit(77); // <-- code to skip this test. + + } catch (const std::exception& e) { + fprintf(stderr, "%s\n", e.what()); + fprintf(stderr, "FAIL\n"); + exit(EXIT_FAILURE); + } + + fprintf(stderr, "PASS\n"); +} +#define RUN_TEST(x) run_test(#x, &(x)) + +void check_string(pg::conn_ptr &conn, std::string expected, const std::string &query) { + pg::result_ptr res = conn->exec(query); + + int ntuples = PQntuples(res->get()); + if (ntuples != 1) { + throw std::runtime_error((boost::format("Expected only one tuple from a query " + "to check a string, but got %1%. Query " + "was: %2%.") + % ntuples % query).str()); + } + + std::string actual = PQgetvalue(res->get(), 0, 0); + + if (actual != expected) { + throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running " + "query: %3%.") + % expected % actual % query).str()); + } +} + + +void check_count(pg::conn_ptr &conn, int expected, const std::string &query) { + pg::result_ptr res = conn->exec(query); + + int ntuples = PQntuples(res->get()); + if (ntuples != 1) { + throw std::runtime_error((boost::format("Expected only one tuple from a query " + "to check COUNT(*), but got %1%. Query " + "was: %2%.") + % ntuples % query).str()); + } + + std::string numstr = PQgetvalue(res->get(), 0, 0); + int count = boost::lexical_cast(numstr); + + if (count != expected) { + throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running " + "query: %3%.") + % expected % count % query).str()); + } +} + +void check_number(pg::conn_ptr &conn, double expected, const std::string &query) { + pg::result_ptr res = conn->exec(query); + + int ntuples = PQntuples(res->get()); + if (ntuples != 1) { + throw std::runtime_error((boost::format("Expected only one tuple from a query, " + " but got %1%. Query was: %2%.") + % ntuples % query).str()); + } + + std::string numstr = PQgetvalue(res->get(), 0, 0); + double num = boost::lexical_cast(numstr); + + // floating point isn't exact, so allow a 0.01% difference + if ((num > 1.0001*expected) || (num < 0.9999*expected)) { + throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running " + "query: %3%.") + % expected % num % query).str()); + } +} + +void assert_has_table(pg::conn_ptr &test_conn, const std::string &table_name) { + std::string query = (boost::format("select count(*) from pg_catalog.pg_class " + "where relname = '%1%'") + % table_name).str(); + + check_count(test_conn, 1, query); +} + +// "simple" test modeled on the basic regression test from +// the python script. this is just to check everything is +// working as expected before we start the complex stuff. +void test_z_order() { + boost::scoped_ptr db; + + try { + db.reset(new pg::tempdb); + } catch (const std::exception &e) { + std::cerr << "Unable to setup database: " << e.what() << "\n"; + throw skip_test(); + } + + std::string proc_name("test-output-pgsql"), input_file("-"); + char *argv[] = { &proc_name[0], &input_file[0], NULL }; + + boost::shared_ptr mid_pgsql(new middle_pgsql_t()); + options_t options = options_t::parse(2, argv); + options.conninfo = db->conninfo().c_str(); + options.num_procs = 1; + options.prefix = "osm2pgsql_test"; + options.style = "default.style"; + + boost::shared_ptr out_test(new output_pgsql_t(mid_pgsql.get(), options)); + + osmdata_t osmdata(mid_pgsql, out_test); + + boost::scoped_ptr parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection)); + + osmdata.start(); + + if (parser->streamFile("libxml2", "tests/test_output_pgsql_z_order.osm", options.sanitize, &osmdata) != 0) { + throw std::runtime_error("Unable to read input file `tests/test_output_pgsql_z_order.osm'."); + } + + parser.reset(NULL); + + osmdata.stop(); + + // start a new connection to run tests on + pg::conn_ptr test_conn = pg::conn::connect(db->conninfo()); + + assert_has_table(test_conn, "osm2pgsql_test_point"); + assert_has_table(test_conn, "osm2pgsql_test_line"); + assert_has_table(test_conn, "osm2pgsql_test_polygon"); + assert_has_table(test_conn, "osm2pgsql_test_roads"); + + check_string(test_conn, "motorway", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 0"); + check_string(test_conn, "trunk", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 1"); + check_string(test_conn, "primary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 2"); + check_string(test_conn, "secondary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 3"); + check_string(test_conn, "tertiary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 4"); + + check_string(test_conn, "residential", "SELECT highway FROM osm2pgsql_test_line ORDER BY z_order DESC LIMIT 1 OFFSET 0"); +} + +} // anonymous namespace + +int main(int argc, char *argv[]) { + RUN_TEST(test_z_order); + + return 0; +} diff --git a/tests/test_output_pgsql_z_order.osm b/tests/test_output_pgsql_z_order.osm new file mode 100644 index 000000000..76ddd9a92 --- /dev/null +++ b/tests/test_output_pgsql_z_order.osm @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +