parent
							
								
									2927d149db
								
							
						
					
					
						commit
						b3599ea249
					
				@ -80,6 +80,8 @@ const constexpr double TILE_SIZE = 256.0;
 | 
			
		||||
// Converts projected mercator degrees to PX
 | 
			
		||||
const constexpr double DEGREE_TO_PX = detail::MAXEXTENT / 180.0;
 | 
			
		||||
 | 
			
		||||
double degreeToPixel(FloatLatitude lat, unsigned zoom);
 | 
			
		||||
double degreeToPixel(FloatLongitude lon, unsigned zoom);
 | 
			
		||||
FloatLatitude yToLat(const double value);
 | 
			
		||||
double latToY(const FloatLatitude latitude);
 | 
			
		||||
void xyzToMercator(const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy);
 | 
			
		||||
 | 
			
		||||
@ -1,87 +0,0 @@
 | 
			
		||||
#ifndef UTIL_TILES_HPP
 | 
			
		||||
#define UTIL_TILES_HPP
 | 
			
		||||
 | 
			
		||||
#include "util/coordinate.hpp"
 | 
			
		||||
 | 
			
		||||
#include <boost/assert.hpp>
 | 
			
		||||
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
 | 
			
		||||
// This is a port of the tilebelt algorithm https://github.com/mapbox/tilebelt
 | 
			
		||||
