Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] Refactor tileCover #3810

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 21 additions & 52 deletions src/mbgl/map/source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/box.hpp>
#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_update_parameters.hpp>
Expand Down Expand Up @@ -302,47 +300,6 @@ TileData::State Source::addTile(const TileID& tileID, const StyleUpdateParameter
return newState;
}

double Source::getZoom(const TransformState& state) const {
double offset = std::log(util::tileSize / tileSize) / std::log(2);
return state.getZoom() + offset;
}

int32_t Source::coveringZoomLevel(const TransformState& state) const {
double zoom = getZoom(state);
if (type == SourceType::Raster || type == SourceType::Video) {
zoom = ::round(zoom);
} else {
zoom = std::floor(zoom);
}
return util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
}

std::forward_list<TileID> Source::coveringTiles(const TransformState& state) const {
int32_t z = coveringZoomLevel(state);

auto actualZ = z;
const bool reparseOverscaled =
type == SourceType::Vector ||
type == SourceType::Annotations;

if (z < info->minZoom) return {{}};
if (z > info->maxZoom) z = info->maxZoom;

// Map four viewport corners to pixel coordinates
box points = state.cornersToBox(z);
const TileCoordinate center = state.pointToCoordinate({ state.getWidth() / 2.0f, state.getHeight()/ 2.0f }).zoomTo(z);

std::forward_list<TileID> covering_tiles = tileCover(z, points, reparseOverscaled ? actualZ : z);

covering_tiles.sort([&center](const TileID& a, const TileID& b) {
// Sorts by distance from the box center
return std::fabs(a.x - center.column) + std::fabs(a.y - center.row) <
std::fabs(b.x - center.column) + std::fabs(b.y - center.row);
});

return covering_tiles;
}

