@@ -30,7 +30,6 @@ class LayerDescription;
|
||||
class Sprite;
|
||||
class Style;
|
||||
class StyleLayer;
|
||||
class StyleSource;
|
||||
class TexturePool;
|
||||
class FileSource;
|
||||
class View;
|
||||
@@ -175,7 +174,6 @@ private:
|
||||
void setup();
|
||||
|
||||
void updateTiles();
|
||||
void updateSources();
|
||||
|
||||
// Triggered by triggerUpdate();
|
||||
void update();
|
||||
@@ -194,7 +192,7 @@ private:
|
||||
|
||||
void processTasks();
|
||||
|
||||
void updateAnnotationTiles(const std::vector<Tile::ID>&);
|
||||
void updateAnnotationTiles(const std::vector<TileID>&);
|
||||
|
||||
enum class Mode : uint8_t {
|
||||
None, // we're not doing any processing
|
||||
@@ -249,8 +247,6 @@ private:
|
||||
|
||||
const std::unique_ptr<MapData> data;
|
||||
|
||||
std::set<util::ptr<StyleSource>> activeSources;
|
||||
|
||||
std::atomic<UpdateType> updated;
|
||||
|
||||
std::mutex mutexTask;
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
#ifndef MBGL_MAP_TILE
|
||||
#define MBGL_MAP_TILE
|
||||
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class TileData;
|
||||
struct box;
|
||||
|
||||
struct ClipID {
|
||||
inline ClipID() {}
|
||||
inline ClipID(const std::string &mask_, const std::string &reference_) : mask(mask_), reference(reference_) {}
|
||||
|
||||
std::bitset<8> mask;
|
||||
std::bitset<8> reference;
|
||||
|
||||
inline bool operator==(const ClipID &other) const {
|
||||
return mask == other.mask && reference == other.reference;
|
||||
}
|
||||
};
|
||||
|
||||
class Tile : private util::noncopyable {
|
||||
public:
|
||||
struct ID {
|
||||
const int16_t w = 0;
|
||||
const int8_t z = 0;
|
||||
const int32_t x = 0, y = 0;
|
||||
|
||||
inline explicit ID(int8_t z_, int32_t x_, int32_t y_)
|
||||
: w((x_ < 0 ? x_ - (1 << z_) + 1 : x_) / (1 << z_)), z(z_), x(x_), y(y_) {}
|
||||
|
||||
inline uint64_t to_uint64() const {
|
||||
return ((std::pow(2, z) * y + x) * 32) + z;
|
||||
}
|
||||
|
||||
struct Hash {
|
||||
std::size_t operator()(ID const& i) const {
|
||||
return std::hash<uint64_t>()(i.to_uint64());
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const ID& rhs) const {
|
||||
return w == rhs.w && z == rhs.z && x == rhs.x && y == rhs.y;
|
||||
}
|
||||
|
||||
inline bool operator!=(const ID& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
inline bool operator<(const ID &rhs) const {
|
||||
if (w != rhs.w) return w < rhs.w;
|
||||
if (z != rhs.z) return z < rhs.z;
|
||||
if (x != rhs.x) return x < rhs.x;
|
||||
return y < rhs.y;
|
||||
}
|
||||
|
||||
ID parent(int8_t z) const;
|
||||
ID normalized() const;
|
||||
std::forward_list<ID> children(int32_t z) const;
|
||||
bool isChildOf(const Tile::ID &id) const;
|
||||
operator std::string() const;
|
||||
};
|
||||
|
||||
static std::forward_list<Tile::ID> cover(int8_t z, const box& bounds);
|
||||
|
||||
public:
|
||||
explicit Tile(const ID& id);
|
||||
|
||||
public:
|
||||
const Tile::ID id;
|
||||
ClipID clip;
|
||||
mat4 matrix;
|
||||
util::ptr<TileData> data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,6 @@
|
||||
#ifndef MBGL_MAP_TRANSFORM_STATE
|
||||
#define MBGL_MAP_TRANSFORM_STATE
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
@@ -13,12 +11,15 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class TileID;
|
||||
struct box;
|
||||
|
||||
class TransformState {
|
||||
friend class Transform;
|
||||
|
||||
public:
|
||||
// Matrix
|
||||
void matrixFor(mat4& matrix, const Tile::ID& id) const;
|
||||
void matrixFor(mat4& matrix, const TileID& id) const;
|
||||
box cornersToBox(uint32_t z) const;
|
||||
|
||||
// Dimensions
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <mbgl/map/annotation.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/map/live_tile.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
@@ -29,7 +30,7 @@ private:
|
||||
private:
|
||||
const AnnotationType type = AnnotationType::Point;
|
||||
const AnnotationSegments geometry;
|
||||
std::unordered_map<Tile::ID, std::weak_ptr<const LiveTileFeature>, Tile::ID::Hash> tileFeatures;
|
||||
std::unordered_map<TileID, std::weak_ptr<const LiveTileFeature>, TileID::Hash> tileFeatures;
|
||||
const LatLngBounds bounds;
|
||||
};
|
||||
|
||||
@@ -82,7 +83,7 @@ vec2<double> AnnotationManager::projectPoint(const LatLng& point) {
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
std::pair<std::vector<Tile::ID>, AnnotationIDs> AnnotationManager::addPointAnnotations(
|
||||
std::pair<std::vector<TileID>, AnnotationIDs> AnnotationManager::addPointAnnotations(
|
||||
const std::vector<LatLng>& points, const std::vector<std::string>& symbols, const Map& map) {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
|
||||
@@ -97,7 +98,7 @@ std::pair<std::vector<Tile::ID>, AnnotationIDs> AnnotationManager::addPointAnnot
|
||||
std::vector<uint32_t> annotationIDs;
|
||||
annotationIDs.reserve(points.size());
|
||||
|
||||
std::vector<Tile::ID> affectedTiles;
|
||||
std::vector<TileID> affectedTiles;
|
||||
|
||||
for (size_t i = 0; i < points.size(); ++i) {
|
||||
const uint32_t annotationID = nextID();
|
||||
@@ -121,7 +122,7 @@ std::pair<std::vector<Tile::ID>, AnnotationIDs> AnnotationManager::addPointAnnot
|
||||
|
||||
for (int8_t z = maxZoom; z >= 0; z--) {
|
||||
affectedTiles.emplace_back(z, x, y);
|
||||
Tile::ID tileID = affectedTiles.back();
|
||||
TileID tileID = affectedTiles.back();
|
||||
|
||||
// calculate tile coordinate
|
||||
const Coordinate coordinate(extent * (p.x * z2 - x), extent * (p.y * z2 - y));
|
||||
@@ -180,10 +181,10 @@ std::pair<std::vector<Tile::ID>, AnnotationIDs> AnnotationManager::addPointAnnot
|
||||
return std::make_pair(affectedTiles, annotationIDs);
|
||||
}
|
||||
|
||||
std::vector<Tile::ID> AnnotationManager::removeAnnotations(const AnnotationIDs& ids, const Map& map) {
|
||||
std::vector<TileID> AnnotationManager::removeAnnotations(const AnnotationIDs& ids, const Map& map) {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
|
||||
std::vector<Tile::ID> affectedTiles;
|
||||
std::vector<TileID> affectedTiles;
|
||||
|
||||
std::vector<uint32_t> z2s;
|
||||
uint8_t zoomCount = map.getMaxZoom() + 1;
|
||||
@@ -208,7 +209,7 @@ std::vector<Tile::ID> AnnotationManager::removeAnnotations(const AnnotationIDs&
|
||||
p = projectPoint(latLng);
|
||||
x = z2s[z] * p.x;
|
||||
y = z2s[z] * p.y;
|
||||
Tile::ID tid(z, x, y);
|
||||
TileID tid(z, x, y);
|
||||
// erase annotation from tile's list
|
||||
auto& tileAnnotations = tiles[tid].first;
|
||||
tileAnnotations.erase(annotationID);
|
||||
@@ -225,7 +226,7 @@ std::vector<Tile::ID> AnnotationManager::removeAnnotations(const AnnotationIDs&
|
||||
}
|
||||
}
|
||||
|
||||
// Tile::IDs for tiles that need refreshed.
|
||||
// TileIDs for tiles that need refreshed.
|
||||
return affectedTiles;
|
||||
}
|
||||
|
||||
@@ -239,13 +240,13 @@ std::vector<uint32_t> AnnotationManager::getAnnotationsInBounds(const LatLngBoun
|
||||
const vec2<double> nePoint = projectPoint(queryBounds.ne);
|
||||
|
||||
// tiles number y from top down
|
||||
const Tile::ID nwTile(z, swPoint.x * z2, nePoint.y * z2);
|
||||
const Tile::ID seTile(z, nePoint.x * z2, swPoint.y * z2);
|
||||
const TileID nwTile(z, swPoint.x * z2, nePoint.y * z2);
|
||||
const TileID seTile(z, nePoint.x * z2, swPoint.y * z2);
|
||||
|
||||
std::vector<uint32_t> matchingAnnotations;
|
||||
|
||||
for (auto& tile : tiles) {
|
||||
Tile::ID id = tile.first;
|
||||
TileID id = tile.first;
|
||||
if (id.z == z) {
|
||||
if (id.x >= nwTile.x && id.x <= seTile.x && id.y >= nwTile.y && id.y <= seTile.y) {
|
||||
if (id.x > nwTile.x && id.x < seTile.x && id.y > nwTile.y && id.y < seTile.y) {
|
||||
@@ -292,7 +293,7 @@ LatLngBounds AnnotationManager::getBoundsForAnnotations(const AnnotationIDs& ids
|
||||
return bounds;
|
||||
}
|
||||
|
||||
const LiveTile* AnnotationManager::getTile(Tile::ID const& id) {
|
||||
const LiveTile* AnnotationManager::getTile(const TileID& id) {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
|
||||
const auto tile_it = tiles.find(id);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef MBGL_MAP_ANNOTATIONS
|
||||
#define MBGL_MAP_ANNOTATIONS
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
@@ -28,13 +28,13 @@ public:
|
||||
~AnnotationManager();
|
||||
|
||||
void setDefaultPointAnnotationSymbol(const std::string& symbol);
|
||||
std::pair<std::vector<Tile::ID>, AnnotationIDs> addPointAnnotations(
|
||||
std::pair<std::vector<TileID>, AnnotationIDs> addPointAnnotations(
|
||||
const std::vector<LatLng>&, const std::vector<std::string>& symbols, const Map&);
|
||||
std::vector<Tile::ID> removeAnnotations(const AnnotationIDs&, const Map&);
|
||||
std::vector<TileID> removeAnnotations(const AnnotationIDs&, const Map&);
|
||||
AnnotationIDs getAnnotationsInBounds(const LatLngBounds&, const Map&) const;
|
||||
LatLngBounds getBoundsForAnnotations(const AnnotationIDs&) const;
|
||||
|
||||
const LiveTile* getTile(Tile::ID const& id);
|
||||
const LiveTile* getTile(const TileID& id);
|
||||
|
||||
static const std::string layerID;
|
||||
|
||||
@@ -46,7 +46,7 @@ private:
|
||||
mutable std::mutex mtx;
|
||||
std::string defaultPointAnnotationSymbol;
|
||||
std::unordered_map<uint32_t, std::unique_ptr<Annotation>> annotations;
|
||||
std::unordered_map<Tile::ID, std::pair<std::unordered_set<uint32_t>, std::unique_ptr<LiveTile>>, Tile::ID::Hash> tiles;
|
||||
std::unordered_map<TileID, std::pair<std::unordered_set<uint32_t>, std::unique_ptr<LiveTile>>, TileID::Hash> tiles;
|
||||
uint32_t nextID_ = 0;
|
||||
};
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
#include <mbgl/map/live_tile_data.hpp>
|
||||
#include <mbgl/map/live_tile.hpp>
|
||||
#include <mbgl/map/tile_parser.hpp>
|
||||
#include <mbgl/style/style_source.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/vector_tile.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
LiveTileData::LiveTileData(Tile::ID const& id_,
|
||||
LiveTileData::LiveTileData(const TileID& id_,
|
||||
AnnotationManager& annotationManager_,
|
||||
float mapMaxZoom,
|
||||
util::ptr<Style> style_,
|
||||
@@ -36,24 +36,19 @@ void LiveTileData::parse() {
|
||||
throw std::runtime_error("style isn't present in LiveTileData object anymore");
|
||||
}
|
||||
|
||||
if (source.type == SourceType::Annotations) {
|
||||
const LiveTile* tile = annotationManager.getTile(id);
|
||||
const LiveTile* tile = annotationManager.getTile(id);
|
||||
if (tile) {
|
||||
// Parsing creates state that is encapsulated in TileParser. While parsing,
|
||||
// the TileParser object writes results into this objects. All other state
|
||||
// is going to be discarded afterwards.
|
||||
TileParser parser(*tile, *this, style, glyphAtlas, glyphStore, spriteAtlas, sprite);
|
||||
|
||||
if (tile) {
|
||||
// Parsing creates state that is encapsulated in TileParser. While parsing,
|
||||
// the TileParser object writes results into this objects. All other state
|
||||
// is going to be discarded afterwards.
|
||||
TileParser parser(*tile, *this, style, glyphAtlas, glyphStore, spriteAtlas, sprite);
|
||||
// Clear the style so that we don't have a cycle in the shared_ptr references.
|
||||
style.reset();
|
||||
|
||||
// Clear the style so that we don't have a cycle in the shared_ptr references.
|
||||
style.reset();
|
||||
|
||||
parser.parse();
|
||||
} else {
|
||||
state = State::obsolete;
|
||||
}
|
||||
parser.parse();
|
||||
} else {
|
||||
throw std::runtime_error("unknown live tile source type");
|
||||
state = State::obsolete;
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
Log::Error(Event::ParseTile, "Live-parsing [%d/%d/%d] failed: %s", id.z, id.x, id.y, ex.what());
|
||||
|
||||
@@ -9,7 +9,7 @@ class AnnotationManager;
|
||||
|
||||
class LiveTileData : public VectorTileData {
|
||||
public:
|
||||
LiveTileData(Tile::ID const&,
|
||||
LiveTileData(const TileID&,
|
||||
AnnotationManager&,
|
||||
float mapMaxZoom,
|
||||
util::ptr<Style>,
|
||||
|
||||
@@ -90,7 +90,6 @@ Map::~Map() {
|
||||
"MapandMain");
|
||||
|
||||
// Explicitly reset all pointers.
|
||||
activeSources.clear();
|
||||
sprite.reset();
|
||||
glyphStore.reset();
|
||||
style.reset();
|
||||
@@ -129,11 +128,6 @@ void Map::start(bool startPaused) {
|
||||
// Remove all of these to make sure they are destructed in the correct thread.
|
||||
style.reset();
|
||||
|
||||
// Since we don't have a stylesheet anymore, this will disable all Sources and cancel
|
||||
// their associated requests.
|
||||
updateSources();
|
||||
assert(activeSources.empty());
|
||||
|
||||
// It's now safe to destroy/join the workers since there won't be any more callbacks that
|
||||
// could dispatch to the worker pool.
|
||||
workers.reset();
|
||||
@@ -622,14 +616,15 @@ LatLngBounds Map::getBoundsForAnnotations(const std::vector<uint32_t>& annotatio
|
||||
});
|
||||
}
|
||||
|
||||
void Map::updateAnnotationTiles(const std::vector<Tile::ID>& ids) {
|
||||
void Map::updateAnnotationTiles(const std::vector<TileID>& ids) {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
for (const auto &source : activeSources) {
|
||||
if (!style) return;
|
||||
for (const auto &source : style->sources) {
|
||||
if (source->info.type == SourceType::Annotations) {
|
||||
source->source->invalidateTiles(*this, ids);
|
||||
return;
|
||||
source->invalidateTiles(ids);
|
||||
}
|
||||
}
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
#pragma mark - Toggles
|
||||
@@ -689,45 +684,11 @@ Duration Map::getDefaultTransitionDuration() {
|
||||
return data->getDefaultTransitionDuration();
|
||||
}
|
||||
|
||||
void Map::updateSources() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
// First, disable all existing sources.
|
||||
for (const auto& source : activeSources) {
|
||||
source->enabled = false;
|
||||
}
|
||||
|
||||
// Then, reenable all of those that we actually use when drawing this layer.
|
||||
if (style) {
|
||||
for (const auto& layer : style->layers) {
|
||||
if (layer->bucket && layer->bucket->style_source) {
|
||||
(*activeSources.emplace(layer->bucket->style_source).first)->enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then, construct or destroy the actual source object, depending on enabled state.
|
||||
for (const auto& source : activeSources) {
|
||||
if (source->enabled) {
|
||||
if (!source->source) {
|
||||
source->source = std::make_shared<Source>(source->info);
|
||||
source->source->load(*this, *env);
|
||||
}
|
||||
} else {
|
||||
source->source.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, remove all sources that are disabled.
|
||||
util::erase_if(activeSources, [](util::ptr<StyleSource> source){
|
||||
return !source->enabled;
|
||||
});
|
||||
}
|
||||
|
||||
void Map::updateTiles() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
for (const auto& source : activeSources) {
|
||||
source->source->update(*this, getWorker(), style, *glyphAtlas, *glyphStore,
|
||||
if (!style) return;
|
||||
for (const auto& source : style->sources) {
|
||||
source->update(*this, getWorker(), style, *glyphAtlas, *glyphStore,
|
||||
*spriteAtlas, getSprite(), *texturePool, [this]() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
triggerUpdate();
|
||||
@@ -779,6 +740,13 @@ void Map::loadStyleJSON(const std::string& json, const std::string& base) {
|
||||
const std::string glyphURL = util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken());
|
||||
glyphStore->setURL(glyphURL);
|
||||
|
||||
for (const auto& source : style->sources) {
|
||||
source->load(getAccessToken(), *env, [this]() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
triggerUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
triggerUpdate(Update::Zoom);
|
||||
}
|
||||
|
||||
@@ -821,8 +789,6 @@ void Map::prepare() {
|
||||
style->recalculate(state.getNormalizedZoom(), now);
|
||||
}
|
||||
|
||||
updateSources();
|
||||
|
||||
// Allow the sprite atlas to potentially pull new sprite images if needed.
|
||||
spriteAtlas->resize(state.getPixelRatio());
|
||||
spriteAtlas->setSprite(getSprite());
|
||||
@@ -843,8 +809,8 @@ void Map::render() {
|
||||
|
||||
assert(style);
|
||||
assert(painter);
|
||||
painter->render(*style, activeSources,
|
||||
state, data->getAnimationTime());
|
||||
|
||||
painter->render(*style, state, data->getAnimationTime());
|
||||
|
||||
// Schedule another rerender when we definitely need a next frame.
|
||||
if (transform.needsTransition() || style->hasTransitions()) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
RasterTileData::RasterTileData(Tile::ID const &id_, TexturePool &texturePool,
|
||||
RasterTileData::RasterTileData(const TileID& id_, TexturePool &texturePool,
|
||||
const SourceInfo &source_)
|
||||
: TileData(id_, source_), bucket(texturePool, layout) {
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef MBGL_MAP_RASTER_TILE_DATA
|
||||
#define MBGL_MAP_RASTER_TILE_DATA
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/tile_data.hpp>
|
||||
#include <mbgl/style/style_layout.hpp>
|
||||
#include <mbgl/renderer/raster_bucket.hpp>
|
||||
@@ -17,7 +16,7 @@ class RasterTileData : public TileData {
|
||||
friend class TileParser;
|
||||
|
||||
public:
|
||||
RasterTileData(Tile::ID const &id, TexturePool &, const SourceInfo &);
|
||||
RasterTileData(const TileID&, TexturePool&, const SourceInfo&);
|
||||
~RasterTileData();
|
||||
|
||||
void parse() override;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/environment.hpp>
|
||||
#include <mbgl/map/transform.hpp>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/renderer/painter.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/raster.hpp>
|
||||
@@ -18,6 +19,8 @@
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
#include <mbgl/util/token.hpp>
|
||||
#include <mbgl/util/tile_cover.hpp>
|
||||
|
||||
#include <mbgl/map/vector_tile_data.hpp>
|
||||
#include <mbgl/map/raster_tile_data.hpp>
|
||||
@@ -27,15 +30,105 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
Source::Source(SourceInfo& info_)
|
||||
: info(info_)
|
||||
void parse(const rapidjson::Value& value, std::vector<std::string>& target, const char *name) {
|
||||
if (!value.HasMember(name))
|
||||
return;
|
||||
|
||||
const rapidjson::Value& property = value[name];
|
||||
if (!property.IsArray())
|
||||
return;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++)
|
||||
if (!property[i].IsString())
|
||||
return;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++)
|
||||
target.emplace_back(std::string(property[i].GetString(), property[i].GetStringLength()));
|
||||
}
|
||||
|
||||
void parse(const rapidjson::Value& value, std::string& target, const char* name) {
|
||||
if (!value.HasMember(name))
|
||||
return;
|
||||
|
||||
const rapidjson::Value& property = value[name];
|
||||
if (!property.IsString())
|
||||
return;
|
||||
|
||||
target = { property.GetString(), property.GetStringLength() };
|
||||
}
|
||||
|
||||
void parse(const rapidjson::Value& value, uint16_t& target, const char* name) {
|
||||
if (!value.HasMember(name))
|
||||
return;
|
||||
|
||||
const rapidjson::Value& property = value[name];
|
||||
if (!property.IsUint())
|
||||
return;
|
||||
|
||||
unsigned int uint = property.GetUint();
|
||||
if (uint > std::numeric_limits<uint16_t>::max())
|
||||
return;
|
||||
|
||||
target = uint;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void parse(const rapidjson::Value& value, std::array<float, N>& target, const char* name) {
|
||||
if (!value.HasMember(name))
|
||||
return;
|
||||
|
||||
const rapidjson::Value& property = value[name];
|
||||
if (!property.IsArray() || property.Size() != N)
|
||||
return;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++)
|
||||
if (!property[i].IsNumber())
|
||||
return;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++)
|
||||
target[i] = property[i].GetDouble();
|
||||
}
|
||||
|
||||
void SourceInfo::parseTileJSONProperties(const rapidjson::Value& value) {
|
||||
parse(value, tiles, "tiles");
|
||||
parse(value, min_zoom, "minzoom");
|
||||
parse(value, max_zoom, "maxzoom");
|
||||
parse(value, attribution, "attribution");
|
||||
parse(value, center, "center");
|
||||
parse(value, bounds, "bounds");
|
||||
}
|
||||
|
||||
std::string SourceInfo::tileURL(const TileID& id, float pixelRatio) const {
|
||||
std::string result = tiles.at((id.x + id.y) % tiles.size());
|
||||
result = util::mapbox::normalizeTileURL(result, url, type);
|
||||
result = util::replaceTokens(result, [&](const std::string &token) -> std::string {
|
||||
if (token == "z") return util::toString(id.z);
|
||||
if (token == "x") return util::toString(id.x);
|
||||
if (token == "y") return util::toString(id.y);
|
||||
if (token == "prefix") {
|
||||
std::string prefix { 2 };
|
||||
prefix[0] = "0123456789abcdef"[id.x % 16];
|
||||
prefix[1] = "0123456789abcdef"[id.y % 16];
|
||||
return prefix;
|
||||
}
|
||||
if (token == "ratio") return pixelRatio > 1.0 ? "@2x" : "";
|
||||
return "";
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
Source::Source()
|
||||
{
|
||||
}
|
||||
|
||||
Source::~Source() {}
|
||||
|
||||
// Note: This is a separate function that must be called exactly once after creation
|
||||
// The reason this isn't part of the constructor is that calling shared_from_this() in
|
||||
// the constructor fails.
|
||||
void Source::load(Map &map, Environment &env) {
|
||||
void Source::load(const std::string& accessToken,
|
||||
Environment& env,
|
||||
std::function<void()> callback) {
|
||||
if (info.url.empty()) {
|
||||
loaded = true;
|
||||
return;
|
||||
@@ -43,8 +136,8 @@ void Source::load(Map &map, Environment &env) {
|
||||
|
||||
util::ptr<Source> source = shared_from_this();
|
||||
|
||||
const std::string url = util::mapbox::normalizeSourceURL(info.url, map.getAccessToken());
|
||||
env.request({ Resource::Kind::JSON, url }, [source, &map](const Response &res) {
|
||||
const std::string url = util::mapbox::normalizeSourceURL(info.url, accessToken);
|
||||
env.request({ Resource::Kind::JSON, url }, [source, callback](const Response &res) {
|
||||
if (res.status != Response::Successful) {
|
||||
Log::Warning(Event::General, "Failed to load source TileJSON: %s", res.message.c_str());
|
||||
return;
|
||||
@@ -61,19 +154,7 @@ void Source::load(Map &map, Environment &env) {
|
||||
source->info.parseTileJSONProperties(d);
|
||||
source->loaded = true;
|
||||
|
||||
map.triggerUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
void Source::updateClipIDs(const std::map<Tile::ID, ClipID> &mapping) {
|
||||
std::for_each(tiles.begin(), tiles.end(), [&mapping](std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair) {
|
||||
Tile &tile = *pair.second;
|
||||
auto it = mapping.find(tile.id);
|
||||
if (it != mapping.end()) {
|
||||
tile.clip = it->second;
|
||||
} else {
|
||||
tile.clip = ClipID {};
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,10 +166,6 @@ void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transf
|
||||
}
|
||||
}
|
||||
|
||||
size_t Source::getTileCount() const {
|
||||
return tiles.size();
|
||||
}
|
||||
|
||||
void Source::drawClippingMasks(Painter &painter) {
|
||||
for (const auto& pair : tiles) {
|
||||
Tile &tile = *pair.second;
|
||||
@@ -114,16 +191,6 @@ void Source::finishRender(Painter &painter) {
|
||||
}
|
||||
}
|
||||
|
||||
std::forward_list<Tile::ID> Source::getIDs() const {
|
||||
std::forward_list<Tile::ID> ptrs;
|
||||
|
||||
std::transform(tiles.begin(), tiles.end(), std::front_inserter(ptrs), [](const std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair) {
|
||||
Tile &tile = *pair.second;
|
||||
return tile.id;
|
||||
});
|
||||
return ptrs;
|
||||
}
|
||||
|
||||
std::forward_list<Tile *> Source::getLoadedTiles() const {
|
||||
std::forward_list<Tile *> ptrs;
|
||||
auto it = ptrs.before_begin();
|
||||
@@ -136,7 +203,7 @@ std::forward_list<Tile *> Source::getLoadedTiles() const {
|
||||
}
|
||||
|
||||
|
||||
TileData::State Source::hasTile(const Tile::ID& id) {
|
||||
TileData::State Source::hasTile(const TileID& id) {
|
||||
auto it = tiles.find(id);
|
||||
if (it != tiles.end()) {
|
||||
Tile &tile = *it->second;
|
||||
@@ -152,7 +219,7 @@ TileData::State Source::addTile(Map &map, uv::worker &worker,
|
||||
util::ptr<Style> style, GlyphAtlas &glyphAtlas,
|
||||
GlyphStore &glyphStore, SpriteAtlas &spriteAtlas,
|
||||
util::ptr<Sprite> sprite, TexturePool &texturePool,
|
||||
const Tile::ID &id, std::function<void()> callback) {
|
||||
const TileID &id, std::function<void()> callback) {
|
||||
const TileData::State state = hasTile(id);
|
||||
|
||||
if (state != TileData::State::invalid) {
|
||||
@@ -164,7 +231,7 @@ TileData::State Source::addTile(Map &map, uv::worker &worker,
|
||||
|
||||
// We couldn't find the tile in the list. Create a new one.
|
||||
// Try to find the associated TileData object.
|
||||
const Tile::ID normalized_id = id.normalized();
|
||||
const TileID normalized_id = id.normalized();
|
||||
|
||||
auto it = tile_data.find(normalized_id);
|
||||
if (it != tile_data.end()) {
|
||||
@@ -211,7 +278,7 @@ int32_t Source::coveringZoomLevel(const TransformState& state) const {
|
||||
return std::floor(getZoom(state));
|
||||
}
|
||||
|
||||
std::forward_list<Tile::ID> Source::coveringTiles(const TransformState& state) const {
|
||||
std::forward_list<TileID> Source::coveringTiles(const TransformState& state) const {
|
||||
int32_t z = coveringZoomLevel(state);
|
||||
|
||||
if (z < info.min_zoom) return {{}};
|
||||
@@ -221,9 +288,9 @@ std::forward_list<Tile::ID> Source::coveringTiles(const TransformState& state) c
|
||||
box points = state.cornersToBox(z);
|
||||
const vec2<double>& center = points.center;
|
||||
|
||||
std::forward_list<Tile::ID> covering_tiles = Tile::cover(z, points);
|
||||
std::forward_list<TileID> covering_tiles = tileCover(z, points);
|
||||
|
||||
covering_tiles.sort([¢er](const Tile::ID& a, const Tile::ID& b) {
|
||||
covering_tiles.sort([¢er](const TileID& a, const TileID& b) {
|
||||
// Sorts by distance from the box center
|
||||
return std::fabs(a.x - center.x) + std::fabs(a.y - center.y) <
|
||||
std::fabs(b.x - center.x) + std::fabs(b.y - center.y);
|
||||
@@ -241,7 +308,7 @@ std::forward_list<Tile::ID> Source::coveringTiles(const TransformState& state) c
|
||||
*
|
||||
* @return boolean Whether the children found completely cover the tile.
|
||||
*/
|
||||
bool Source::findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::forward_list<Tile::ID>& retain) {
|
||||
bool Source::findLoadedChildren(const TileID& id, int32_t maxCoveringZoom, std::forward_list<TileID>& retain) {
|
||||
bool complete = true;
|
||||
int32_t z = id.z;
|
||||
auto ids = id.children(z + 1);
|
||||
@@ -269,9 +336,9 @@ bool Source::findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std
|
||||
*
|
||||
* @return boolean Whether a parent was found.
|
||||
*/
|
||||
bool Source::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::forward_list<Tile::ID>& retain) {
|
||||
bool Source::findLoadedParent(const TileID& id, int32_t minCoveringZoom, std::forward_list<TileID>& retain) {
|
||||
for (int32_t z = id.z - 1; z >= minCoveringZoom; --z) {
|
||||
const Tile::ID parent_id = id.parent(z);
|
||||
const TileID parent_id = id.parent(z);
|
||||
const TileData::State state = hasTile(parent_id);
|
||||
if (state == TileData::State::parsed) {
|
||||
retain.emplace_front(parent_id);
|
||||
@@ -295,7 +362,7 @@ void Source::update(Map &map,
|
||||
}
|
||||
|
||||
int32_t zoom = std::floor(getZoom(map.getState()));
|
||||
std::forward_list<Tile::ID> required = coveringTiles(map.getState());
|
||||
std::forward_list<TileID> required = coveringTiles(map.getState());
|
||||
|
||||
// Determine the overzooming/underzooming amounts.
|
||||
int32_t minCoveringZoom = util::clamp<int32_t>(zoom - 10, info.min_zoom, info.max_zoom);
|
||||
@@ -304,7 +371,7 @@ void Source::update(Map &map,
|
||||
// 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<Tile::ID> retain(required);
|
||||
std::forward_list<TileID> retain(required);
|
||||
|
||||
// Add existing child/parent tiles if the actual tile is not yet loaded
|
||||
for (const auto& id : required) {
|
||||
@@ -329,8 +396,8 @@ void Source::update(Map &map,
|
||||
|
||||
// Remove tiles that we definitely don't need, i.e. tiles that are not on
|
||||
// the required list.
|
||||
std::set<Tile::ID> retain_data;
|
||||
util::erase_if(tiles, [&retain, &retain_data](std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair) {
|
||||
std::set<TileID> retain_data;
|
||||
util::erase_if(tiles, [&retain, &retain_data](std::pair<const TileID, std::unique_ptr<Tile>> &pair) {
|
||||
Tile &tile = *pair.second;
|
||||
bool obsolete = std::find(retain.begin(), retain.end(), tile.id) == retain.end();
|
||||
if (!obsolete) {
|
||||
@@ -340,7 +407,7 @@ void Source::update(Map &map,
|
||||
});
|
||||
|
||||
// Remove all the expired pointers from the set.
|
||||
util::erase_if(tile_data, [&retain_data](std::pair<const Tile::ID, std::weak_ptr<TileData>> &pair) {
|
||||
util::erase_if(tile_data, [&retain_data](std::pair<const TileID, std::weak_ptr<TileData>> &pair) {
|
||||
const util::ptr<TileData> tile = pair.second.lock();
|
||||
if (!tile) {
|
||||
return true;
|
||||
@@ -358,12 +425,11 @@ void Source::update(Map &map,
|
||||
updated = map.getTime();
|
||||
}
|
||||
|
||||
void Source::invalidateTiles(Map& map, const std::vector<Tile::ID>& ids) {
|
||||
void Source::invalidateTiles(const std::vector<TileID>& ids) {
|
||||
for (auto& id : ids) {
|
||||
tiles.erase(id);
|
||||
tile_data.erase(id);
|
||||
}
|
||||
map.triggerUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
#ifndef MBGL_MAP_SOURCE
|
||||
#define MBGL_MAP_SOURCE
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/map/tile_data.hpp>
|
||||
#include <mbgl/style/style_source.hpp>
|
||||
#include <mbgl/style/types.hpp>
|
||||
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
#include <iosfwd>
|
||||
@@ -28,49 +30,71 @@ class Style;
|
||||
class Painter;
|
||||
class StyleLayer;
|
||||
class TransformState;
|
||||
class Tile;
|
||||
struct ClipID;
|
||||
struct box;
|
||||
|
||||
class SourceInfo : private util::noncopyable {
|
||||
public:
|
||||
SourceType type = SourceType::Vector;
|
||||
std::string url;
|
||||
std::vector<std::string> tiles;
|
||||
uint16_t tile_size = 512;
|
||||
uint16_t min_zoom = 0;
|
||||
uint16_t max_zoom = 22;
|
||||
std::string attribution;
|
||||
std::array<float, 3> center = {{0, 0, 0}};
|
||||
std::array<float, 4> bounds = {{-180, -90, 180, 90}};
|
||||
|
||||
void parseTileJSONProperties(const rapidjson::Value&);
|
||||
std::string tileURL(const TileID& id, float pixelRatio) const;
|
||||
};
|
||||
|
||||
class Source : public std::enable_shared_from_this<Source>, private util::noncopyable {
|
||||
public:
|
||||
Source(SourceInfo&);
|
||||
Source();
|
||||
~Source();
|
||||
|
||||
void load(const std::string& accessToken,
|
||||
Environment&,
|
||||
std::function<void()> callback);
|
||||
|
||||
void load(Map &, Environment &);
|
||||
void update(Map &, uv::worker &, util::ptr<Style>, GlyphAtlas &, GlyphStore &,
|
||||
SpriteAtlas &, util::ptr<Sprite>, TexturePool &, std::function<void()> callback);
|
||||
void invalidateTiles(Map&, const std::vector<Tile::ID>&);
|
||||
|
||||
void invalidateTiles(const std::vector<TileID>&);
|
||||
|
||||
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
|
||||
void drawClippingMasks(Painter &painter);
|
||||
size_t getTileCount() const;
|
||||
void render(Painter &painter, const StyleLayer &layer_desc);
|
||||
void finishRender(Painter &painter);
|
||||
|
||||
std::forward_list<Tile::ID> getIDs() const;
|
||||
std::forward_list<Tile *> getLoadedTiles() const;
|
||||
void updateClipIDs(const std::map<Tile::ID, ClipID> &mapping);
|
||||
|
||||
SourceInfo info;
|
||||
bool enabled;
|
||||
|
||||
private:
|
||||
bool findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::forward_list<Tile::ID>& retain);
|
||||
bool findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::forward_list<Tile::ID>& retain);
|
||||
bool findLoadedChildren(const TileID& id, int32_t maxCoveringZoom, std::forward_list<TileID>& retain);
|
||||
bool findLoadedParent(const TileID& id, int32_t minCoveringZoom, std::forward_list<TileID>& retain);
|
||||
int32_t coveringZoomLevel(const TransformState&) const;
|
||||
std::forward_list<Tile::ID> coveringTiles(const TransformState&) const;
|
||||
std::forward_list<TileID> coveringTiles(const TransformState&) const;
|
||||
|
||||
TileData::State addTile(Map &, uv::worker &, util::ptr<Style>, GlyphAtlas &,
|
||||
GlyphStore &, SpriteAtlas &, util::ptr<Sprite>, TexturePool &,
|
||||
const Tile::ID &, std::function<void()> callback);
|
||||
const TileID &, std::function<void()> callback);
|
||||
|
||||
TileData::State hasTile(const Tile::ID& id);
|
||||
TileData::State hasTile(const TileID& id);
|
||||
|
||||
double getZoom(const TransformState &state) const;
|
||||
|
||||
SourceInfo& info;
|
||||
bool loaded = false;
|
||||
|
||||
// Stores the time when this source was most recently updated.
|
||||
TimePoint updated = TimePoint::min();
|
||||
|
||||
std::map<Tile::ID, std::unique_ptr<Tile>> tiles;
|
||||
std::map<Tile::ID, std::weak_ptr<TileData>> tile_data;
|
||||
std::map<TileID, std::unique_ptr<Tile>> tiles;
|
||||
std::map<TileID, std::weak_ptr<TileData>> tile_data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,147 +1,3 @@
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/box.hpp>
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
#include <iostream>
|
||||
|
||||
Tile::Tile(const ID& id_)
|
||||
: id(id_) {
|
||||
}
|
||||
|
||||
Tile::ID Tile::ID::parent(int8_t parent_z) const {
|
||||
assert(parent_z < z);
|
||||
int32_t dim = std::pow(2, z - parent_z);
|
||||
return Tile::ID{
|
||||
parent_z,
|
||||
(x >= 0 ? x : x - dim + 1) / dim,
|
||||
y / dim
|
||||
};
|
||||
}
|
||||
|
||||
std::forward_list<Tile::ID> Tile::ID::children(int32_t child_z) const {
|
||||
assert(child_z > z);
|
||||
int32_t factor = std::pow(2, child_z - z);
|
||||
|
||||
std::forward_list<ID> child_ids;
|
||||
for (int32_t ty = y * factor, y_max = (y + 1) * factor; ty < y_max; ++ty) {
|
||||
for (int32_t tx = x * factor, x_max = (x + 1) * factor; tx < x_max; ++tx) {
|
||||
child_ids.emplace_front(child_z, tx, ty);
|
||||
}
|
||||
}
|
||||
return child_ids;
|
||||
}
|
||||
|
||||
Tile::ID Tile::ID::normalized() const {
|
||||
int32_t dim = std::pow(2, z);
|
||||
int32_t nx = x, ny = y;
|
||||
while (nx < 0) nx += dim;
|
||||
while (nx >= dim) nx -= dim;
|
||||
return ID { z, nx, ny };
|
||||
}
|
||||
|
||||
bool Tile::ID::isChildOf(const Tile::ID &parent_id) const {
|
||||
if (parent_id.z >= z || parent_id.w != w) {
|
||||
return false;
|
||||
}
|
||||
int32_t scale = std::pow(2, z - parent_id.z);
|
||||
return parent_id.x == ((x < 0 ? x - scale + 1 : x) / scale) &&
|
||||
parent_id.y == y / scale;
|
||||
}
|
||||
|
||||
|
||||
Tile::ID::operator std::string() const {
|
||||
return util::toString(z) + "/" + util::toString(x) + "/" + util::toString(y);
|
||||
}
|
||||
|
||||
|
||||
// Taken from polymaps src/Layer.js
|
||||
// https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383
|
||||
|
||||
struct edge {
|
||||
double x0 = 0, y0 = 0;
|
||||
double x1 = 0, y1 = 0;
|
||||
double dx = 0, dy = 0;
|
||||
|
||||
edge(vec2<double> a, vec2<double> b) {
|
||||
if (a.y > b.y) { std::swap(a, b); }
|
||||
x0 = a.x;
|
||||
y0 = a.y;
|
||||
x1 = b.x;
|
||||
y1 = b.y;
|
||||
dx = b.x - a.x;
|
||||
dy = b.y - a.y;
|
||||
}
|
||||
};
|
||||
|
||||
typedef const std::function<void(int32_t x0, int32_t x1, int32_t y)> ScanLine;
|
||||
|
||||
// scan-line conversion
|
||||
static void scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine scanLine) {
|
||||
double y0 = std::fmax(ymin, std::floor(e1.y0));
|
||||
double y1 = std::fmin(ymax, std::ceil(e1.y1));
|
||||
|
||||
// sort edges by x-coordinate
|
||||
if ((e0.x0 == e1.x0 && e0.y0 == e1.y0) ?
|
||||
(e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) :
|
||||
(e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0)) {
|
||||
std::swap(e0, e1);
|
||||
}
|
||||
|
||||
// scan lines!
|
||||
double m0 = e0.dx / e0.dy;
|
||||
double m1 = e1.dx / e1.dy;
|
||||
double d0 = e0.dx > 0; // use y + 1 to compute x0
|
||||
double d1 = e1.dx < 0; // use y + 1 to compute x1
|
||||
for (int32_t y = y0; y < y1; y++) {
|
||||
double x0 = m0 * std::fmax(0, std::fmin(e0.dy, y + d0 - e0.y0)) + e0.x0;
|
||||
double x1 = m1 * std::fmax(0, std::fmin(e1.dy, y + d1 - e1.y0)) + e1.x0;
|
||||
scanLine(std::floor(x1), std::ceil(x0), y);
|
||||
}
|
||||
}
|
||||
|
||||
// scan-line conversion
|
||||
static void scanTriangle(const mbgl::vec2<double> a, const mbgl::vec2<double> b, const mbgl::vec2<double> c, int32_t ymin, int32_t ymax, ScanLine& scanLine) {
|
||||
edge ab = edge(a, b);
|
||||
edge bc = edge(b, c);
|
||||
edge ca = edge(c, a);
|
||||
|
||||
// sort edges by y-length
|
||||
if (ab.dy > bc.dy) { std::swap(ab, bc); }
|
||||
if (ab.dy > ca.dy) { std::swap(ab, ca); }
|
||||
if (bc.dy > ca.dy) { std::swap(bc, ca); }
|
||||
|
||||
// scan span! scan span!
|
||||
if (ab.dy) scanSpans(ca, ab, ymin, ymax, scanLine);
|
||||
if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine);
|
||||
}
|
||||
|
||||
std::forward_list<Tile::ID> Tile::cover(int8_t z, const mbgl::box &bounds) {
|
||||
int32_t tiles = 1 << z;
|
||||
std::forward_list<mbgl::Tile::ID> t;
|
||||
|
||||
auto scanLine = [&](int32_t x0, int32_t x1, int32_t y) {
|
||||
int32_t x;
|
||||
if (y >= 0 && y <= tiles) {
|
||||
for (x = x0; x < x1; x++) {
|
||||
t.emplace_front(z, x, y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Divide the screen up in two triangles and scan each of them:
|
||||
// \---+
|
||||
// | \ |
|
||||
// +---\.
|
||||
scanTriangle(bounds.tl, bounds.tr, bounds.br, 0, tiles, scanLine);
|
||||
scanTriangle(bounds.br, bounds.bl, bounds.tl, 0, tiles, scanLine);
|
||||
|
||||
t.unique();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
42
src/mbgl/map/tile.hpp
Normal file
42
src/mbgl/map/tile.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef MBGL_MAP_TILE
|
||||
#define MBGL_MAP_TILE
|
||||
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class TileData;
|
||||
struct box;
|
||||
|
||||
struct ClipID {
|
||||
inline ClipID() {}
|
||||
inline ClipID(const std::string &mask_, const std::string &reference_) : mask(mask_), reference(reference_) {}
|
||||
|
||||
std::bitset<8> mask;
|
||||
std::bitset<8> reference;
|
||||
|
||||
inline bool operator==(const ClipID &other) const {
|
||||
return mask == other.mask && reference == other.reference;
|
||||
}
|
||||
};
|
||||
|
||||
class Tile : private util::noncopyable {
|
||||
public:
|
||||
explicit Tile(const TileID& id_)
|
||||
: id(id_) {}
|
||||
|
||||
const TileID id;
|
||||
ClipID clip;
|
||||
mat4 matrix;
|
||||
util::ptr<TileData> data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,18 +1,14 @@
|
||||
#include <mbgl/map/tile_data.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/environment.hpp>
|
||||
#include <mbgl/style/style_source.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
|
||||
#include <mbgl/util/token.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/mapbox.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
TileData::TileData(Tile::ID const& id_, const SourceInfo& source_)
|
||||
TileData::TileData(const TileID& id_, const SourceInfo& source_)
|
||||
: id(id_),
|
||||
name(id),
|
||||
state(State::initial),
|
||||
@@ -34,25 +30,7 @@ const std::string TileData::toString() const {
|
||||
}
|
||||
|
||||
void TileData::request(uv::worker &worker, float pixelRatio, std::function<void()> callback) {
|
||||
if (source.tiles.empty())
|
||||
return;
|
||||
|
||||
std::string url = source.tiles[(id.x + id.y) % source.tiles.size()];
|
||||
url = util::mapbox::normalizeTileURL(url, source.url, source.type);
|
||||
url = util::replaceTokens(url, [&](const std::string &token) -> std::string {
|
||||
if (token == "z") return util::toString(id.z);
|
||||
if (token == "x") return util::toString(id.x);
|
||||
if (token == "y") return util::toString(id.y);
|
||||
if (token == "prefix") {
|
||||
std::string prefix { 2 };
|
||||
prefix[0] = "0123456789abcdef"[id.x % 16];
|
||||
prefix[1] = "0123456789abcdef"[id.y % 16];
|
||||
return prefix;
|
||||
}
|
||||
if (token == "ratio") return pixelRatio > 1.0 ? "@2x" : "";
|
||||
return "";
|
||||
});
|
||||
|
||||
std::string url = source.tileURL(id, pixelRatio);
|
||||
state = State::loading;
|
||||
|
||||
std::weak_ptr<TileData> weak_tile = shared_from_this();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef MBGL_MAP_TILE_DATA
|
||||
#define MBGL_MAP_TILE_DATA
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/renderer/debug_bucket.hpp>
|
||||
#include <mbgl/geometry/debug_font_buffer.hpp>
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
obsolete
|
||||
};
|
||||
|
||||
TileData(Tile::ID const &id, const SourceInfo &);
|
||||
TileData(const TileID&, const SourceInfo&);
|
||||
~TileData();
|
||||
|
||||
void request(uv::worker&, float pixelRatio, std::function<void ()> callback);
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
virtual void render(Painter &painter, const StyleLayer &layer_desc, const mat4 &matrix) = 0;
|
||||
virtual bool hasData(StyleLayer const &layer_desc) const = 0;
|
||||
|
||||
const Tile::ID id;
|
||||
const TileID id;
|
||||
const std::string name;
|
||||
std::atomic<State> state;
|
||||
|
||||
|
||||
52
src/mbgl/map/tile_id.cpp
Normal file
52
src/mbgl/map/tile_id.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
TileID TileID::parent(int8_t parent_z) const {
|
||||
assert(parent_z < z);
|
||||
int32_t dim = std::pow(2, z - parent_z);
|
||||
return TileID{
|
||||
parent_z,
|
||||
(x >= 0 ? x : x - dim + 1) / dim,
|
||||
y / dim
|
||||
};
|
||||
}
|
||||
|
||||
std::forward_list<TileID> TileID::children(int32_t child_z) const {
|
||||
assert(child_z > z);
|
||||
int32_t factor = std::pow(2, child_z - z);
|
||||
|
||||
std::forward_list<TileID> child_ids;
|
||||
for (int32_t ty = y * factor, y_max = (y + 1) * factor; ty < y_max; ++ty) {
|
||||
for (int32_t tx = x * factor, x_max = (x + 1) * factor; tx < x_max; ++tx) {
|
||||
child_ids.emplace_front(child_z, tx, ty);
|
||||
}
|
||||
}
|
||||
return child_ids;
|
||||
}
|
||||
|
||||
TileID TileID::normalized() const {
|
||||
int32_t dim = std::pow(2, z);
|
||||
int32_t nx = x, ny = y;
|
||||
while (nx < 0) nx += dim;
|
||||
while (nx >= dim) nx -= dim;
|
||||
return TileID { z, nx, ny };
|
||||
}
|
||||
|
||||
bool TileID::isChildOf(const TileID &parent_id) const {
|
||||
if (parent_id.z >= z || parent_id.w != w) {
|
||||
return false;
|
||||
}
|
||||
int32_t scale = std::pow(2, z - parent_id.z);
|
||||
return parent_id.x == ((x < 0 ? x - scale + 1 : x) / scale) &&
|
||||
parent_id.y == y / scale;
|
||||
}
|
||||
|
||||
TileID::operator std::string() const {
|
||||
return util::toString(z) + "/" + util::toString(x) + "/" + util::toString(y);
|
||||
}
|
||||
|
||||
}
|
||||
55
src/mbgl/map/tile_id.hpp
Normal file
55
src/mbgl/map/tile_id.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef MBGL_MAP_TILE_ID
|
||||
#define MBGL_MAP_TILE_ID
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <forward_list>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class TileID {
|
||||
public:
|
||||
const int16_t w = 0;
|
||||
const int8_t z = 0;
|
||||
const int32_t x = 0, y = 0;
|
||||
|
||||
inline explicit TileID(int8_t z_, int32_t x_, int32_t y_)
|
||||
: w((x_ < 0 ? x_ - (1 << z_) + 1 : x_) / (1 << z_)), z(z_), x(x_), y(y_) {}
|
||||
|
||||
inline uint64_t to_uint64() const {
|
||||
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;
|
||||
}
|
||||
|
||||
inline bool operator!=(const TileID& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
inline bool operator<(const TileID& rhs) const {
|
||||
if (w != rhs.w) return w < rhs.w;
|
||||
if (z != rhs.z) return z < rhs.z;
|
||||
if (x != rhs.x) return x < rhs.x;
|
||||
return y < rhs.y;
|
||||
}
|
||||
|
||||
TileID parent(int8_t z) const;
|
||||
TileID normalized() const;
|
||||
std::forward_list<TileID> children(int32_t z) const;
|
||||
bool isChildOf(const TileID&) const;
|
||||
operator std::string() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/style/style_source.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/renderer/fill_bucket.hpp>
|
||||
#include <mbgl/renderer/line_bucket.hpp>
|
||||
#include <mbgl/renderer/symbol_bucket.hpp>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/util/projection.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/box.hpp>
|
||||
@@ -7,7 +8,7 @@ using namespace mbgl;
|
||||
|
||||
#pragma mark - Matrix
|
||||
|
||||
void TransformState::matrixFor(mat4& matrix, const Tile::ID& id) const {
|
||||
void TransformState::matrixFor(mat4& matrix, const TileID& id) const {
|
||||
const double tile_scale = std::pow(2, id.z);
|
||||
const double tile_size = scale * util::tileSize / tile_scale;
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/style/style_bucket.hpp>
|
||||
#include <mbgl/style/style_source.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/geometry/glyph_atlas.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/util/pbf.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
VectorTileData::VectorTileData(Tile::ID const& id_,
|
||||
VectorTileData::VectorTileData(const TileID& id_,
|
||||
float mapMaxZoom,
|
||||
util::ptr<Style> style_,
|
||||
GlyphAtlas& glyphAtlas_,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef MBGL_MAP_VECTOR_TILE_DATA
|
||||
#define MBGL_MAP_VECTOR_TILE_DATA
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/tile_data.hpp>
|
||||
#include <mbgl/geometry/elements_buffer.hpp>
|
||||
#include <mbgl/geometry/fill_buffer.hpp>
|
||||
@@ -30,7 +29,7 @@ class VectorTileData : public TileData {
|
||||
friend class TileParser;
|
||||
|
||||
public:
|
||||
VectorTileData(Tile::ID const&,
|
||||
VectorTileData(const TileID&,
|
||||
float mapMaxZoom,
|
||||
util::ptr<Style>,
|
||||
GlyphAtlas&,
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
#ifndef MBGL_RENDERER_BUCKET
|
||||
#define MBGL_RENDERER_BUCKET
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Painter;
|
||||
class StyleLayer;
|
||||
class TileID;
|
||||
|
||||
class Bucket : private util::noncopyable {
|
||||
public:
|
||||
virtual void render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
const mat4 &matrix) = 0;
|
||||
virtual void render(Painter&, const StyleLayer&, const TileID&, const mat4&) = 0;
|
||||
virtual bool hasData() const = 0;
|
||||
virtual ~Bucket() {}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ DebugBucket::DebugBucket(DebugFontBuffer& fontBuffer_)
|
||||
}
|
||||
|
||||
void DebugBucket::render(Painter &painter, const StyleLayer & /*layer_desc*/,
|
||||
const Tile::ID & /*id*/, const mat4 &matrix) {
|
||||
const TileID & /*id*/, const mat4 &matrix) {
|
||||
painter.renderDebugText(*this, matrix);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class DebugBucket : public Bucket {
|
||||
public:
|
||||
DebugBucket(DebugFontBuffer& fontBuffer);
|
||||
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) override;
|
||||
bool hasData() const override;
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ void FillBucket::tessellate() {
|
||||
lineGroup.vertex_length += total_vertex_count;
|
||||
}
|
||||
|
||||
void FillBucket::render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void FillBucket::render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) {
|
||||
painter.renderFill(*this, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
LineElementsBuffer &lineElementsBuffer);
|
||||
~FillBucket() override;
|
||||
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) override;
|
||||
bool hasData() const override;
|
||||
|
||||
|
||||
@@ -326,7 +326,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
|
||||
}
|
||||
}
|
||||
|
||||
void LineBucket::render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void LineBucket::render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) {
|
||||
painter.renderLine(*this, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
PointElementsBuffer &pointElementsBuffer);
|
||||
~LineBucket() override;
|
||||
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) override;
|
||||
bool hasData() const override;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <mbgl/util/mat3.hpp>
|
||||
#include <mbgl/geometry/sprite_atlas.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
|
||||
#if defined(DEBUG)
|
||||
#include <mbgl/util/stopwatch.hpp>
|
||||
@@ -215,19 +216,25 @@ void Painter::prepareTile(const Tile& tile) {
|
||||
MBGL_CHECK_ERROR(glStencilFunc(GL_EQUAL, ref, mask));
|
||||
}
|
||||
|
||||
void Painter::render(const Style& style, const std::set<util::ptr<StyleSource>>& sources,
|
||||
TransformState state_, TimePoint time) {
|
||||
void Painter::render(const Style& style, TransformState state_, TimePoint time) {
|
||||
state = state_;
|
||||
|
||||
clear();
|
||||
resize();
|
||||
changeMatrix();
|
||||
|
||||
std::set<Source*> sources;
|
||||
for (const auto& source : style.sources) {
|
||||
if (source->enabled) {
|
||||
sources.insert(source.get());
|
||||
}
|
||||
}
|
||||
|
||||
// Update all clipping IDs.
|
||||
ClipIDGenerator generator;
|
||||
for (const auto& source : sources) {
|
||||
generator.update(source->source->getLoadedTiles());
|
||||
source->source->updateMatrices(projMatrix, state);
|
||||
generator.update(source->getLoadedTiles());
|
||||
source->updateMatrices(projMatrix, state);
|
||||
}
|
||||
|
||||
drawClippingMasks(sources);
|
||||
@@ -280,7 +287,7 @@ void Painter::render(const Style& style, const std::set<util::ptr<StyleSource>>&
|
||||
// When only rendering layers via the stylesheet, it's possible that we don't
|
||||
// ever visit a tile during rendering.
|
||||
for (const auto& source : sources) {
|
||||
source->source->finishRender(*this);
|
||||
source->finishRender(*this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,18 +309,11 @@ void Painter::renderLayer(const StyleLayer &layer_desc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!layer_desc.bucket->style_source) {
|
||||
if (!layer_desc.bucket->source) {
|
||||
Log::Warning(Event::Render, "can't find source for layer '%s'", layer_desc.id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
StyleSource const& style_source = *layer_desc.bucket->style_source;
|
||||
|
||||
// Skip this layer if there is no data.
|
||||
if (!style_source.source) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip this layer if it's outside the range of min/maxzoom.
|
||||
// This may occur when there /is/ a bucket created for this layer, but the min/max-zoom
|
||||
// is set to a fractional value, or value that is larger than the source maxzoom.
|
||||
@@ -350,7 +350,7 @@ void Painter::renderLayer(const StyleLayer &layer_desc) {
|
||||
StyleLayerTypeClass(layer_desc.type).c_str());
|
||||
}
|
||||
|
||||
style_source.source->render(*this, layer_desc);
|
||||
layer_desc.bucket->source->render(*this, layer_desc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ void Painter::renderBackground(const StyleLayer &layer_desc) {
|
||||
MBGL_CHECK_ERROR(glEnable(GL_STENCIL_TEST));
|
||||
}
|
||||
|
||||
mat4 Painter::translatedMatrix(const mat4& matrix, const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor) {
|
||||
mat4 Painter::translatedMatrix(const mat4& matrix, const std::array<float, 2> &translation, const TileID &id, TranslateAnchorType anchor) {
|
||||
if (translation[0] == 0 && translation[1] == 0) {
|
||||
return matrix;
|
||||
} else {
|
||||
|
||||
@@ -42,7 +42,6 @@ class SpriteAtlas;
|
||||
class GlyphAtlas;
|
||||
class LineAtlas;
|
||||
class Source;
|
||||
class StyleSource;
|
||||
|
||||
class FillBucket;
|
||||
class LineBucket;
|
||||
@@ -55,6 +54,7 @@ struct RasterProperties;
|
||||
|
||||
class LayerDescription;
|
||||
class RasterTileData;
|
||||
struct ClipID;
|
||||
|
||||
class Painter : private util::noncopyable {
|
||||
public:
|
||||
@@ -76,7 +76,6 @@ public:
|
||||
void changeMatrix();
|
||||
|
||||
void render(const Style& style,
|
||||
const std::set<util::ptr<StyleSource>>& sources,
|
||||
TransformState state,
|
||||
TimePoint time);
|
||||
|
||||
@@ -93,10 +92,10 @@ public:
|
||||
|
||||
void renderDebugText(DebugBucket& bucket, const mat4 &matrix);
|
||||
void renderDebugText(const std::vector<std::string> &strings);
|
||||
void renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderSymbol(SymbolBucket& bucket, const StyleLayer &layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderRaster(RasterBucket& bucket, const StyleLayer &layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
|
||||
void renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
|
||||
void renderSymbol(SymbolBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
|
||||
void renderRaster(RasterBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
|
||||
void renderBackground(const StyleLayer &layer_desc);
|
||||
|
||||
float saturationFactor(float saturation);
|
||||
@@ -107,7 +106,7 @@ public:
|
||||
|
||||
void renderPrerenderedTexture(RasterBucket &bucket, const mat4 &matrix, const RasterProperties& properties);
|
||||
|
||||
void createPrerendered(RasterBucket& bucket, const StyleLayer &layer_desc, const Tile::ID& id);
|
||||
void createPrerendered(RasterBucket& bucket, const StyleLayer &layer_desc, const TileID& id);
|
||||
|
||||
void resize();
|
||||
|
||||
@@ -121,7 +120,7 @@ public:
|
||||
// Configures the painter strata that is used for early z-culling of fragments.
|
||||
void setStrata(float strata);
|
||||
|
||||
void drawClippingMasks(const std::set<util::ptr<StyleSource>> &sources);
|
||||
void drawClippingMasks(const std::set<Source*>&);
|
||||
void drawClippingMask(const mat4& matrix, const ClipID& clip);
|
||||
|
||||
void resetFramebuffer();
|
||||
@@ -135,13 +134,13 @@ public:
|
||||
private:
|
||||
void setupShaders();
|
||||
void deleteShaders();
|
||||
mat4 translatedMatrix(const mat4& matrix, const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor);
|
||||
mat4 translatedMatrix(const mat4& matrix, const std::array<float, 2> &translation, const TileID &id, TranslateAnchorType anchor);
|
||||
|
||||
void prepareTile(const Tile& tile);
|
||||
|
||||
template <typename BucketProperties, typename StyleProperties>
|
||||
void renderSDF(SymbolBucket &bucket,
|
||||
const Tile::ID &id,
|
||||
const TileID &id,
|
||||
const mat4 &matrixSymbol,
|
||||
const BucketProperties& bucketProperties,
|
||||
const StyleProperties& styleProperties,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include <mbgl/renderer/painter.hpp>
|
||||
#include <mbgl/renderer/fill_bucket.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/util/clip_ids.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
void Painter::drawClippingMasks(const std::set<util::ptr<StyleSource>> &sources) {
|
||||
void Painter::drawClippingMasks(const std::set<Source*>& sources) {
|
||||
gl::group group("clipping masks");
|
||||
|
||||
useProgram(plainShader->program);
|
||||
@@ -18,7 +19,7 @@ void Painter::drawClippingMasks(const std::set<util::ptr<StyleSource>> &sources)
|
||||
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
|
||||
|
||||
for (const auto& source : sources) {
|
||||
source->source->drawClippingMasks(*this);
|
||||
source->drawClippingMasks(*this);
|
||||
}
|
||||
|
||||
MBGL_CHECK_ERROR(glEnable(GL_DEPTH_TEST));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <mbgl/renderer/painter.hpp>
|
||||
#include <mbgl/renderer/debug_bucket.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix) {
|
||||
// Abort early.
|
||||
if (!bucket.hasData()) return;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix) {
|
||||
// Abort early.
|
||||
if (pass == RenderPass::Opaque) return;
|
||||
if (!bucket.hasData()) return;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
void Painter::renderRaster(RasterBucket& bucket, const StyleLayer &layer_desc, const Tile::ID&, const mat4 &matrix) {
|
||||
void Painter::renderRaster(RasterBucket& bucket, const StyleLayer &layer_desc, const TileID&, const mat4 &matrix) {
|
||||
if (pass != RenderPass::Translucent) return;
|
||||
|
||||
const RasterProperties &properties = layer_desc.getProperties<RasterProperties>();
|
||||
|
||||
@@ -13,7 +13,7 @@ using namespace mbgl;
|
||||
|
||||
template <typename BucketProperties, typename StyleProperties>
|
||||
void Painter::renderSDF(SymbolBucket &bucket,
|
||||
const Tile::ID &id,
|
||||
const TileID &id,
|
||||
const mat4 &matrix,
|
||||
const BucketProperties& bucketProperties,
|
||||
const StyleProperties& styleProperties,
|
||||
@@ -112,7 +112,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
|
||||
}
|
||||
}
|
||||
|
||||
void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, const Tile::ID &id, const mat4 &matrix) {
|
||||
void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, const TileID &id, const mat4 &matrix) {
|
||||
// Abort early.
|
||||
if (pass == RenderPass::Opaque) {
|
||||
return;
|
||||
|
||||
@@ -8,7 +8,7 @@ RasterBucket::RasterBucket(TexturePool& texturePool, const StyleLayoutRaster& la
|
||||
raster(texturePool) {
|
||||
}
|
||||
|
||||
void RasterBucket::render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void RasterBucket::render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) {
|
||||
painter.renderRaster(*this, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class RasterBucket : public Bucket {
|
||||
public:
|
||||
RasterBucket(TexturePool&, const StyleLayoutRaster&);
|
||||
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) override;
|
||||
bool hasData() const override;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ SymbolBucket::~SymbolBucket() {
|
||||
// Do not remove. header file only contains forward definitions to unique pointers.
|
||||
}
|
||||
|
||||
void SymbolBucket::render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void SymbolBucket::render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) {
|
||||
painter.renderSymbol(*this, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
SymbolBucket(Collision &collision);
|
||||
~SymbolBucket() override;
|
||||
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const Tile::ID &id,
|
||||
void render(Painter &painter, const StyleLayer &layer_desc, const TileID &id,
|
||||
const mat4 &matrix) override;
|
||||
bool hasData() const override;
|
||||
bool hasTextData() const;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/map/sprite.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/style/style_parser.hpp>
|
||||
#include <mbgl/style/style_bucket.hpp>
|
||||
@@ -36,10 +37,17 @@ void Style::cascade(const std::vector<std::string>& classes) {
|
||||
void Style::recalculate(float z, TimePoint now) {
|
||||
uv::writelock lock(mtx);
|
||||
|
||||
for (const auto& source : sources) {
|
||||
source->enabled = false;
|
||||
}
|
||||
|
||||
zoomHistory.update(z, now);
|
||||
|
||||
for (const auto& layer : layers) {
|
||||
layer->updateProperties(z, now, zoomHistory);
|
||||
if (layer->bucket && layer->bucket->source) {
|
||||
layer->bucket->source->enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +81,7 @@ void Style::loadJSON(const uint8_t *const data) {
|
||||
StyleParser parser;
|
||||
parser.parse(doc);
|
||||
|
||||
sources = parser.getSources();
|
||||
layers = parser.getLayers();
|
||||
sprite_url = parser.getSprite();
|
||||
glyph_url = parser.getGlyphURL();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Source;
|
||||
class StyleLayer;
|
||||
|
||||
class Style : public util::noncopyable {
|
||||
@@ -32,6 +33,7 @@ public:
|
||||
|
||||
const std::string &getSpriteURL() const;
|
||||
|
||||
std::vector<util::ptr<Source>> sources;
|
||||
std::vector<util::ptr<StyleLayer>> layers;
|
||||
std::string glyph_url;
|
||||
std::string base;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class StyleSource;
|
||||
class Source;
|
||||
|
||||
class StyleBucket : public util::noncopyable {
|
||||
public:
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
|
||||
const StyleLayerType type;
|
||||
std::string name;
|
||||
util::ptr<StyleSource> style_source;
|
||||
util::ptr<Source> source;
|
||||
std::string source_layer;
|
||||
FilterExpression filter;
|
||||
ClassProperties layout;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <mbgl/style/style_source.hpp>
|
||||
#include <mbgl/style/style_parser.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/map/annotation.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
@@ -59,11 +59,11 @@ void StyleParser::parse(JSVal document) {
|
||||
iconOverlap.AddMember("icon-allow-overlap", true, d.GetAllocator());
|
||||
parseLayout(iconOverlap, pointBucket);
|
||||
|
||||
SourceInfo& info = sources.emplace(id, std::make_shared<StyleSource>()).first->second->info;
|
||||
info.type = SourceType::Annotations;
|
||||
|
||||
auto source_it = sources.find(id);
|
||||
pointBucket->style_source = source_it->second;
|
||||
util::ptr<Source> source = std::make_shared<Source>();
|
||||
sourcesMap.emplace(id, source);
|
||||
sources.emplace_back(source);
|
||||
source->info.type = SourceType::Annotations;
|
||||
pointBucket->source = source;
|
||||
annotations->bucket = pointBucket;
|
||||
//
|
||||
// end point annotations
|
||||
@@ -218,12 +218,13 @@ void StyleParser::parseSources(JSVal value) {
|
||||
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
|
||||
for (; itr != value.MemberEnd(); ++itr) {
|
||||
std::string name { itr->name.GetString(), itr->name.GetStringLength() };
|
||||
SourceInfo& info = sources.emplace(name, std::make_shared<StyleSource>()).first->second->info;
|
||||
|
||||
parseRenderProperty<SourceTypeClass>(itr->value, info.type, "type");
|
||||
parseRenderProperty(itr->value, info.url, "url");
|
||||
parseRenderProperty(itr->value, info.tile_size, "tileSize");
|
||||
info.parseTileJSONProperties(itr->value);
|
||||
util::ptr<Source> source = std::make_shared<Source>();
|
||||
parseRenderProperty<SourceTypeClass>(itr->value, source->info.type, "type");
|
||||
parseRenderProperty(itr->value, source->info.url, "url");
|
||||
parseRenderProperty(itr->value, source->info.tile_size, "tileSize");
|
||||
source->info.parseTileJSONProperties(itr->value);
|
||||
sources.emplace_back(source);
|
||||
sourcesMap.emplace(name, source);
|
||||
}
|
||||
} else {
|
||||
Log::Warning(Event::ParseStyle, "sources must be an object");
|
||||
@@ -939,9 +940,9 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) {
|
||||
JSVal value_source = replaceConstant(value["source"]);
|
||||
if (value_source.IsString()) {
|
||||
const std::string source_name = { value_source.GetString(), value_source.GetStringLength() };
|
||||
auto source_it = sources.find(source_name);
|
||||
if (source_it != sources.end()) {
|
||||
bucket->style_source = source_it->second;
|
||||
auto source_it = sourcesMap.find(source_name);
|
||||
if (source_it != sourcesMap.end()) {
|
||||
bucket->source = source_it->second;
|
||||
} else {
|
||||
Log::Warning(Event::ParseStyle, "can't find source '%s' required for layer '%s'", source_name.c_str(), layer->id.c_str());
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/style_source.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/style/filter_expression.hpp>
|
||||
#include <mbgl/style/class_properties.hpp>
|
||||
#include <mbgl/style/style_bucket.hpp>
|
||||
@@ -17,6 +17,7 @@ namespace mbgl {
|
||||
enum class ClassID : uint32_t;
|
||||
|
||||
class StyleLayer;
|
||||
class Source;
|
||||
|
||||
class StyleParser {
|
||||
public:
|
||||
@@ -26,6 +27,10 @@ public:
|
||||
|
||||
void parse(JSVal document);
|
||||
|
||||
std::vector<util::ptr<Source>> getSources() {
|
||||
return sources;
|
||||
}
|
||||
|
||||
std::vector<util::ptr<StyleLayer>> getLayers() {
|
||||
return layers;
|
||||
}
|
||||
@@ -90,12 +95,10 @@ private:
|
||||
private:
|
||||
std::unordered_map<std::string, const rapidjson::Value *> constants;
|
||||
|
||||
std::unordered_map<std::string, const util::ptr<StyleSource>> sources;
|
||||
|
||||
// This stores the root layer.
|
||||
std::vector<util::ptr<Source>> sources;
|
||||
std::vector<util::ptr<StyleLayer>> layers;
|
||||
|
||||
// This maps ids to Layer objects, with all items being at the root level.
|
||||
std::unordered_map<std::string, const util::ptr<Source>> sourcesMap;
|
||||
std::unordered_map<std::string, std::pair<JSVal, util::ptr<StyleLayer>>> layersMap;
|
||||
|
||||
// Store a stack of layers we're parsing right now. This is to prevent reference cycles.
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
#include <mbgl/style/style_source.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
void parse(const rapidjson::Value& value, std::vector<std::string>& target, const char *name) {
|
||||
if (!value.HasMember(name))
|
||||
return;
|
||||
|
||||
const rapidjson::Value& property = value[name];
|
||||
if (!property.IsArray())
|
||||
return;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++)
|
||||
if (!property[i].IsString())
|
||||
return;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++)
|
||||
target.emplace_back(std::string(property[i].GetString(), property[i].GetStringLength()));
|
||||
}
|
||||
|
||||
void parse(const rapidjson::Value& value, std::string& target, const char* name) {
|
||||
if (!value.HasMember(name))
|
||||
return;
|
||||
|
||||
const rapidjson::Value& property = value[name];
|
||||
if (!property.IsString())
|
||||
return;
|
||||
|
||||
target = { property.GetString(), property.GetStringLength() };
|
||||
}
|
||||
|
||||
void parse(const rapidjson::Value& value, uint16_t& target, const char* name) {
|
||||
if (!value.HasMember(name))
|
||||
return;
|
||||
|
||||
const rapidjson::Value& property = value[name];
|
||||
if (!property.IsUint())
|
||||
return;
|
||||
|
||||
unsigned int uint = property.GetUint();
|
||||
if (uint > std::numeric_limits<uint16_t>::max())
|
||||
return;
|
||||
|
||||
target = uint;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void parse(const rapidjson::Value& value, std::array<float, N>& target, const char* name) {
|
||||
if (!value.HasMember(name))
|
||||
return;
|
||||
|
||||
const rapidjson::Value& property = value[name];
|
||||
if (!property.IsArray() || property.Size() != N)
|
||||
return;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++)
|
||||
if (!property[i].IsNumber())
|
||||
return;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++)
|
||||
target[i] = property[i].GetDouble();
|
||||
}
|
||||
|
||||
void SourceInfo::parseTileJSONProperties(const rapidjson::Value& value) {
|
||||
parse(value, tiles, "tiles");
|
||||
parse(value, min_zoom, "minzoom");
|
||||
parse(value, max_zoom, "maxzoom");
|
||||
parse(value, attribution, "attribution");
|
||||
parse(value, center, "center");
|
||||
parse(value, bounds, "bounds");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef MBGL_STYLE_STYLE_SOURCE
|
||||
#define MBGL_STYLE_STYLE_SOURCE
|
||||
|
||||
#include <mbgl/style/types.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Source;
|
||||
|
||||
class SourceInfo : private util::noncopyable {
|
||||
public:
|
||||
SourceType type = SourceType::Vector;
|
||||
std::string url;
|
||||
std::vector<std::string> tiles;
|
||||
uint16_t tile_size = 512;
|
||||
uint16_t min_zoom = 0;
|
||||
uint16_t max_zoom = 22;
|
||||
std::string attribution;
|
||||
std::array<float, 3> center = {{0, 0, 0}};
|
||||
std::array<float, 4> bounds = {{-180, -90, 180, 90}};
|
||||
|
||||
void parseTileJSONProperties(const rapidjson::Value&);
|
||||
};
|
||||
|
||||
|
||||
class StyleSource : private util::noncopyable {
|
||||
public:
|
||||
SourceInfo info;
|
||||
bool enabled = false;
|
||||
util::ptr<Source> source;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <mbgl/util/clip_ids.hpp>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
@@ -15,7 +15,7 @@ namespace mbgl {
|
||||
|
||||
ClipIDGenerator::Leaf::Leaf(Tile &tile_) : tile(tile_) {}
|
||||
|
||||
void ClipIDGenerator::Leaf::add(const Tile::ID &p) {
|
||||
void ClipIDGenerator::Leaf::add(const TileID &p) {
|
||||
if (p.isChildOf(tile.id)) {
|
||||
// Ensure that no already present child is a parent of the new p.
|
||||
for (const auto& child : children) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef MBGL_UTIL_CLIP_IDS
|
||||
#define MBGL_UTIL_CLIP_IDS
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
@@ -10,15 +11,17 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Tile;
|
||||
|
||||
class ClipIDGenerator {
|
||||
private:
|
||||
struct Leaf {
|
||||
Leaf(Tile &tile);
|
||||
void add(const Tile::ID &p);
|
||||
void add(const TileID &p);
|
||||
bool operator==(const Leaf &other) const;
|
||||
|
||||
Tile &tile;
|
||||
std::forward_list<Tile::ID> children;
|
||||
std::forward_list<TileID> children;
|
||||
};
|
||||
|
||||
typedef std::vector<Leaf> Pool;
|
||||
|
||||
93
src/mbgl/util/tile_cover.cpp
Normal file
93
src/mbgl/util/tile_cover.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include <mbgl/util/tile_cover.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
#include <mbgl/util/box.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
// Taken from polymaps src/Layer.js
|
||||
// https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383
|
||||
|
||||
struct edge {
|
||||
double x0 = 0, y0 = 0;
|
||||
double x1 = 0, y1 = 0;
|
||||
double dx = 0, dy = 0;
|
||||
|
||||
edge(vec2<double> a, vec2<double> b) {
|
||||
if (a.y > b.y) { std::swap(a, b); }
|
||||
x0 = a.x;
|
||||
y0 = a.y;
|
||||
x1 = b.x;
|
||||
y1 = b.y;
|
||||
dx = b.x - a.x;
|
||||
dy = b.y - a.y;
|
||||
}
|
||||
};
|
||||
|
||||
typedef const std::function<void(int32_t x0, int32_t x1, int32_t y)> ScanLine;
|
||||
|
||||
// scan-line conversion
|
||||
static void scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine scanLine) {
|
||||
double y0 = std::fmax(ymin, std::floor(e1.y0));
|
||||
double y1 = std::fmin(ymax, std::ceil(e1.y1));
|
||||
|
||||
// sort edges by x-coordinate
|
||||
if ((e0.x0 == e1.x0 && e0.y0 == e1.y0) ?
|
||||
(e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) :
|
||||
(e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0)) {
|
||||
std::swap(e0, e1);
|
||||
}
|
||||
|
||||
// scan lines!
|
||||
double m0 = e0.dx / e0.dy;
|
||||
double m1 = e1.dx / e1.dy;
|
||||
double d0 = e0.dx > 0; // use y + 1 to compute x0
|
||||
double d1 = e1.dx < 0; // use y + 1 to compute x1
|
||||
for (int32_t y = y0; y < y1; y++) {
|
||||
double x0 = m0 * std::fmax(0, std::fmin(e0.dy, y + d0 - e0.y0)) + e0.x0;
|
||||
double x1 = m1 * std::fmax(0, std::fmin(e1.dy, y + d1 - e1.y0)) + e1.x0;
|
||||
scanLine(std::floor(x1), std::ceil(x0), y);
|
||||
}
|
||||
}
|
||||
|
||||
// scan-line conversion
|
||||
static void scanTriangle(const mbgl::vec2<double> a, const mbgl::vec2<double> b, const mbgl::vec2<double> c, int32_t ymin, int32_t ymax, ScanLine& scanLine) {
|
||||
edge ab = edge(a, b);
|
||||
edge bc = edge(b, c);
|
||||
edge ca = edge(c, a);
|
||||
|
||||
// sort edges by y-length
|
||||
if (ab.dy > bc.dy) { std::swap(ab, bc); }
|
||||
if (ab.dy > ca.dy) { std::swap(ab, ca); }
|
||||
if (bc.dy > ca.dy) { std::swap(bc, ca); }
|
||||
|
||||
// scan span! scan span!
|
||||
if (ab.dy) scanSpans(ca, ab, ymin, ymax, scanLine);
|
||||
if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine);
|
||||
}
|
||||
|
||||
std::forward_list<TileID> tileCover(int8_t z, const mbgl::box &bounds) {
|
||||
int32_t tiles = 1 << z;
|
||||
std::forward_list<mbgl::TileID> t;
|
||||
|
||||
auto scanLine = [&](int32_t x0, int32_t x1, int32_t y) {
|
||||
int32_t x;
|
||||
if (y >= 0 && y <= tiles) {
|
||||
for (x = x0; x < x1; x++) {
|
||||
t.emplace_front(z, x, y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Divide the screen up in two triangles and scan each of them:
|
||||
// \---+
|
||||
// | \ |
|
||||
// +---\.
|
||||
scanTriangle(bounds.tl, bounds.tr, bounds.br, 0, tiles, scanLine);
|
||||
scanTriangle(bounds.br, bounds.bl, bounds.tl, 0, tiles, scanLine);
|
||||
|
||||
t.unique();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
15
src/mbgl/util/tile_cover.hpp
Normal file
15
src/mbgl/util/tile_cover.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef MBGL_UTIL_TILE_COVER
|
||||
#define MBGL_UTIL_TILE_COVER
|
||||
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/util/box.hpp>
|
||||
|
||||
#include <forward_list>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
std::forward_list<TileID> tileCover(int8_t z, const box& bounds);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <mbgl/util/clip_ids.hpp>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
@@ -29,11 +30,11 @@ template <typename T> void print(const T &sources) {
|
||||
TEST(ClipIDs, ParentAndFourChildren) {
|
||||
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 1, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, 0, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, 1, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, 1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 0, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, 0, 1 }),
|
||||
std::make_shared<Tile>(TileID { 1, 1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, 1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 0, 0, 0 }),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -50,11 +51,11 @@ TEST(ClipIDs, ParentAndFourChildren) {
|
||||
TEST(ClipIDs, ParentAndFourChildrenNegative) {
|
||||
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 1, -2, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, -2, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, -1, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, -1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 0, -1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, -2, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, -2, 1 }),
|
||||
std::make_shared<Tile>(TileID { 1, -1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, -1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 0, -1, 0 }),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -71,11 +72,11 @@ TEST(ClipIDs, ParentAndFourChildrenNegative) {
|
||||
TEST(ClipIDs, NegativeParentAndMissingLevel) {
|
||||
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 1, -1, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, -1, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, -2, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, -1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, -2, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, -1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 2, -1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 2, -2, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, -1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, -2, 0 }),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -93,13 +94,13 @@ TEST(ClipIDs, NegativeParentAndMissingLevel) {
|
||||
TEST(ClipIDs, SevenOnSameLevel) {
|
||||
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 2 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 1, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 1, 2 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 2, 0 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 2 }),
|
||||
std::make_shared<Tile>(TileID { 2, 1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 2, 1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 1, 2 }),
|
||||
std::make_shared<Tile>(TileID { 2, 2, 0 }),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -118,18 +119,18 @@ TEST(ClipIDs, SevenOnSameLevel) {
|
||||
TEST(ClipIDs, MultipleLevels) {
|
||||
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 3, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 3, 0, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 4, 0, 2 }),
|
||||
std::make_shared<Tile>(Tile::ID { 4, 1, 2 }),
|
||||
std::make_shared<Tile>(Tile::ID { 4, 0, 3 }),
|
||||
std::make_shared<Tile>(Tile::ID { 4, 1, 3 }),
|
||||
std::make_shared<Tile>(Tile::ID { 3, 1, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 3, 1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 1, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 3, 2, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 3, 2, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 3, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 3, 0, 1 }),
|
||||
std::make_shared<Tile>(TileID { 4, 0, 2 }),
|
||||
std::make_shared<Tile>(TileID { 4, 1, 2 }),
|
||||
std::make_shared<Tile>(TileID { 4, 0, 3 }),
|
||||
std::make_shared<Tile>(TileID { 4, 1, 3 }),
|
||||
std::make_shared<Tile>(TileID { 3, 1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 3, 1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 3, 2, 0 }),
|
||||
std::make_shared<Tile>(TileID { 3, 2, 1 }),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -154,17 +155,17 @@ TEST(ClipIDs, MultipleLevels) {
|
||||
TEST(ClipIDs, Bug206) {
|
||||
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 10, 162, 395 }),
|
||||
std::make_shared<Tile>(Tile::ID { 10, 162, 396 }),
|
||||
std::make_shared<Tile>(Tile::ID { 10, 163, 395 }),
|
||||
std::make_shared<Tile>(Tile::ID { 11, 326, 791 }),
|
||||
std::make_shared<Tile>(Tile::ID { 12, 654, 1582 }),
|
||||
std::make_shared<Tile>(Tile::ID { 12, 654, 1583 }),
|
||||
std::make_shared<Tile>(Tile::ID { 12, 655, 1582 }),
|
||||
std::make_shared<Tile>(Tile::ID { 12, 655, 1583 }),
|
||||
std::make_shared<Tile>(Tile::ID { 10, 163, 396 }),
|
||||
std::make_shared<Tile>(Tile::ID { 10, 164, 395 }),
|
||||
std::make_shared<Tile>(Tile::ID { 10, 164, 396 }),
|
||||
std::make_shared<Tile>(TileID { 10, 162, 395 }),
|
||||
std::make_shared<Tile>(TileID { 10, 162, 396 }),
|
||||
std::make_shared<Tile>(TileID { 10, 163, 395 }),
|
||||
std::make_shared<Tile>(TileID { 11, 326, 791 }),
|
||||
std::make_shared<Tile>(TileID { 12, 654, 1582 }),
|
||||
std::make_shared<Tile>(TileID { 12, 654, 1583 }),
|
||||
std::make_shared<Tile>(TileID { 12, 655, 1582 }),
|
||||
std::make_shared<Tile>(TileID { 12, 655, 1583 }),
|
||||
std::make_shared<Tile>(TileID { 10, 163, 396 }),
|
||||
std::make_shared<Tile>(TileID { 10, 164, 395 }),
|
||||
std::make_shared<Tile>(TileID { 10, 164, 396 }),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -188,23 +189,23 @@ TEST(ClipIDs, Bug206) {
|
||||
TEST(ClipIDs, MultipleSources) {
|
||||
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 0, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, 1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 2, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 2, 2 }),
|
||||
std::make_shared<Tile>(TileID { 0, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, 1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 2, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 2, 2 }),
|
||||
},
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 0, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, 1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 2, 2 }),
|
||||
std::make_shared<Tile>(TileID { 0, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, 1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 2, 2 }),
|
||||
},
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 1, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, 0, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, 1, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 1, 1, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 1, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, 0, 1 }),
|
||||
std::make_shared<Tile>(TileID { 1, 1, 0 }),
|
||||
std::make_shared<Tile>(TileID { 1, 1, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 1, 1 }),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -230,13 +231,13 @@ TEST(ClipIDs, MultipleSources) {
|
||||
TEST(ClipIDs, DuplicateIDs) {
|
||||
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 1 }),
|
||||
},
|
||||
{
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 0 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 1 }),
|
||||
std::make_shared<Tile>(Tile::ID { 2, 0, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 0 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 1 }),
|
||||
std::make_shared<Tile>(TileID { 2, 0, 1 }),
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
#include <iostream>
|
||||
#include "../fixtures/util.hpp"
|
||||
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
|
||||
TEST(Variant, isChild) {
|
||||
ASSERT_TRUE(Tile::ID(1, 0, 0).isChildOf(Tile::ID(0, 0, 0)));
|
||||
ASSERT_TRUE(Tile::ID(1, 1, 0).isChildOf(Tile::ID(0, 0, 0)));
|
||||
ASSERT_TRUE(Tile::ID(1, 2, 0).isChildOf(Tile::ID(0, 1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(1, 3, 0).isChildOf(Tile::ID(0, 1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(1, 4, 0).isChildOf(Tile::ID(0, 2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(1, 5, 0).isChildOf(Tile::ID(0, 2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, 0, 0).isChildOf(Tile::ID(0, 0, 0)));
|
||||
ASSERT_TRUE(TileID(1, 0, 0).isChildOf(TileID(0, 0, 0)));
|
||||
ASSERT_TRUE(TileID(1, 1, 0).isChildOf(TileID(0, 0, 0)));
|
||||
ASSERT_TRUE(TileID(1, 2, 0).isChildOf(TileID(0, 1, 0)));
|
||||
ASSERT_TRUE(TileID(1, 3, 0).isChildOf(TileID(0, 1, 0)));
|
||||
ASSERT_TRUE(TileID(1, 4, 0).isChildOf(TileID(0, 2, 0)));
|
||||
ASSERT_TRUE(TileID(1, 5, 0).isChildOf(TileID(0, 2, 0)));
|
||||
ASSERT_TRUE(TileID(2, 0, 0).isChildOf(TileID(0, 0, 0)));
|
||||
|
||||
ASSERT_TRUE(Tile::ID(2, 8, 0).isChildOf(Tile::ID(0, 2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, 9, 0).isChildOf(Tile::ID(0, 2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, 10, 0).isChildOf(Tile::ID(0, 2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, 11, 0).isChildOf(Tile::ID(0, 2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, 12, 0).isChildOf(Tile::ID(0, 3, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, 13, 0).isChildOf(Tile::ID(0, 3, 0)));
|
||||
ASSERT_TRUE(TileID(2, 8, 0).isChildOf(TileID(0, 2, 0)));
|
||||
ASSERT_TRUE(TileID(2, 9, 0).isChildOf(TileID(0, 2, 0)));
|
||||
ASSERT_TRUE(TileID(2, 10, 0).isChildOf(TileID(0, 2, 0)));
|
||||
ASSERT_TRUE(TileID(2, 11, 0).isChildOf(TileID(0, 2, 0)));
|
||||
ASSERT_TRUE(TileID(2, 12, 0).isChildOf(TileID(0, 3, 0)));
|
||||
ASSERT_TRUE(TileID(2, 13, 0).isChildOf(TileID(0, 3, 0)));
|
||||
|
||||
ASSERT_TRUE(Tile::ID(1, -1, 0).isChildOf(Tile::ID(0, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(1, -2, 0).isChildOf(Tile::ID(0, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(1, -3, 0).isChildOf(Tile::ID(0, -2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(1, -4, 0).isChildOf(Tile::ID(0, -2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -1, 0).isChildOf(Tile::ID(0, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -2, 0).isChildOf(Tile::ID(0, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -3, 0).isChildOf(Tile::ID(0, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -4, 0).isChildOf(Tile::ID(0, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -5, 0).isChildOf(Tile::ID(0, -2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -6, 0).isChildOf(Tile::ID(0, -2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -7, 0).isChildOf(Tile::ID(0, -2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -8, 0).isChildOf(Tile::ID(0, -2, 0)));
|
||||
ASSERT_TRUE(TileID(1, -1, 0).isChildOf(TileID(0, -1, 0)));
|
||||
ASSERT_TRUE(TileID(1, -2, 0).isChildOf(TileID(0, -1, 0)));
|
||||
ASSERT_TRUE(TileID(1, -3, 0).isChildOf(TileID(0, -2, 0)));
|
||||
ASSERT_TRUE(TileID(1, -4, 0).isChildOf(TileID(0, -2, 0)));
|
||||
ASSERT_TRUE(TileID(2, -1, 0).isChildOf(TileID(0, -1, 0)));
|
||||
ASSERT_TRUE(TileID(2, -2, 0).isChildOf(TileID(0, -1, 0)));
|
||||
ASSERT_TRUE(TileID(2, -3, 0).isChildOf(TileID(0, -1, 0)));
|
||||
ASSERT_TRUE(TileID(2, -4, 0).isChildOf(TileID(0, -1, 0)));
|
||||
ASSERT_TRUE(TileID(2, -5, 0).isChildOf(TileID(0, -2, 0)));
|
||||
ASSERT_TRUE(TileID(2, -6, 0).isChildOf(TileID(0, -2, 0)));
|
||||
ASSERT_TRUE(TileID(2, -7, 0).isChildOf(TileID(0, -2, 0)));
|
||||
ASSERT_TRUE(TileID(2, -8, 0).isChildOf(TileID(0, -2, 0)));
|
||||
|
||||
ASSERT_FALSE(Tile::ID(4, -16, 0).isChildOf(Tile::ID(0, -2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(4, -17, 0).isChildOf(Tile::ID(0, -2, 0)));
|
||||
ASSERT_FALSE(TileID(4, -16, 0).isChildOf(TileID(0, -2, 0)));
|
||||
ASSERT_TRUE(TileID(4, -17, 0).isChildOf(TileID(0, -2, 0)));
|
||||
|
||||
ASSERT_TRUE(Tile::ID(2, -1, 0).isChildOf(Tile::ID(1, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -2, 0).isChildOf(Tile::ID(1, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -3, 0).isChildOf(Tile::ID(1, -2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(2, -4, 0).isChildOf(Tile::ID(1, -2, 0)));
|
||||
ASSERT_TRUE(Tile::ID(3, -1, 0).isChildOf(Tile::ID(1, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(3, -2, 0).isChildOf(Tile::ID(1, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(3, -3, 0).isChildOf(Tile::ID(1, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(3, -4, 0).isChildOf(Tile::ID(1, -1, 0)));
|
||||
ASSERT_TRUE(Tile::ID(3, -5, 0).isChildOf(Tile::ID(1, -2, 0)));
|
||||
ASSERT_TRUE(TileID(2, -1, 0).isChildOf(TileID(1, -1, 0)));
|
||||
ASSERT_TRUE(TileID(2, -2, 0).isChildOf(TileID(1, -1, 0)));
|
||||
ASSERT_TRUE(TileID(2, -3, 0).isChildOf(TileID(1, -2, 0)));
|
||||
ASSERT_TRUE(TileID(2, -4, 0).isChildOf(TileID(1, -2, 0)));
|
||||
ASSERT_TRUE(TileID(3, -1, 0).isChildOf(TileID(1, -1, 0)));
|
||||
ASSERT_TRUE(TileID(3, -2, 0).isChildOf(TileID(1, -1, 0)));
|
||||
ASSERT_TRUE(TileID(3, -3, 0).isChildOf(TileID(1, -1, 0)));
|
||||
ASSERT_TRUE(TileID(3, -4, 0).isChildOf(TileID(1, -1, 0)));
|
||||
ASSERT_TRUE(TileID(3, -5, 0).isChildOf(TileID(1, -2, 0)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user