namespace osrm
 | 
			
		||||
{
 | 
			
		||||
namespace util
 | 
			
		||||
{
 | 
			
		||||
namespace tiles
 | 
			
		||||
{
 | 
			
		||||
struct Tile
 | 
			
		||||
{
 | 
			
		||||
    unsigned x;
 | 
			
		||||
    unsigned y;
 | 
			
		||||
    unsigned z;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace detail
 | 
			
		||||
{
 | 
			
		||||
// optimized for 32bit integers
 | 
			
		||||
static constexpr unsigned MAX_ZOOM = 32;
 | 
			
		||||
 | 
			
		||||
// Returns 1-indexed 1..32 of MSB if value > 0 or 0 if value == 0
 | 
			
		||||
inline unsigned getMSBPosition(std::uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
    if (value == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
    std::uint8_t pos = 1;
 | 
			
		||||
    while (value >>= 1)
 | 
			
		||||
        pos++;
 | 
			
		||||
    return pos;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline unsigned getBBMaxZoom(const Tile top_left, const Tile bottom_left)
 | 
			
		||||
{
 | 
			
		||||
    auto x_xor = top_left.x ^ bottom_left.x;
 | 
			
		||||
    auto y_xor = top_left.y ^ bottom_left.y;
 | 
			
		||||
    auto lon_msb = detail::getMSBPosition(x_xor);
 | 
			
		||||
    auto lat_msb = detail::getMSBPosition(y_xor);
 | 
			
		||||
    return MAX_ZOOM - std::max(lon_msb, lat_msb);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Tile pointToTile(const FloatLongitude lon, const FloatLatitude lat)
 | 
			
		||||
{
 | 
			
		||||
    auto sin_lat = std::sin(static_cast<double>(lat) * M_PI / 180.);
 | 
			
		||||
    auto p2z = std::pow(2, detail::MAX_ZOOM);
 | 
			
		||||
    unsigned x = p2z * (static_cast<double>(lon) / 360. + 0.5);
 | 
			
		||||
    unsigned y = p2z * (0.5 - 0.25 * std::log((1 + sin_lat) / (1 - sin_lat)) / M_PI);
 | 
			
		||||
 | 
			
		||||
    return Tile{x, y, detail::MAX_ZOOM};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Tile getBBMaxZoomTile(const FloatLongitude min_lon,
 | 
			
		||||
                             const FloatLatitude min_lat,
 | 
			
		||||
                             const FloatLongitude max_lon,
 | 
			
		||||
                             const FloatLatitude max_lat)
 | 
			
		||||
{
 | 
			
		||||
    const auto top_left = pointToTile(min_lon, min_lat);
 | 
			
		||||
    const auto bottom_left = pointToTile(max_lon, max_lat);
 | 
			
		||||
    BOOST_ASSERT(top_left.z == detail::MAX_ZOOM);
 | 
			
		||||
    BOOST_ASSERT(bottom_left.z == detail::MAX_ZOOM);
 | 
			
		||||
 | 
			
		||||
    const auto max_zoom = detail::getBBMaxZoom(top_left, bottom_left);
 | 
			
		||||
 | 
			
		||||
    if (max_zoom == 0)
 | 
			
		||||
    {
 | 
			
		||||
        return Tile{0, 0, 0};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto x = top_left.x >> (detail::MAX_ZOOM - max_zoom);
 | 
			
		||||
    auto y = top_left.y >> (detail::MAX_ZOOM - max_zoom);
 | 
			
		||||
 | 
			
		||||
    return Tile{x, y, max_zoom};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										48
									
								
								include/util/viewport.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								include/util/viewport.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
#ifndef UTIL_VIEWPORT_HPP
 | 
			
		||||
#define UTIL_VIEWPORT_HPP
 | 
			
		||||
 | 
			
		||||
#include "util/coordinate.hpp"
 | 
			
		||||
#include "util/coordinate_calculation.hpp"
 | 
			
		||||
 | 
			
		||||
#include <boost/assert.hpp>
 | 
			
		||||
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
 | 
			
		||||
// Port of https://github.com/mapbox/geo-viewport
 | 
			
		||||
 | 
			
		||||
namespace osrm
 | 
			
		||||
{
 | 
			
		||||
namespace util
 | 
			
		||||
{
 | 
			
		||||
namespace viewport
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace detail
 | 
			
		||||
{
 | 
			
		||||
static constexpr unsigned MAX_ZOOM = 18;
 | 
			
		||||
static constexpr unsigned MIN_ZOOM = 1;
 | 
			
		||||
// this is an upper bound to current display sizes
 | 
			
		||||
static constexpr double VIEWPORT_WIDTH = 8 * coordinate_calculation::mercator::TILE_SIZE;
 | 
			
		||||
static constexpr double VIEWPORT_HEIGHT = 5 * coordinate_calculation::mercator::TILE_SIZE;
 | 
			
		||||
static double INV_LOG_2 = 1. / std::log(2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned getFittedZoom(util::Coordinate south_west, util::Coordinate north_east)
 | 
			
		||||
{
 | 
			
		||||
    const auto min_x = coordinate_calculation::mercator::degreeToPixel(toFloating(south_west.lon), detail::MAX_ZOOM);
 | 
			
		||||
    const auto max_y = coordinate_calculation::mercator::degreeToPixel(toFloating(south_west.lat), detail::MAX_ZOOM);
 | 
			
		||||
    const auto max_x = coordinate_calculation::mercator::degreeToPixel(toFloating(north_east.lon), detail::MAX_ZOOM);
 | 
			
		||||
    const auto min_y = coordinate_calculation::mercator::degreeToPixel(toFloating(north_east.lat), detail::MAX_ZOOM);
 | 
			
		||||
    const double width_ratio = (max_x - min_x) / detail::VIEWPORT_WIDTH;
 | 
			
		||||
    const double height_ratio = (max_y - min_y) / detail::VIEWPORT_HEIGHT;
 | 
			
		||||
    const auto zoom = detail::MAX_ZOOM - std::max(std::log(width_ratio), std::log(height_ratio)) * detail::INV_LOG_2;
 | 
			
		||||
 | 
			
		||||
    return std::max<unsigned>(detail::MIN_ZOOM, zoom);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
#include "engine/guidance/leg_geometry.hpp"
 | 
			
		||||
#include "engine/douglas_peucker.hpp"
 | 
			
		||||
#include "util/tiles.hpp"
 | 
			
		||||
#include "util/viewport.hpp"
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
@ -23,25 +23,22 @@ namespace
 | 
			
		||||
 | 
			
		||||
unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometries)
 | 
			
		||||
{
 | 
			
		||||
    util::FixedLongitude min_lon{std::numeric_limits<int>::max()};
 | 
			
		||||
    util::FixedLongitude max_lon{std::numeric_limits<int>::min()};
 | 
			
		||||
    util::FixedLatitude min_lat{std::numeric_limits<int>::max()};
 | 
			
		||||
    util::FixedLatitude max_lat{std::numeric_limits<int>::min()};
 | 
			
		||||
    util::Coordinate south_west{util::FixedLongitude{std::numeric_limits<int>::max()}, util::FixedLatitude{std::numeric_limits<int>::max()}};
 | 
			
		||||
    util::Coordinate north_east{util::FixedLongitude{std::numeric_limits<int>::min()}, util::FixedLatitude{std::numeric_limits<int>::min()}};
 | 
			
		||||
 | 
			
		||||
    for (const auto &leg_geometry : leg_geometries)
 | 
			
		||||
    {
 | 
			
		||||
        for (const auto coord : leg_geometry.locations)
 | 
			
		||||
        {
 | 
			
		||||
            min_lon = std::min(min_lon, coord.lon);
 | 
			
		||||
            max_lon = std::max(max_lon, coord.lon);
 | 
			
		||||
            min_lat = std::min(min_lat, coord.lat);
 | 
			
		||||
            max_lat = std::max(max_lat, coord.lat);
 | 
			
		||||
            south_west.lon = std::min(south_west.lon, coord.lon);
 | 
			
		||||
            south_west.lat = std::min(south_west.lat, coord.lat);
 | 
			
		||||
 | 
			
		||||
            north_east.lon = std::max(north_east.lon, coord.lon);
 | 
			
		||||
            north_east.lat = std::max(north_east.lat, coord.lat);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return util::tiles::getBBMaxZoomTile(toFloating(min_lon), toFloating(min_lat),
 | 
			
		||||
                                         toFloating(max_lon), toFloating(max_lat))
 | 
			
		||||
        .z;
 | 
			
		||||
    return util::viewport::getFittedZoom(south_west, north_east);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<util::Coordinate> simplifyGeometry(const std::vector<LegGeometry> &leg_geometries,
 | 
			
		||||
 | 
			
		||||
@ -29,20 +29,6 @@ Coordinate::Coordinate(const FloatLongitude lon_, const FloatLatitude lat_)
 | 
			
		||||
 | 
			
		||||
Coordinate::Coordinate(const FixedLongitude lon_, const FixedLatitude lat_) : lon(lon_), lat(lat_)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    if (0 != (std::abs(static_cast<int>(lon)) >> 30))
 | 
			
		||||
    {
 | 
			
		||||
        std::bitset<32> x_coordinate_vector(static_cast<int>(lon));
 | 
			
		||||
        SimpleLogger().Write(logDEBUG) << "broken lon: " << lon
 | 
			
		||||
                                       << ", bits: " << x_coordinate_vector;
 | 
			
		||||
    }
 | 
			
		||||
    if (0 != (std::abs(static_cast<int>(lat)) >> 30))
 | 
			
		||||
    {
 | 
			
		||||
        std::bitset<32> y_coordinate_vector(static_cast<int>(lat));
 | 
			
		||||
        SimpleLogger().Write(logDEBUG) << "broken lat: " << lat
 | 
			
		||||
                                       << ", bits: " << y_coordinate_vector;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Coordinate::IsValid() const
 | 
			
		||||
 | 
			
		||||
@ -301,9 +301,26 @@ inline void pixelToDegree(const double shift, double &x, double &y)
 | 
			
		||||
    x = (x - b) / shift * 360.0;
 | 
			
		||||
    // FIXME needs to be simplified
 | 
			
		||||
    const double g = (y - b) / -(shift / (2 * M_PI)) / DEGREE_TO_RAD;
 | 
			
		||||
    static_assert(DEGREE_TO_RAD / (2 * M_PI) - 1/360. < 0.0001, "");
 | 
			
		||||
    y = static_cast<double>(util::coordinate_calculation::mercator::yToLat(g));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double degreeToPixel(FloatLongitude lon, unsigned zoom)
 | 
			
		||||
{
 | 
			
		||||
    const double shift = (1u << zoom) * TILE_SIZE;
 | 
			
		||||
    const double b = shift / 2.0;
 | 
			
		||||
    const double x = b * (1 + static_cast<double>(lon) / 180.0);
 | 
			
		||||
    return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double degreeToPixel(FloatLatitude lat, unsigned zoom)
 | 
			
		||||
{
 | 
			
		||||
    const double shift = (1u << zoom) * TILE_SIZE;
 | 
			
		||||
    const double b = shift / 2.0;
 | 
			
		||||
    const double y = b * (1. - latToY(lat) / 180.);
 | 
			
		||||
    return y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Converts a WMS tile coordinate (z,x,y) into a wsg84 bounding box
 | 
			
		||||
void xyzToWSG84(const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@ -1,83 +0,0 @@
 | 
			
		||||
#include "util/tiles.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace osrm::util;
 | 
			
		||||
 | 
			
		||||
#include <boost/functional/hash.hpp>
 | 
			
		||||
#include <boost/test/unit_test.hpp>
 | 
			
		||||
#include <boost/test/test_case_template.hpp>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(tiles_test)
 | 
			
		||||
 | 
			
		||||
using namespace osrm;
 | 
			
		||||
using namespace osrm::util;
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(point_to_tile_test)
 | 
			
		||||
{
 | 
			
		||||
    tiles::Tile tile_1_reference{2306375680, 1409941503, 32};
 | 
			
		||||
    tiles::Tile tile_2_reference{2308259840, 1407668224, 32};
 | 
			
		||||
    tiles::Tile tile_3_reference{616562688, 2805989376, 32};
 | 
			
		||||
    tiles::Tile tile_4_reference{1417674752, 2084569088, 32};
 | 
			
		||||
    tiles::Tile tile_5_reference{616562688, 2805989376, 32};
 | 
			
		||||
    tiles::Tile tile_6_reference{712654285, 2671662374, 32};
 | 
			
		||||
 | 
			
		||||
    auto tile_1 =
 | 
			
		||||
        tiles::pointToTile(FloatLongitude(13.31817626953125), FloatLatitude(52.449314140869696));
 | 
			
		||||
    auto tile_2 =
 | 
			
		||||
        tiles::pointToTile(FloatLongitude(13.476104736328125), FloatLatitude(52.56529070208021));
 | 
			
		||||
    auto tile_3 =
 | 
			
		||||
        tiles::pointToTile(FloatLongitude(-128.32031249999997), FloatLatitude(-48.224672649565186));
 | 
			
		||||
    auto tile_4 =
 | 
			
		||||
        tiles::pointToTile(FloatLongitude(-61.17187499999999), FloatLatitude(5.266007882805498));
 | 
			
		||||
    auto tile_5 =
 | 
			
		||||
        tiles::pointToTile(FloatLongitude(-128.32031249999997), FloatLatitude(-48.224672649565186));
 | 
			
		||||
    auto tile_6 =
 | 
			
		||||
        tiles::pointToTile(FloatLongitude(-120.266007882805532), FloatLatitude(-40.17187499999999));
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_1.x, tile_1_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_1.y, tile_1_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_1.z, tile_1_reference.z);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_2.x, tile_2_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_2.y, tile_2_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_2.z, tile_2_reference.z);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_3.x, tile_3_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_3.y, tile_3_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_3.z, tile_3_reference.z);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_4.x, tile_4_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_4.y, tile_4_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_4.z, tile_4_reference.z);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_5.x, tile_5_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_5.y, tile_5_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_5.z, tile_5_reference.z);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_6.x, tile_6_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_6.y, tile_6_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_6.z, tile_6_reference.z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Verify that the bearing-bounds checking function behaves as expected
 | 
			
		||||
BOOST_AUTO_TEST_CASE(bounding_box_to_tile_test)
 | 
			
		||||
{
 | 
			
		||||
    tiles::Tile tile_1_reference{17, 10, 5};
 | 
			
		||||
    tiles::Tile tile_2_reference{0, 0, 0};
 | 
			
		||||
    tiles::Tile tile_3_reference{0, 2, 2};
 | 
			
		||||
    auto tile_1 = tiles::getBBMaxZoomTile(
 | 
			
		||||
        FloatLongitude(13.31817626953125), FloatLatitude(52.449314140869696),
 | 
			
		||||
        FloatLongitude(13.476104736328125), FloatLatitude(52.56529070208021));
 | 
			
		||||
    auto tile_2 = tiles::getBBMaxZoomTile(
 | 
			
		||||
        FloatLongitude(-128.32031249999997), FloatLatitude(-48.224672649565186),
 | 
			
		||||
        FloatLongitude(-61.17187499999999), FloatLatitude(5.266007882805498));
 | 
			
		||||
    auto tile_3 = tiles::getBBMaxZoomTile(
 | 
			
		||||
        FloatLongitude(-128.32031249999997), FloatLatitude(-48.224672649565186),
 | 
			
		||||
        FloatLongitude(-120.2660078828055), FloatLatitude(-40.17187499999999));
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_1.x, tile_1_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_1.y, tile_1_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_1.z, tile_1_reference.z);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_2.x, tile_2_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_2.y, tile_2_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_2.z, tile_2_reference.z);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_3.x, tile_3_reference.x);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_3.y, tile_3_reference.y);
 | 
			
		||||
    BOOST_CHECK_EQUAL(tile_3.z, tile_3_reference.z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
							
								
								
									
										25
									
								
								unit_tests/util/viewport.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								unit_tests/util/viewport.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
#include "util/viewport.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace osrm::util;
 | 
			
		||||
 | 
			
		||||
#include <boost/functional/hash.hpp>
 | 
			
		||||
#include <boost/test/unit_test.hpp>
 | 
			
		||||
#include <boost/test/test_case_template.hpp>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(viewport_test)
 | 
			
		||||
 | 
			
		||||
using namespace osrm;
 | 
			
		||||
using namespace osrm::util;
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(zoom_level_test)
 | 
			
		||||
{
 | 
			
		||||
    BOOST_CHECK_EQUAL(
 | 
			
		||||
        viewport::getFittedZoom(
 | 
			
		||||
            Coordinate(FloatLongitude{5.668343999999995}, FloatLatitude{45.111511000000014}),
 | 
			
		||||
            Coordinate(FloatLongitude{5.852471999999996}, FloatLatitude{45.26800200000002})),
 | 
			
		||||
        12);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user