From b123d6011448764fd5004bdea17c074f814faea8 Mon Sep 17 00:00:00 2001 From: Frederik Ramm Date: Sat, 3 Oct 2015 01:44:37 +0200 Subject: [PATCH 1/8] Add area reprojection facility --- Makefile.am | 6 +- geometry-builder.cpp | 86 ++++++++++++++++++++--- geometry-builder.hpp | 8 +++ options.cpp | 7 +- options.hpp | 1 + output-pgsql.cpp | 2 + reprojection.cpp | 38 +++++++++++ reprojection.hpp | 1 + tests/area-reprojection.osm | 27 ++++++++ tests/test-area-reprojection.cpp | 114 +++++++++++++++++++++++++++++++ 10 files changed, 278 insertions(+), 12 deletions(-) create mode 100644 tests/area-reprojection.osm create mode 100644 tests/test-area-reprojection.cpp diff --git a/Makefile.am b/Makefile.am index 6b26e4558..708aca5f2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -63,7 +63,8 @@ check_PROGRAMS = \ tests/test-options-parse \ tests/test-options-database \ tests/test-expire-tiles \ - tests/test-hstore-match-only + tests/test-hstore-match-only \ + tests/test-area-reprojection tests_test_parse_xml2_SOURCES = tests/test-parse-xml2.cpp tests_test_parse_xml2_LDADD = libosm2pgsql.la @@ -105,6 +106,8 @@ tests_test_options_database_SOURCES = tests/test-options-database.cpp tests_test_options_database_LDADD = libosm2pgsql.la tests_test_expire_tiles_SOURCES = tests/test-expire-tiles.cpp tests_test_expire_tiles_LDADD = libosm2pgsql.la +tests_test_area_reprojection_SOURCES = tests/test-area-reprojection.cpp tests/common-pg.cpp +tests_test_area_reprojection_LDADD = libosm2pgsql.la MOSTLYCLEANFILES = tests/test_middle_flat.flat.nodes.bin tests/test_output_pgsql_area_way.flat.nodes.bin @@ -154,6 +157,7 @@ tests_test_output_multi_point_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_multi_point_multi_table_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_multi_polygon_LDADD += $(GLOBAL_LDFLAGS) tests_test_hstore_match_only_LDADD += $(GLOBAL_LDFLAGS) +tests_test_area_reprojection_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) diff --git a/geometry-builder.cpp b/geometry-builder.cpp index f5f661e29..7064f17f7 100644 --- a/geometry-builder.cpp +++ b/geometry-builder.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -112,7 +111,7 @@ geometry_builder::maybe_wkt_t geometry_builder::get_wkt_simple(const nodelist_t } } geom->normalize(); // Fix direction of ring - wkt->area = geom->getArea(); + wkt->area = getArea(geom.get()); } else { if (coords->getSize() < 2) throw std::runtime_error("Excluding degenerate line."); @@ -171,7 +170,7 @@ geometry_builder::maybe_wkts_t geometry_builder::get_wkt_split(const nodelist_t wkts->push_back(geometry_builder::wkt_t()); //then we set on the one we already have wkts->back().geom = writer.write(geom.get()); - wkts->back().area = geom->getArea(); + wkts->back().area = getArea(geom.get()); } else { if (coords->getSize() < 2) @@ -355,7 +354,7 @@ geometry_builder::maybe_wkts_t geometry_builder::build_polygons(const multinodel { polys[totalpolys].polygon = gf.createPolygon(gf.createLinearRing(pline->getCoordinates()),0); polys[totalpolys].ring = gf.createLinearRing(pline->getCoordinates()); - polys[totalpolys].area = polys[totalpolys].polygon->getArea(); + polys[totalpolys].area = getArea(polys[totalpolys].polygon); polys[totalpolys].iscontained = 0; polys[totalpolys].containedbyid = 0; if (polys[totalpolys].area > 0.0) @@ -445,7 +444,7 @@ geometry_builder::maybe_wkts_t geometry_builder::build_polygons(const multinodel wkts->push_back(geometry_builder::wkt_t()); //then we set on the one we already have wkts->back().geom = writer.write(multipoly.get()); - wkts->back().area = multipoly->getArea(); + wkts->back().area = getArea(multipoly.get()); } } else @@ -463,7 +462,7 @@ geometry_builder::maybe_wkts_t geometry_builder::build_polygons(const multinodel wkts->push_back(geometry_builder::wkt_t()); //then we set on the one we already have wkts->back().geom = writer.write(poly); - wkts->back().area = poly->getArea(); + wkts->back().area = getArea(poly); } delete(poly); } @@ -577,7 +576,7 @@ geometry_builder::maybe_wkts_t geometry_builder::build_both(const multinodelist_ { polys[totalpolys].polygon = gf.createPolygon(gf.createLinearRing(pline->getCoordinates()),0); polys[totalpolys].ring = gf.createLinearRing(pline->getCoordinates()); - polys[totalpolys].area = polys[totalpolys].polygon->getArea(); + polys[totalpolys].area = getArea(polys[totalpolys].polygon); polys[totalpolys].iscontained = 0; polys[totalpolys].containedbyid = 0; if (polys[totalpolys].area > 0.0) @@ -713,7 +712,7 @@ geometry_builder::maybe_wkts_t geometry_builder::build_both(const multinodelist_ wkts->push_back(geometry_builder::wkt_t()); //then we set on the one we already have wkts->back().geom = writer.write(multipoly.get()); - wkts->back().area = multipoly->getArea(); + wkts->back().area = getArea(multipoly.get()); } } else @@ -731,7 +730,7 @@ geometry_builder::maybe_wkts_t geometry_builder::build_both(const multinodelist_ wkts->push_back(geometry_builder::wkt_t()); //then we set on the one we already have wkts->back().geom = writer.write(poly); - wkts->back().area = poly->getArea(); + wkts->back().area = getArea(poly); } delete(poly); } @@ -760,8 +759,75 @@ void geometry_builder::set_exclude_broken_polygon(int exclude) excludepoly = exclude; } +void geometry_builder::set_reprojection(struct reprojection *r) +{ + reprojection = r; +} + +/** + * Computes area of given polygonal geometry. + * Returns + * - the standard GEOS getArea result if area reprojection has not been enabled + * - the GEOS getArea resolt of this geometry projected to EPSG:3857 if reprojection has been enabled + */ +double geometry_builder::getArea(const geos::geom::Geometry *geom) const +{ + // reprojection is not necessary, or has not been asked for. + if (!reprojection) + { + return geom->getArea(); + } + + // MultiPolygon - return sum of individual areas + if (const geos::geom::MultiPolygon* multi = dynamic_cast(geom)) + { + double area = 0.0; + for (std::size_t i=0; igetNumGeometries(); i++) + { + area += getArea(multi->getGeometryN(i)); + } + return area; + } + + const geos::geom::Polygon *poly = dynamic_cast(geom); + if (!poly) return 0.0; + + // standard polygon - reproject, then compute area of outer - areas of holes + + const geos::geom::LineString* ext = poly->getExteriorRing(); + geos::geom::LinearRing* projectedExt = reproject_linearring(ext); + std::size_t nholes = poly->getNumInteriorRing(); + std::vector *projectedHoles = new std::vector(nholes); + for (std::size_t i=0; i< poly->getNumInteriorRing(); i++) + { + const geos::geom::LineString* hole = poly->getInteriorRingN(i); + (*projectedHoles)[i] = reproject_linearring(hole); + } + const geos::geom::Polygon *projectedPoly = poly->getFactory()->createPolygon(projectedExt, projectedHoles); + + double area = projectedPoly->getArea(); + delete projectedPoly; + return area; +} + +/** + * Reprojects given Linear Ring from target projection to spherical mercator. + * Caller takes ownership of return value. + */ +geos::geom::LinearRing* geometry_builder::reproject_linearring(const geos::geom::LineString *ls) const +{ + std::vector *projectedCoords = new std::vector(); + for(auto i: *(ls->getCoordinatesRO()->toVector())) + { + Coordinate c(i.x, i.y); + reprojection->target_to_tile(&c.y, &c.x); + projectedCoords->push_back(c); + } + return ls->getFactory()->createLinearRing(ls->getFactory()->getCoordinateSequenceFactory()->create(projectedCoords)); +} + geometry_builder::geometry_builder() - : excludepoly(false) { + : excludepoly(false), reprojection(nullptr) { } geometry_builder::~geometry_builder() { diff --git a/geometry-builder.hpp b/geometry-builder.hpp index b7def6691..eac539030 100644 --- a/geometry-builder.hpp +++ b/geometry-builder.hpp @@ -24,11 +24,14 @@ #define GEOMETRY_BUILDER_H #include "osmtypes.hpp" +#include "reprojection.hpp" #include #include #include #include +#include +#include struct geometry_builder : public boost::noncopyable { @@ -57,9 +60,14 @@ struct geometry_builder : public boost::noncopyable maybe_wkt_t build_multilines(const multinodelist_t &xnodes, osmid_t osm_id) const; void set_exclude_broken_polygon(int exclude); + void set_reprojection(struct reprojection *r); + double getArea(const geos::geom::Geometry *geom) const; private: bool excludepoly; + struct reprojection *reprojection; + geos::geom::LinearRing* reproject_linearring(const geos::geom::LineString *ls) const; + }; #endif diff --git a/options.cpp b/options.cpp index 0c9691d5d..ffb35e97d 100644 --- a/options.cpp +++ b/options.cpp @@ -63,6 +63,7 @@ namespace {"flat-nodes",1,0,209}, {"exclude-invalid-polygon",0,0,210}, {"tag-transform-script",1,0,212}, + {"reproject-area",0,0,213}, {0, 0, 0, 0} }; @@ -202,6 +203,7 @@ namespace By default natural=coastline tagged data will be discarded\n\ because renderers usually have shape files for them.\n\ --exclude-invalid-polygon do not import polygons with invalid geometries.\n\ + --reproject-area compute area column using spherical mercator coordinates.\n\ -h|--help Help information.\n\ -v|--verbose Verbose output.\n"); } @@ -268,7 +270,7 @@ options_t::options_t(): #else alloc_chunkwise(ALLOC_SPARSE), #endif - droptemp(false), unlogged(false), hstore_match_only(false), flat_node_cache_enabled(false), excludepoly(false), flat_node_file(boost::none), + droptemp(false), unlogged(false), hstore_match_only(false), flat_node_cache_enabled(false), excludepoly(false), reproject_area(false), flat_node_file(boost::none), tag_transform_script(boost::none), tag_transform_node_func(boost::none), tag_transform_way_func(boost::none), tag_transform_rel_func(boost::none), tag_transform_rel_mem_func(boost::none), create(false), long_usage_bool(false), pass_prompt(false), output_backend("pgsql"), input_reader("auto"), bbox(boost::none), @@ -456,6 +458,9 @@ options_t::options_t(int argc, char *argv[]): options_t() case 212: tag_transform_script = optarg; break; + case 213: + reproject_area = true; + break; case 'V': exit (EXIT_SUCCESS); break; diff --git a/options.hpp b/options.hpp index df0fd3800..f4e2fc304 100644 --- a/options.hpp +++ b/options.hpp @@ -75,6 +75,7 @@ struct options_t { bool hstore_match_only; ///< only copy rows that match an explicitly listed key bool flat_node_cache_enabled; bool excludepoly; + bool reproject_area; boost::optional flat_node_file; /** * these options allow you to control the name of the diff --git a/output-pgsql.cpp b/output-pgsql.cpp index 8346eeddf..b6b5d324c 100644 --- a/output-pgsql.cpp +++ b/output-pgsql.cpp @@ -678,6 +678,7 @@ output_pgsql_t::output_pgsql_t(const middle_query_t* mid_, const options_t &opti reproj = m_options.projection; builder.set_exclude_broken_polygon(m_options.excludepoly); + if (m_options.reproject_area) builder.set_reprojection(reproj.get()); m_export_list.reset(new export_list()); @@ -747,6 +748,7 @@ output_pgsql_t::output_pgsql_t(const output_pgsql_t& other): ways_pending_tracker(new id_tracker()), ways_done_tracker(new id_tracker()), rels_pending_tracker(new id_tracker()) { builder.set_exclude_broken_polygon(m_options.excludepoly); + if (m_options.reproject_area) builder.set_reprojection(reproj.get()); for(std::vector >::const_iterator t = other.m_tables.begin(); t != other.m_tables.end(); ++t) { //copy constructor will just connect to the already there table m_tables.push_back(std::shared_ptr(new table_t(**t))); diff --git a/reprojection.cpp b/reprojection.cpp index fac420213..ec688822c 100644 --- a/reprojection.cpp +++ b/reprojection.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -162,6 +164,42 @@ void reprojection::reproject(double *lat, double *lon) const *lon = x[0]; } +void reprojection::target_to_tile(double *lat, double *lon) const +{ + double x[1], y[1], z[1]; + + if (Proj == PROJ_SPHERE_MERC) + return; + + if (Proj == PROJ_LATLONG) + { + if (*lat > 85.07) + *lat = 85.07; + if (*lat < -85.07) + *lat = -85.07; + + //std::cout << "builtin=" << Proj << ": " << *lon ; + *lon = (*lon) * EARTH_CIRCUMFERENCE / 360.0; + *lat = log(tan(M_PI/4.0 + (*lat) * DEG_TO_RAD / 2.0)) * EARTH_CIRCUMFERENCE/(M_PI*2); + //std::cout << " => " << *lon << std::endl; + return; + } + + x[0] = *lon; + y[0] = *lat; + z[0] = 0; + + /** end of "caution" section. */ + + pj_transform(pj_target, pj_tile, 1, 1, x, y, z); + + //std::cout << "proj=" << Proj << ": " << *lon << " => " << x[0] << std::endl; + + *lat = y[0]; + *lon = x[0]; + +} + /** * Converts from (target) coordinates to tile coordinates. * diff --git a/reprojection.hpp b/reprojection.hpp index 945b72cfb..c0d9c08a9 100644 --- a/reprojection.hpp +++ b/reprojection.hpp @@ -28,6 +28,7 @@ struct reprojection : public boost::noncopyable struct Projection_Info const* project_getprojinfo(void); void reproject(double *lat, double *lon) const; + void target_to_tile(double *lat, double *lon) const; void coords_to_tile(double *tilex, double *tiley, double lon, double lat, int map_width); int get_proj_id() const; diff --git a/tests/area-reprojection.osm b/tests/area-reprojection.osm new file mode 100644 index 000000000..d5a5a2a53 --- /dev/null +++ b/tests/area-reprojection.osm @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test-area-reprojection.cpp b/tests/test-area-reprojection.cpp new file mode 100644 index 000000000..e0496eb33 --- /dev/null +++ b/tests/test-area-reprojection.cpp @@ -0,0 +1,114 @@ +/* + +Test the area reprojection functionality of osm2pgsql + +The idea behind that functionality is to populate the way_area +column with the area that a polygoun would have in EPSG:3857, +rather than the area it actually has in the coordinate system +used for importing. + +This goes with a test data file named area-reprojection.osm + +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "osmtypes.hpp" +#include "osmdata.hpp" +#include "middle.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 "tests/common-pg.hpp" + +void run_test(const char* test_name, void (*testfunc)()) { + try { + fprintf(stderr, "%s\n", test_name); + testfunc(); + + } 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 test_area_base(bool latlon, bool reproj, double expect_area) { + std::unique_ptr db; + + try { + db.reset(new pg::tempdb); + } catch (const std::exception &e) { + std::cerr << "Unable to setup database: " << e.what() << "\n"; + exit(77); + } + + std::shared_ptr mid_pgsql(new middle_pgsql_t()); + options_t options; + options.database_options = db->database_options; + options.num_procs = 1; + options.style = "default.style"; + options.prefix = "osm2pgsql_test"; + if (latlon) options.projection.reset(new reprojection(PROJ_LATLONG)); + if (reproj) options.reproject_area = true; + options.scale = latlon ? 10000000 : 100; + + auto out_test = std::make_shared(mid_pgsql.get(), options); + + osmdata_t osmdata(mid_pgsql, out_test); + + std::unique_ptr parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection, false)); + + osmdata.start(); + + parser->stream_file("libxml2", "tests/area-reprojection.osm", &osmdata); + + parser.reset(nullptr); + + osmdata.stop(); + + // tables should not contain any tag columns + db->check_count(1, "select count(*) from osm2pgsql_test_polygon"); + db->check_number(expect_area, "SELECT way_area FROM osm2pgsql_test_polygon"); + + return; +} + +void test_area_classic() { + test_area_base(false, false, 6.66e+10); +} + +void test_area_latlon() { + test_area_base(true, false, 6.66e-1); +} + +void test_area_latlon_with_reprojection() { + test_area_base(true, true, 6.66e+10); +} + +int main(int argc, char *argv[]) { + RUN_TEST(test_area_latlon); + RUN_TEST(test_area_classic); + RUN_TEST(test_area_latlon_with_reprojection); + return 0; +} + From bb08d8f8e3bfbdeffdaaaceab5b28af401b02c7d Mon Sep 17 00:00:00 2001 From: Frederik Ramm Date: Sat, 3 Oct 2015 21:06:41 +0200 Subject: [PATCH 2/8] cosmetic fixes --- geometry-builder.cpp | 7 +++++-- reprojection.cpp | 10 ++++++---- tests/area-reprojection.osm | 22 +++++++++++----------- tests/test-area-reprojection.cpp | 9 ++++++--- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/geometry-builder.cpp b/geometry-builder.cpp index 7064f17f7..11a8e98d9 100644 --- a/geometry-builder.cpp +++ b/geometry-builder.cpp @@ -790,9 +790,12 @@ double geometry_builder::getArea(const geos::geom::Geometry *geom) const } const geos::geom::Polygon *poly = dynamic_cast(geom); - if (!poly) return 0.0; + if (!poly) { + return 0.0; + } - // standard polygon - reproject, then compute area of outer - areas of holes + // standard polygon - reproject rings individually, then assemble polygon and + // compute area. const geos::geom::LineString* ext = poly->getExteriorRing(); geos::geom::LinearRing* projectedExt = reproject_linearring(ext); diff --git a/reprojection.cpp b/reprojection.cpp index ec688822c..4de979897 100644 --- a/reprojection.cpp +++ b/reprojection.cpp @@ -9,8 +9,6 @@ #include #include -#include -#include #include #include #include @@ -164,6 +162,12 @@ void reprojection::reproject(double *lat, double *lon) const *lon = x[0]; } +/** + * Converts from (target) coordinates to coordinates in the tile projection (EPSG:3857) + * + * Do not confuse with coords_to_tile which does *not* calculate coordinates in the + * tile projection, but tile coordinates. + */ void reprojection::target_to_tile(double *lat, double *lon) const { double x[1], y[1], z[1]; @@ -178,10 +182,8 @@ void reprojection::target_to_tile(double *lat, double *lon) const if (*lat < -85.07) *lat = -85.07; - //std::cout << "builtin=" << Proj << ": " << *lon ; *lon = (*lon) * EARTH_CIRCUMFERENCE / 360.0; *lat = log(tan(M_PI/4.0 + (*lat) * DEG_TO_RAD / 2.0)) * EARTH_CIRCUMFERENCE/(M_PI*2); - //std::cout << " => " << *lon << std::endl; return; } diff --git a/tests/area-reprojection.osm b/tests/area-reprojection.osm index d5a5a2a53..0c98a0982 100644 --- a/tests/area-reprojection.osm +++ b/tests/area-reprojection.osm @@ -1,16 +1,16 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/tests/test-area-reprojection.cpp b/tests/test-area-reprojection.cpp index e0496eb33..4a64dae86 100644 --- a/tests/test-area-reprojection.cpp +++ b/tests/test-area-reprojection.cpp @@ -68,8 +68,12 @@ void test_area_base(bool latlon, bool reproj, double expect_area) { options.num_procs = 1; options.style = "default.style"; options.prefix = "osm2pgsql_test"; - if (latlon) options.projection.reset(new reprojection(PROJ_LATLONG)); - if (reproj) options.reproject_area = true; + if (latlon) { + options.projection.reset(new reprojection(PROJ_LATLONG)); + } + if (reproj) { + options.reproject_area = true; + } options.scale = latlon ? 10000000 : 100; auto out_test = std::make_shared(mid_pgsql.get(), options); @@ -111,4 +115,3 @@ int main(int argc, char *argv[]) { RUN_TEST(test_area_latlon_with_reprojection); return 0; } - From 28898b6e2edbd20863e272f4dd950abe8600a937 Mon Sep 17 00:00:00 2001 From: Paul Norman Date: Thu, 8 Oct 2015 15:15:33 -0700 Subject: [PATCH 3/8] Fix Doxygen formatting, whitespace errors --- geometry-builder.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/geometry-builder.cpp b/geometry-builder.cpp index 11a8e98d9..c96b3d523 100644 --- a/geometry-builder.cpp +++ b/geometry-builder.cpp @@ -764,11 +764,9 @@ void geometry_builder::set_reprojection(struct reprojection *r) reprojection = r; } -/** +/** * Computes area of given polygonal geometry. - * Returns - * - the standard GEOS getArea result if area reprojection has not been enabled - * - the GEOS getArea resolt of this geometry projected to EPSG:3857 if reprojection has been enabled + * \return the area in projected units, or in EPSG 3857 if area reprojection is enabled */ double geometry_builder::getArea(const geos::geom::Geometry *geom) const { @@ -807,9 +805,9 @@ double geometry_builder::getArea(const geos::geom::Geometry *geom) const (*projectedHoles)[i] = reproject_linearring(hole); } const geos::geom::Polygon *projectedPoly = poly->getFactory()->createPolygon(projectedExt, projectedHoles); - + double area = projectedPoly->getArea(); - delete projectedPoly; + delete projectedPoly; return area; } From 52e1be60603f91ff7b8d9612ba120d3b86065624 Mon Sep 17 00:00:00 2001 From: Paul Norman Date: Thu, 8 Oct 2015 15:32:51 -0700 Subject: [PATCH 4/8] Fix reprojection area code to follow code format standards --- geometry-builder.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/geometry-builder.cpp b/geometry-builder.cpp index c96b3d523..1b9a8112f 100644 --- a/geometry-builder.cpp +++ b/geometry-builder.cpp @@ -771,17 +771,14 @@ void geometry_builder::set_reprojection(struct reprojection *r) double geometry_builder::getArea(const geos::geom::Geometry *geom) const { // reprojection is not necessary, or has not been asked for. - if (!reprojection) - { + if (!reprojection) { return geom->getArea(); } // MultiPolygon - return sum of individual areas - if (const geos::geom::MultiPolygon* multi = dynamic_cast(geom)) - { + if (const geos::geom::MultiPolygon* multi = dynamic_cast(geom)) { double area = 0.0; - for (std::size_t i=0; igetNumGeometries(); i++) - { + for (std::size_t i=0; igetNumGeometries(); i++) { area += getArea(multi->getGeometryN(i)); } return area; @@ -799,8 +796,7 @@ double geometry_builder::getArea(const geos::geom::Geometry *geom) const geos::geom::LinearRing* projectedExt = reproject_linearring(ext); std::size_t nholes = poly->getNumInteriorRing(); std::vector *projectedHoles = new std::vector(nholes); - for (std::size_t i=0; i< poly->getNumInteriorRing(); i++) - { + for (std::size_t i=0; i< poly->getNumInteriorRing(); i++) { const geos::geom::LineString* hole = poly->getInteriorRingN(i); (*projectedHoles)[i] = reproject_linearring(hole); } @@ -818,8 +814,7 @@ double geometry_builder::getArea(const geos::geom::Geometry *geom) const geos::geom::LinearRing* geometry_builder::reproject_linearring(const geos::geom::LineString *ls) const { std::vector *projectedCoords = new std::vector(); - for(auto i: *(ls->getCoordinatesRO()->toVector())) - { + for (auto i: *(ls->getCoordinatesRO()->toVector())) { Coordinate c(i.x, i.y); reprojection->target_to_tile(&c.y, &c.x); projectedCoords->push_back(c); From e046c24013def3645b0d86364230cfc78586df30 Mon Sep 17 00:00:00 2001 From: Paul Norman Date: Thu, 8 Oct 2015 15:33:35 -0700 Subject: [PATCH 5/8] Remove commented debugging statement --- reprojection.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/reprojection.cpp b/reprojection.cpp index 4de979897..9b929eb2c 100644 --- a/reprojection.cpp +++ b/reprojection.cpp @@ -195,11 +195,8 @@ void reprojection::target_to_tile(double *lat, double *lon) const pj_transform(pj_target, pj_tile, 1, 1, x, y, z); - //std::cout << "proj=" << Proj << ": " << *lon << " => " << x[0] << std::endl; - *lat = y[0]; *lon = x[0]; - } /** From b49bbdb80ffe7e9c71d67de505ba7938f30532d4 Mon Sep 17 00:00:00 2001 From: Paul Norman Date: Tue, 20 Oct 2015 19:23:08 -0700 Subject: [PATCH 6/8] Rename area tests to be more consistent with others --- .gitignore | 1 + Makefile.am | 8 ++++---- ...t-area-reprojection.cpp => test-output-pgsql-area.cpp} | 6 ++---- .../{area-reprojection.osm => test_output_pgsql_area.osm} | 0 4 files changed, 7 insertions(+), 8 deletions(-) rename tests/{test-area-reprojection.cpp => test-output-pgsql-area.cpp} (95%) rename tests/{area-reprojection.osm => test_output_pgsql_area.osm} (100%) diff --git a/.gitignore b/.gitignore index 414c26440..1c6cbc60d 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ tests/test-output-pgsql tests/test-output-pgsql-tablespace tests/test-output-pgsql-z_order tests/test-output-pgsql-schema +tests/test-output-pgsql-area tests/test-expire-tiles tests/test-hstore-match-only tests/*.log diff --git a/Makefile.am b/Makefile.am index 708aca5f2..a3687c7cd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,7 +64,7 @@ check_PROGRAMS = \ tests/test-options-database \ tests/test-expire-tiles \ tests/test-hstore-match-only \ - tests/test-area-reprojection + tests/test-output-pgsql-area tests_test_parse_xml2_SOURCES = tests/test-parse-xml2.cpp tests_test_parse_xml2_LDADD = libosm2pgsql.la @@ -106,8 +106,8 @@ tests_test_options_database_SOURCES = tests/test-options-database.cpp tests_test_options_database_LDADD = libosm2pgsql.la tests_test_expire_tiles_SOURCES = tests/test-expire-tiles.cpp tests_test_expire_tiles_LDADD = libosm2pgsql.la -tests_test_area_reprojection_SOURCES = tests/test-area-reprojection.cpp tests/common-pg.cpp -tests_test_area_reprojection_LDADD = libosm2pgsql.la +tests_test_output_pgsql_area_SOURCES = tests/test-output-pgsql-area.cpp tests/common-pg.cpp +tests_test_output_pgsql_area_LDADD = libosm2pgsql.la MOSTLYCLEANFILES = tests/test_middle_flat.flat.nodes.bin tests/test_output_pgsql_area_way.flat.nodes.bin @@ -157,7 +157,7 @@ tests_test_output_multi_point_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_multi_point_multi_table_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_multi_polygon_LDADD += $(GLOBAL_LDFLAGS) tests_test_hstore_match_only_LDADD += $(GLOBAL_LDFLAGS) -tests_test_area_reprojection_LDADD += $(GLOBAL_LDFLAGS) +tests_test_output_pgsql_area_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) diff --git a/tests/test-area-reprojection.cpp b/tests/test-output-pgsql-area.cpp similarity index 95% rename from tests/test-area-reprojection.cpp rename to tests/test-output-pgsql-area.cpp index 4a64dae86..d6df39856 100644 --- a/tests/test-area-reprojection.cpp +++ b/tests/test-output-pgsql-area.cpp @@ -1,4 +1,4 @@ -/* +/** Test the area reprojection functionality of osm2pgsql @@ -7,8 +7,6 @@ column with the area that a polygoun would have in EPSG:3857, rather than the area it actually has in the coordinate system used for importing. -This goes with a test data file named area-reprojection.osm - */ #include #include @@ -84,7 +82,7 @@ void test_area_base(bool latlon, bool reproj, double expect_area) { osmdata.start(); - parser->stream_file("libxml2", "tests/area-reprojection.osm", &osmdata); + parser->stream_file("libxml2", "tests/test_output_pgsql_area.osm", &osmdata); parser.reset(nullptr); diff --git a/tests/area-reprojection.osm b/tests/test_output_pgsql_area.osm similarity index 100% rename from tests/area-reprojection.osm rename to tests/test_output_pgsql_area.osm From 0878fbbb3dce99593a5db64aff01f66efc57d1b9 Mon Sep 17 00:00:00 2001 From: Paul Norman Date: Tue, 20 Oct 2015 20:52:59 -0700 Subject: [PATCH 7/8] test area of both polygons and multipolygons --- tests/test-output-pgsql-area.cpp | 14 ++++---- tests/test_output_pgsql_area.osm | 58 +++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/tests/test-output-pgsql-area.cpp b/tests/test-output-pgsql-area.cpp index d6df39856..d8249a426 100644 --- a/tests/test-output-pgsql-area.cpp +++ b/tests/test-output-pgsql-area.cpp @@ -50,7 +50,7 @@ void run_test(const char* test_name, void (*testfunc)()) { #define RUN_TEST(x) run_test(#x, &(x)) -void test_area_base(bool latlon, bool reproj, double expect_area) { +void test_area_base(bool latlon, bool reproj, double expect_area_poly, double expect_area_multi) { std::unique_ptr db; try { @@ -88,23 +88,23 @@ void test_area_base(bool latlon, bool reproj, double expect_area) { osmdata.stop(); - // tables should not contain any tag columns - db->check_count(1, "select count(*) from osm2pgsql_test_polygon"); - db->check_number(expect_area, "SELECT way_area FROM osm2pgsql_test_polygon"); + db->check_count(2, "SELECT COUNT(*) FROM osm2pgsql_test_polygon"); + db->check_number(expect_area_poly, "SELECT way_area FROM osm2pgsql_test_polygon WHERE name='poly'"); + db->check_number(expect_area_multi, "SELECT way_area FROM osm2pgsql_test_polygon WHERE name='multi'"); return; } void test_area_classic() { - test_area_base(false, false, 6.66e+10); + test_area_base(false, false, 1.23927e+10, 9.91828e+10); } void test_area_latlon() { - test_area_base(true, false, 6.66e-1); + test_area_base(true, false, 1, 8); } void test_area_latlon_with_reprojection() { - test_area_base(true, true, 6.66e+10); + test_area_base(true, true, 1.23927e+10, 9.91828e+10); } int main(int argc, char *argv[]) { diff --git a/tests/test_output_pgsql_area.osm b/tests/test_output_pgsql_area.osm index 0c98a0982..260f11eb4 100644 --- a/tests/test_output_pgsql_area.osm +++ b/tests/test_output_pgsql_area.osm @@ -1,27 +1,55 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + + + + + + - + + + + - - + + + + + + + + + + From db01e7d7df660c8e688fd05ea3b61ef619f6fc41 Mon Sep 17 00:00:00 2001 From: Paul Norman Date: Tue, 20 Oct 2015 21:46:09 -0700 Subject: [PATCH 8/8] Use std::accumulate, make better use of auto --- geometry-builder.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/geometry-builder.cpp b/geometry-builder.cpp index 1b9a8112f..e4e690d50 100644 --- a/geometry-builder.cpp +++ b/geometry-builder.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #if defined(__CYGWIN__) #define GEOS_INLINE @@ -776,15 +777,12 @@ double geometry_builder::getArea(const geos::geom::Geometry *geom) const } // MultiPolygon - return sum of individual areas - if (const geos::geom::MultiPolygon* multi = dynamic_cast(geom)) { - double area = 0.0; - for (std::size_t i=0; igetNumGeometries(); i++) { - area += getArea(multi->getGeometryN(i)); - } - return area; + if (const auto *multi = dynamic_cast(geom)) { + return std::accumulate(multi->begin(), multi->end(), 0.0, + [=](double a, const geos::geom::Geometry *geom) { return a + getArea(geom); }); } - const geos::geom::Polygon *poly = dynamic_cast(geom); + const auto *poly = dynamic_cast(geom); if (!poly) { return 0.0; } @@ -792,17 +790,17 @@ double geometry_builder::getArea(const geos::geom::Geometry *geom) const // standard polygon - reproject rings individually, then assemble polygon and // compute area. - const geos::geom::LineString* ext = poly->getExteriorRing(); - geos::geom::LinearRing* projectedExt = reproject_linearring(ext); - std::size_t nholes = poly->getNumInteriorRing(); + const auto *ext = poly->getExteriorRing(); + auto *projectedExt = reproject_linearring(ext); + auto nholes = poly->getNumInteriorRing(); std::vector *projectedHoles = new std::vector(nholes); - for (std::size_t i=0; i< poly->getNumInteriorRing(); i++) { + for (std::size_t i=0; i < poly->getNumInteriorRing(); i++) { const geos::geom::LineString* hole = poly->getInteriorRingN(i); (*projectedHoles)[i] = reproject_linearring(hole); } - const geos::geom::Polygon *projectedPoly = poly->getFactory()->createPolygon(projectedExt, projectedHoles); + const auto *projectedPoly = poly->getFactory()->createPolygon(projectedExt, projectedHoles); - double area = projectedPoly->getArea(); + auto area = projectedPoly->getArea(); delete projectedPoly; return area; }