/** * Check whether the location is inside the box. * * @pre Location must be defined. * @pre Box must be defined. */ bool contains(const osmium::Location& location) const noexcept { assert(bottom_left()); assert(top_right()); assert(location); return location.x() >= bottom_left().x() && location.y() >= bottom_left().y() && location.x() <= top_right().x() && location.y() <= top_right().y(); }
/** * Create box from bottom left and top right locations. * * @pre Either both locations must be defined or neither. * @pre If both locations are defined, the * bottom left location must actually be to the left and below * the top right location. Same coordinates for bottom/top or * left/right are also okay. */ Box(const osmium::Location& bottom_left, const osmium::Location& top_right) : m_bottom_left(bottom_left), m_top_right(top_right) { assert( (!!bottom_left && !!top_right) || (bottom_left.x() <= top_right.x() && bottom_left.y() <= top_right.y()) ); }
Coordinates operator()(osmium::Location location) const { Coordinates c {location.lon(), location.lat()}; if (m_epsg != 4326) { c = transform(m_crs_wgs84, m_crs_user, Coordinates(deg_to_rad(location.lon()), deg_to_rad(location.lat()))); if (m_crs_user.is_latlong()) { c.x = rad_to_deg(c.x); c.y = rad_to_deg(c.y); } } return c; }
/** * Create a tile with the given zoom level that contains the given * location. * * The values are not checked for validity. * * @pre @code location.valid() && zoom <= 30 @endcode */ explicit Tile(uint32_t zoom, const osmium::Location& location) : z(zoom) { assert(zoom <= 30u); assert(location.valid()); const auto coordinates = lonlat_to_mercator(location); x = mercx_to_tilex(zoom, coordinates.x); y = mercy_to_tiley(zoom, coordinates.y); }
void write_location(const osmium::Location& location, const char x, const char y) { if (location) { output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check()); } else { *m_out += ' '; *m_out += x; *m_out += ' '; *m_out += y; } }
/** * Create a tile with the given zoom level that contains the given * location. * * The values are not checked for validity. * * @pre @code location.valid() && zoom <= 30 @endcode */ explicit Tile(uint32_t zoom, const osmium::Location& location) : z(zoom) { assert(zoom <= 30u); assert(location.valid()); const osmium::geom::Coordinates c = lonlat_to_mercator(location); const int32_t n = 1 << zoom; const double scale = detail::max_coordinate_epsg3857 * 2 / n; x = uint32_t(detail::restrict_to_range<int32_t>(int32_t((c.x + detail::max_coordinate_epsg3857) / scale), 0, n-1)); y = uint32_t(detail::restrict_to_range<int32_t>(int32_t((detail::max_coordinate_epsg3857 - c.y) / scale), 0, n-1)); }
bool to_left_of(const osmium::Location& location) const { // std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n"; if (first().location() == location || second().location() == location) { return false; } const std::pair<osmium::Location, osmium::Location> mm = std::minmax(first().location(), second().location(), [](const osmium::Location a, const osmium::Location b) { return a.y() < b.y(); }); if (mm.first.y() >= location.y() || mm.second.y() < location.y() || first().location().x() > location.x()) { // std::cerr << " false\n"; return false; } int64_t ax = mm.first.x(); int64_t bx = mm.second.x(); int64_t lx = location.x(); int64_t ay = mm.first.y(); int64_t by = mm.second.y(); int64_t ly = location.y(); return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0; }
/** * Extend the bounding box by the given location. If the * location is undefined, the bounding box is unchanged. */ Bounds& extend(const Location& location) noexcept { if (location) { if (m_bottom_left) { if (location.x() < m_bottom_left.x()) { m_bottom_left.x(location.x()); } if (location.x() > m_top_right.x()) { m_top_right.x(location.x()); } if (location.y() < m_bottom_left.y()) { m_bottom_left.y(location.y()); } if (location.y() > m_top_right.y()) { m_top_right.y(location.y()); } } else { m_bottom_left = location; m_top_right = location; } } return *this; }
constexpr explicit vec(const osmium::Location& l) noexcept : x(l.x()), y(l.y()) { }
#include "catch.hpp" #include <sstream> #include <type_traits> #include <osmium/osm/location.hpp> TEST_CASE("Location") { // fails on MSVC and doesn't really matter // static_assert(std::is_literal_type<osmium::Location>::value, "osmium::Location not literal type"); SECTION("instantiation_with_default_parameters") { osmium::Location loc; REQUIRE(!loc); REQUIRE_THROWS_AS(loc.lon(), osmium::invalid_location); REQUIRE_THROWS_AS(loc.lat(), osmium::invalid_location); } SECTION("instantiation_with_double_parameters") { osmium::Location loc1(1.2, 4.5); REQUIRE(!!loc1); REQUIRE(12000000 == loc1.x()); REQUIRE(45000000 == loc1.y()); REQUIRE(1.2 == loc1.lon()); REQUIRE(4.5 == loc1.lat()); osmium::Location loc2(loc1); REQUIRE(4.5 == loc2.lat()); osmium::Location loc3 = loc1;
void write_location(const osmium::Location& location, const char x, const char y) { *m_out += ' '; *m_out += x; if (location) { osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.x()); } *m_out += ' '; *m_out += y; if (location) { osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.y()); } }
Coordinates(const osmium::Location& location) : x(location.lon()), y(location.lat()) { }
inline size_t hash(const osmium::Location& location) noexcept { return location.x() ^ location.y(); }
inline size_t hash<8>(const osmium::Location& location) noexcept { uint64_t h = location.x(); h <<= 32; return static_cast<size_t>(h ^ location.y()); }
void lon(double x) { m_location.lon(x); }
/** * Get latitude of the location in this NodeRef. * * @throws osmium::invalid_location if the location is not set. */ double lat() const { return m_location.lat(); }
/** * Calculate size of the box in square degrees. * * Note that this measure isn't very useful if you want to know the * real-world size of the bounding box! * * @throws osmium::invalid_location unless all coordinates are valid. */ double size() const { return (m_top_right.lon() - m_bottom_left.lon()) * (m_top_right.lat() - m_bottom_left.lat()); }
void update(const osmium::Location& location) { update_int32(location.x()); update_int32(location.y()); }
#include "catch.hpp" #include <osmium/osm/location.hpp> #include <limits> #include <sstream> #include <type_traits> // fails on MSVC and doesn't really matter // static_assert(std::is_literal_type<osmium::Location>::value, "osmium::Location not literal type"); TEST_CASE("Location instantiation with default parameters") { const osmium::Location loc; REQUIRE_FALSE(loc); REQUIRE_FALSE(loc.is_defined()); REQUIRE(loc.is_undefined()); REQUIRE_THROWS_AS(loc.lon(), const osmium::invalid_location&); REQUIRE_THROWS_AS(loc.lat(), const osmium::invalid_location&); } TEST_CASE("Location instantiation with double parameters") { const osmium::Location loc1{1.2, 4.5}; REQUIRE(bool(loc1)); REQUIRE(loc1.is_defined()); REQUIRE_FALSE(loc1.is_undefined()); REQUIRE(12000000 == loc1.x()); REQUIRE(45000000 == loc1.y()); REQUIRE(1.2 == Approx(loc1.lon())); REQUIRE(4.5 == Approx(loc1.lat())); const osmium::Location loc2{loc1};
/** * Get longitude of the location in this NodeRef. * * @throws osmium::invalid_location if the location is not set. */ double lon() const { return m_location.lon(); }
/** * Get internal y value of the location in this NodeRef. */ constexpr int32_t y() const noexcept { return m_location.y(); }
void lat(double y) { m_location.lat(y); }
Coordinates operator()(osmium::Location location) const { return Coordinates {detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())}; }
/** * Checks if there are intersections between any coastline segments. * Returns the number of intersections and overlaps. */ unsigned int CoastlineRingCollection::check_for_intersections(OutputDatabase& output, int segments_fd) { unsigned int overlaps = 0; std::vector<osmium::UndirectedSegment> segments; if (debug) std::cerr << "Setting up segments...\n"; for (const auto& ring : m_list) { ring->add_segments_to_vector(segments); } if (debug) std::cerr << "Sorting...\n"; std::sort(segments.begin(), segments.end()); if (segments_fd >= 0) { if (debug) std::cerr << "Writing segments to file...\n"; ssize_t length = segments.size() * sizeof(osmium::UndirectedSegment); #ifndef _MSC_VER if (::write(segments_fd, segments.data(), length) != length) { #else if (_write(segments_fd, segments.data(), length) != length) { #endif throw std::runtime_error{"Write error"}; } } if (debug) std::cerr << "Finding intersections...\n"; std::vector<osmium::Location> intersections; for (auto it1 = segments.cbegin(); it1 != segments.cend()-1; ++it1) { const osmium::UndirectedSegment& s1 = *it1; for (auto it2 = it1+1; it2 != segments.cend(); ++it2) { const osmium::UndirectedSegment& s2 = *it2; if (s1 == s2) { std::unique_ptr<OGRLineString> line = create_ogr_linestring(s1); output.add_error_line(std::move(line), "overlap"); overlaps++; } else { if (outside_x_range(s2, s1)) { break; } if (y_range_overlap(s1, s2)) { osmium::Location i = intersection(s1, s2); if (i) { intersections.push_back(i); } } } } } for (const auto& intersection : intersections) { std::unique_ptr<OGRPoint> point{new OGRPoint(intersection.lon(), intersection.lat())}; output.add_error_point(std::move(point), "intersection"); } return intersections.size() + overlaps; } bool CoastlineRingCollection::close_antarctica_ring(int epsg) { for (const auto& ring : m_list) { const osmium::Location fpos = ring->first_position(); const osmium::Location lpos = ring->last_position(); if (fpos.lon() > 179.99 && lpos.lon() < -179.99 && fpos.lat() < -77.0 && fpos.lat() > -78.0 && lpos.lat() < -77.0 && lpos.lat() > -78.0) { m_end_nodes.erase(ring->last_node_id()); m_start_nodes.erase(ring->first_node_id()); ring->close_antarctica_ring(epsg); return true; } } return false; } void CoastlineRingCollection::close_rings(OutputDatabase& output, bool debug, double max_distance) { std::vector<Connection> connections; // Create vector with all possible combinations of connections between rings. for (idmap_type::iterator eit = m_end_nodes.begin(); eit != m_end_nodes.end(); ++eit) { for (idmap_type::iterator sit = m_start_nodes.begin(); sit != m_start_nodes.end(); ++sit) { const double distance = (*sit->second)->distance_to_start_position((*eit->second)->last_position()); if (distance < max_distance) { connections.emplace_back(distance, eit->first, sit->first); } } } // Sort vector by distance, shortest at end. std::sort(connections.begin(), connections.end(), Connection::sort_by_distance); // Go through vector starting with the shortest connections and close rings // using the connections in turn. while (!connections.empty()) { Connection conn = connections.back(); connections.pop_back(); // Invalidate all other connections using one of the same end points. connections.erase(remove_if(connections.begin(), connections.end(), conn), connections.end()); idmap_type::iterator eit = m_end_nodes.find(conn.start_id); idmap_type::iterator sit = m_start_nodes.find(conn.end_id); if (eit != m_end_nodes.end() && sit != m_start_nodes.end()) { if (debug) { std::cerr << "Closing ring between node " << conn.end_id << " and node " << conn.start_id << "\n"; } m_fixed_rings++; CoastlineRing* e = eit->second->get(); CoastlineRing* s = sit->second->get(); output.add_error_point(e->ogr_last_point(), "fixed_end_point", e->last_node_id()); output.add_error_point(s->ogr_first_point(), "fixed_end_point", s->first_node_id()); if (e->last_position() != s->first_position()) { std::unique_ptr<OGRLineString> linestring{new OGRLineString}; linestring->addPoint(e->last_position().lon(), e->last_position().lat()); linestring->addPoint(s->first_position().lon(), s->first_position().lat()); output.add_error_line(std::move(linestring), "added_line"); } if (e == s) { // connect to itself by closing ring e->close_ring(); m_end_nodes.erase(eit); m_start_nodes.erase(sit); } else { // connect to other ring e->join_over_gap(*s); m_list.erase(sit->second); if (e->first_position() == e->last_position()) { output.add_error_point(e->ogr_first_point(), "double_node", e->first_node_id()); m_start_nodes.erase(e->first_node_id()); m_end_nodes.erase(eit); m_start_nodes.erase(sit); m_end_nodes.erase(e->last_node_id()); e->fake_close(); } else { m_end_nodes[e->last_node_id()] = eit->second; m_end_nodes.erase(eit); m_start_nodes.erase(sit); } } } } }
void add_location(const osmium::Location& location) { if (location.valid()) { m_dirty_tiles.emplace(m_zoom, location); } }
Coordinates operator()(osmium::Location location) const { return Coordinates{location.lon(), location.lat()}; }
int32_t x() const noexcept { return m_location.x(); }