/**
* Recursively find children of the given tile that are already loaded.
*
Expand All @@ -352,14 +309,14 @@ std::forward_list<TileID> Source::coveringTiles(const TransformState& state) con
*
* @return boolean Whether the children found completely cover the tile.
*/
bool Source::findLoadedChildren(const TileID& tileID, int32_t maxCoveringZoom, std::forward_list<TileID>& retain) {
bool Source::findLoadedChildren(const TileID& tileID, int32_t maxCoveringZoom, std::vector<TileID>& retain) {
bool complete = true;
int32_t z = tileID.z;
auto ids = tileID.children(info->maxZoom);
for (const auto& child_id : ids) {
const TileData::State state = hasTile(child_id);
if (TileData::isReadyState(state)) {
retain.emplace_front(child_id);
retain.emplace_back(child_id);
}
if (state != TileData::State::parsed) {
complete = false;
Expand All @@ -381,12 +338,12 @@ bool Source::findLoadedChildren(const TileID& tileID, int32_t maxCoveringZoom, s
*
* @return boolean Whether a parent was found.
*/
void Source::findLoadedParent(const TileID& tileID, int32_t minCoveringZoom, std::forward_list<TileID>& retain) {
void Source::findLoadedParent(const TileID& tileID, int32_t minCoveringZoom, std::vector<TileID>& retain) {
for (int32_t z = tileID.z - 1; z >= minCoveringZoom; --z) {
const TileID parent_id = tileID.parent(z, info->maxZoom);
const TileData::State state = hasTile(parent_id);
if (TileData::isReadyState(state)) {
retain.emplace_front(parent_id);
retain.emplace_back(parent_id);
if (state == TileData::State::parsed) {
return;
}
Expand All @@ -401,17 +358,29 @@ bool Source::update(const StyleUpdateParameters& parameters) {
return allTilesUpdated;
}

double zoom = coveringZoomLevel(parameters.transformState);
std::forward_list<TileID> required = coveringTiles(parameters.transformState);

// Determine the overzooming/underzooming amounts.
// Determine the overzooming/underzooming amounts and required tiles.
std::vector<TileID> required;
int32_t zoom = coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize);
int32_t minCoveringZoom = util::clamp<int32_t>(zoom - 10, info->minZoom, info->maxZoom);
int32_t maxCoveringZoom = util::clamp<int32_t>(zoom + 1, info->minZoom, info->maxZoom);

if (zoom >= info->minZoom) {
const bool reparseOverscaled =
type == SourceType::Vector ||
type == SourceType::Annotations;

const auto actualZ = zoom;
if (zoom > info->maxZoom) {
zoom = info->maxZoom;
}

required = tileCover(parameters.transformState, zoom, reparseOverscaled ? actualZ : zoom);
}

// Retain is a list of tiles that we shouldn't delete, even if they are not
// the most ideal tile for the current viewport. This may include tiles like
// parent or child tiles that are *already* loaded.
std::forward_list<TileID> retain(required);
std::vector<TileID> retain(required);

// Add existing child/parent tiles if the actual tile is not yet loaded
for (const auto& tileID : required) {
Expand Down
10 changes: 3 additions & 7 deletions src/mbgl/map/source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/rapidjson.hpp>

#include <forward_list>
#include <vector>
#include <map>

namespace mapbox {
Expand Down Expand Up @@ -83,17 +83,13 @@ class Source : private util::noncopyable {
std::exception_ptr,
bool isNewTile);
bool handlePartialTile(const TileID&);
bool findLoadedChildren(const TileID&, int32_t maxCoveringZoom, std::forward_list<TileID>& retain);
void findLoadedParent(const TileID&, int32_t minCoveringZoom, std::forward_list<TileID>& retain);
int32_t coveringZoomLevel(const TransformState&) const;
std::forward_list<TileID> coveringTiles(const TransformState&) const;
bool findLoadedChildren(const TileID&, int32_t maxCoveringZoom, std::vector<TileID>& retain);
void findLoadedParent(const TileID&, int32_t minCoveringZoom, std::vector<TileID>& retain);

TileData::State addTile(const TileID&, const StyleUpdateParameters&);
TileData::State hasTile(const TileID&);
void updateTilePtrs();

double getZoom(const TransformState &state) const;

private:
std::unique_ptr<const SourceInfo> info;

Expand Down
19 changes: 12 additions & 7 deletions src/mbgl/map/tile_id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ class TileID {
return ((std::pow(2, z) * y + x) * 32) + z;
}

struct Hash {
std::size_t operator()(const TileID& id) const {
return std::hash<uint64_t>()(id.to_uint64());
}
};

inline bool operator==(const TileID& rhs) const {
return w == rhs.w && z == rhs.z && x == rhs.x && y == rhs.y;
}
Expand All @@ -51,9 +45,20 @@ class TileID {
std::forward_list<TileID> children(int8_t sourceMaxZoom) const;
bool isChildOf(const TileID&) const;
operator std::string() const;

};

} // namespace mbgl

namespace std {
template <>
struct hash<mbgl::TileID> {
typedef mbgl::TileID argument_type;
typedef std::size_t result_type;

result_type operator()(const mbgl::TileID& id) const {
return std::hash<uint64_t>()(id.to_uint64());
}
};
} // namespace std

#endif
13 changes: 0 additions & 13 deletions src/mbgl/map/transform_state.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <mbgl/map/transform_state.hpp>
#include <mbgl/map/tile_id.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/box.hpp>
#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/util/math.hpp>
Expand Down Expand Up @@ -54,18 +53,6 @@ void TransformState::getProjMatrix(mat4& projMatrix) const {
pixel_y() - getHeight() / 2.0f, 0);
}

box TransformState::cornersToBox(uint32_t z) const {
double w = width;
double h = height;
box b(
pointToCoordinate({ 0, 0 }).zoomTo(z),
pointToCoordinate({ w, 0 }).zoomTo(z),
pointToCoordinate({ w, h }).zoomTo(z),
pointToCoordinate({ 0, h }).zoomTo(z));
return b;
}


#pragma mark - Dimensions

uint16_t TransformState::getWidth() const {
Expand Down
4 changes: 1 addition & 3 deletions src/mbgl/map/transform_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
namespace mbgl {

class TileID;
struct box;
struct TileCoordinate;
class TileCoordinate;

class TransformState {
friend class Transform;
Expand All @@ -27,7 +26,6 @@ class TransformState {
// Matrix
void matrixFor(mat4& matrix, const TileID& id, const int8_t z) const;
void getProjMatrix(mat4& matrix) const;
box cornersToBox(uint32_t z) const;

// Dimensions
uint16_t getWidth() const;
Expand Down
16 changes: 0 additions & 16 deletions src/mbgl/util/box.hpp

This file was deleted.

16 changes: 2 additions & 14 deletions src/mbgl/util/tile_coordinate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,11 @@

namespace mbgl {

struct TileCoordinate {
class TileCoordinate {
public:
double column;
double row;
double zoom;

TileCoordinate(double column_, double row_, double zoom_) :
column(column_), row(row_), zoom(zoom_) {}

TileCoordinate zoomTo(double targetZoom) {
double scale = std::pow(2, targetZoom - zoom);
return { column * scale, row * scale, targetZoom };
}

TileCoordinate operator-(TileCoordinate c) {
c = c.zoomTo(zoom);
return { column - c.column, row - c.row, zoom };
};
};

} // namespace mbgl
Expand Down
76 changes: 69 additions & 7 deletions src/mbgl/util/tile_cover.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include <mbgl/util/tile_cover.hpp>
#include <mbgl/util/vec.hpp>
#include <mbgl/util/box.hpp>
#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/map/source_info.hpp>
#include <mbgl/map/transform_state.hpp>

namespace mbgl {

Expand Down Expand Up @@ -66,7 +68,27 @@ static void scanTriangle(const mbgl::vec2<double> a, const mbgl::vec2<double> b,
if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine);
}

std::forward_list<TileID> tileCover(int8_t z, const mbgl::box &bounds, int8_t actualZ) {
int32_t coveringZoomLevel(double zoom, SourceType type, uint16_t tileSize) {
zoom += std::log(util::tileSize / tileSize) / std::log(2);
if (type == SourceType::Raster || type == SourceType::Video) {
return ::round(zoom);
} else {
return std::floor(zoom);
}
}

static mbgl::vec2<double> zoomTo(const TileCoordinate& c, double z) {
double scale = std::pow(2, z - c.zoom);
return { c.column * scale, c.row * scale };
}

std::vector<TileID> tileCover(const TileCoordinate& tl_,
const TileCoordinate& tr_,
const TileCoordinate& br_,
const TileCoordinate& bl_,
const TileCoordinate& center,
int32_t z,
int32_t actualZ) {
int32_t tiles = 1 << z;
std::forward_list<mbgl::TileID> t;

Expand All @@ -79,10 +101,11 @@ std::forward_list<TileID> tileCover(int8_t z, const mbgl::box &bounds, int8_t ac
}
};

mbgl::vec2<double> tl = { bounds.tl.column, bounds.tl.row };
mbgl::vec2<double> tr = { bounds.tr.column, bounds.tr.row };
mbgl::vec2<double> br = { bounds.br.column, bounds.br.row };
mbgl::vec2<double> bl = { bounds.bl.column, bounds.bl.row };
mbgl::vec2<double> tl = zoomTo(tl_, z);
mbgl::vec2<double> tr = zoomTo(tr_, z);
mbgl::vec2<double> br = zoomTo(br_, z);
mbgl::vec2<double> bl = zoomTo(bl_, z);
mbgl::vec2<double> c = zoomTo(center, z);

// Divide the screen up in two triangles and scan each of them:
// \---+
Expand All @@ -94,7 +117,46 @@ std::forward_list<TileID> tileCover(int8_t z, const mbgl::box &bounds, int8_t ac
t.sort();
t.unique();

return t;
t.sort([&](const TileID& a, const TileID& b) {
// Sorts by distance from the box center
return std::fabs(a.x - c.x) + std::fabs(a.y - c.y) <
std::fabs(b.x - c.x) + std::fabs(b.y - c.y);
});

return std::vector<TileID>(t.begin(), t.end());
}

std::vector<TileID> tileCover(const LatLngBounds& bounds_, int32_t z, int32_t actualZ) {
if (bounds_.isEmpty() ||
bounds_.south() > util::LATITUDE_MAX ||
bounds_.north() < -util::LATITUDE_MAX) {
return {};
}

LatLngBounds bounds = LatLngBounds::hull(
{ std::max(bounds_.south(), -util::LATITUDE_MAX), bounds_.west() },
{ std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });

const TransformState state;
return tileCover(
state.latLngToCoordinate(bounds.northwest()),
state.latLngToCoordinate(bounds.northeast()),
state.latLngToCoordinate(bounds.southeast()),
state.latLngToCoordinate(bounds.southwest()),
state.latLngToCoordinate(bounds.center()),
z, actualZ);
}

std::vector<TileID> tileCover(const TransformState& state, int32_t z, int32_t actualZ) {
const double w = state.getWidth();
const double h = state.getHeight();
return tileCover(
state.pointToCoordinate({ 0, 0 }),
state.pointToCoordinate({ w, 0 }),
state.pointToCoordinate({ w, h }),
state.pointToCoordinate({ 0, h }),
state.pointToCoordinate({ w/2, h/2 }),
z, actualZ);
}

} // namespace mbgl
Loading