tangrams / tangram-es

2D and 3D map renderer using OpenGL ES
MIT License
823 stars 239 forks source link

Core MBTiles Support #960

Closed hallahan closed 7 years ago

hallahan commented 8 years ago

As discussed in #931, an important feature many would like to add is offline map tile support. After a bit of further discussion, it looks like the consensus is to build MBTiles support into the data sources.

MBTiles is a spec that has been maintained since 2011, primarily as a tile storage and transport container. Because it is a widely used method to store tiles, both vector and image, it seems only logical to continue using this schema to store vector tiles offline.

The spec itself describes the SQLite database schema that is required for the file to be considered MBTiles. Right now the spec only describes the contents of a tile to be png or jpg. @pnorman, however, has submitted a PR that adds geojson, topojson, o5m, and mvt to the list of valid formats. In addition, there will be a compression field in the MBTiles metadata table that declares the codec in which tile contents may be compressed.

In the wild, you can find MBTiles storing vector tiles in several places. The most notable example is osm2vectortiles.org.

My thought is that we want to use MBTiles in two key ways: 1) As a tile store and transport mechanism, and 2) as a cache.

Tile Store

There are currently several apps and map SDKs that store raster and vector tiles offline, however, the approach is often only of a caching nature. You will specify a bbox and zoom range in the application, and the application will fetch tiles from an HTTP endpoint, one-by-one. This approach is cumbersome and slow, particulary on a poor internet connection. An alternative workflow would be for Mapzen and others to generate and store pre-populated MBTiles on the server. This approach is consistent with osm2vectortiles, and it can potentially lend well as an addition to Mapzen Metro Extracts.

Cache

Regardless of whether we have an MBTiles data source that has been pre-populated, we want to be able to request tiles ad hoc as we currently do and add them to an MBTiles. At this time, there is an in-memory tile cache of 32MB, and this is a great way to cache tiles in session. However, a persistent cache will be a helpful way to keep tile data over a longer span of time. This should be more resilient than platform-specific caching mechanisms (#623).

scene.yaml

To satisfy having MBTiles as both a container store and cache, we can essentially add a new field to a data source called mbtiles.

sources:
    osm:
        type: GeoJSON
        url:  https://vector.mapzen.com/osm/all/{z}/{x}/{y}.json
        mbtiles: /Users/njh/osm-data/mbtiles/winters-mapzen-geojson.mbtiles
        max_zoom: 16
        url_params:
            api_key: vector-tiles-tyHL4AY

This source can both use the MBTiles file both as a store and a cache. I prepopulated an MBTiles file from Mapzen's tile API for a small town (Winters, CA). This was done with the NodeJS command line tool, tl.

tl copy -z 0 -Z 16 -b '-122.041626 38.486517 -121.920261 38.546017' 'https://vector.mapzen.com/osm/all/{z}/{x}/{y}.json?api_key=vector-tiles-rxXwLYv' mbtiles://./winters-mapzen-geojson.mbtiles

With a url parameter specified for the source, when the device is online it will first request a tile from the HTTP endpoint. In addition to rendering that tile, it will store it in the MBTiles file. If we omit the url parameter, we will skip the HTTP request and instead just try to get the tile from the MBTiles store. This approach means that we try and get up-to-date data from HTTP every time if we are online. We fallback to MBTiles if we are offline.

My thought is that the MBTiles work can happen in the tile worker when a tile task is being processed. To run the tile task, instead of just checking to see if the tile task has data, we can also enqueue the task if the tile has an MBTiles store. Then, rather than simply parse the tile's rawData buffer, we can instead select that raw data from SQLite if it's not there.

To sum this up: rather than creating a new type of data source called MBTilesSource, we instead create a new property in the base DataSource. Any data source with an mbtiles: property can be treated as such.

SQLiteCpp

Though iOS and Android have their platform specific ways of accessing SQLite databases, it is straightforward using SQLiteCpp in our core C++ project. It is a CMake project, well documented and tested, and has a clean C++ API that wraps the core sqlite3 lib. I have been able to integrate this library into Tangram ES, and playing with it has proven successful so far.

Platforms

Right now I'm thinking it would be best to focus on adding the support on the core Tangram ES side of things. We can declare the path to the MBTiles file in the scene.yaml, however, it will also be important to add methods of adding an MBTiles data source in the Android and iOS APIs. In Android, we often need to use Android's API to get paths to files, particularly if we are interested in working in ExternalStorage. In those situations, reliably declaring the path to an MBTiles file in scene.yaml will not work. Maybe we should save that for a later issue?


I'm making a few assumptions as to how this should be done, so input from the team would be helpful as I'm getting started. Some of the implementation specifics I can work though, but I'd like a :thumbsup: / :thumbsdown: for the overall approach.

cc/ @tallytalwar @blair1618 @nvkelso @karimnaaji @bcamper @pnorman @mojodna @migurski

pnorman commented 8 years ago

A few thoughts

hallahan commented 8 years ago

We can check to see if the type key corresponds with the format key in the MBTiles metadata table. This is probably a good idea rather than just arbitrarily trying to use the contents of an MBTiles and hope for the best. If there were a mismatch and we had a url, then the MBTiles would start to be populated with tiles of a conflicting format...

If there is no url parameter in the source, we will only try and retrieve a tile from the MBTiles. The HTTP request for data will be skipped.

If there is both a url and mbtiles in the source, we will try to get data from the url and populate the MBTiles with that data as well as render it. If the URL request fails, we will continue and try to get data from MBTiles.

If there is only url, we will skip the MBTiles bit all together and continue with the current behavior.

pnorman commented 8 years ago

If there is both a url and mbtiles in the source, we will try to get data from the url and populate the MBTiles with that data as well as render it. If the URL request fails, we will continue and try to get data from MBTiles.

This gets into cache behavior. There's uses for preferring either mbtiles or url, and if preferring the url you need to figure out when you want to fall back to the mbtiles because timeouts can be slow.

hallahan commented 8 years ago

Do you have any suggestions on what makes sense regarding cache behavior? Are you thinking that more fine-grained control should be specifiable in the scene.yaml? Or, maybe there is a good best practice that should be implemented?

Here's the code where I'm doing what I described:

https://github.com/hallahan/tangram-es/blob/2e3404bedf49d88751afb4b4359294361f477cfa/core/src/data/dataSource.cpp#L180-L206

startUrlRequest is implemented as platform specific, though I'm pretty sure every platform will let you specify timeout rules. At least, I do know that is the case for Android.

Android's timeout rules:

https://github.com/hallahan/tangram-es/blob/2e3404bedf49d88751afb4b4359294361f477cfa/android/tangram/src/com/mapzen/tangram/HttpHandler.java#L27-L28

pnorman commented 8 years ago

Do you have any suggestions on what makes sense regarding cache behavior? Are you thinking that more fine-grained control should be specifiable in the scene.yaml? Or, maybe there is a good best practice that should be implemented?

As a minimum

MBtiles should be quick, but URL resources can be slow, and it's hard to know in advance how slow they will be, so a nice to have would be to specify the timeout for which the client falls back to the mbtiles.

Of interest might be the mod_tile settings in https://github.com/openstreetmap/mod_tile/blob/master/mod_tile.conf. Matt also has experience in this area.

hallahan commented 8 years ago

Cool. Maybe we could add the following source parameters?

max_timeout: 30 # default
cache_priority: false # default
pnorman commented 8 years ago

if they're on the same level as the url and mbtiles map, will it be clear what they apply to?

hallahan commented 8 years ago

My choice of parameter names might not be the best. I'm happy to do whatever is the consensus. This isn't a blocker right now, because this sort of thing is an extra I can do once the basic functionality works.

pnorman commented 8 years ago

My choice of parameter names might not be the best

I don't have a great alternative eithe

This isn't a blocker right now

Agreed

hallahan commented 8 years ago

Wohoo! Looks like we've got the basics of MBTiles functionality working!

screenshot 2016-09-09 18 29 44

tallytalwar commented 8 years ago

Super cool. Havn't got a chance to look at this yet. But yes great progress.

On Sep 9, 2016 9:32 PM, "Nicholas Hallahan" notifications@github.com wrote:

Wohoo! Looks like we've got the basics of MBTiles functionality working!

[image: screenshot 2016-09-09 18 29 44] https://cloud.githubusercontent.com/assets/556367/18407057/c5026130-76bb-11e6-9818-2d7870b5e5c9.png

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/tangrams/tangram-es/issues/960#issuecomment-246079666, or mute the thread https://github.com/notifications/unsubscribe-auth/AAWAwcDyTr0dOLcDUavz1yBbWG4smX4Cks5qogjAgaJpZM4J4dHy .

hallahan commented 8 years ago

By manually setting the file path for an MBTiles I have in ExternalStorage, I am now able to view my offline data on my Android device in airplane mode:

2016-09-16 01 12 32

It works right now if we set our source as:

sources:
    osm:
        type: GeoJSON
        mbtiles: /storage/emulated/0/mbtiles/winters-mapzen-geojson.mbtiles
        max_zoom: 16

This is great, because it proves that SQLiteCpp in the core library plays nicely on Android as-is. However, we need to be able to dynamically set our MBTiles file for two reasons:

  1. If the file is in ExternalStorage, as is this one, we have to first get the user's permission to access ExternalStorage before trying to open the .mbtiles file.
  2. File paths are not consistent across devices, so we really do need to call Android SDK methods like Environment.getExternalStorageDirectory() to figure out the path to our .mbtiles file.

Today I attempted to solve this with two approaches, with varying degrees of success. I'm actually trying to get this working on the Mac OS client first so that I can debug properly.

Do a Scene Update

map->queueSceneUpdate("sources.osm.mbtiles", "/Users/njh/osm-data/mbtiles/winters-mapzen-geojson.mbtiles");
map->applySceneUpdates();
requestRender();

The nice thing about this approach is that we don't have to add anything to Tangram::Map and JNI. We could work with the existing API. I was having a lot of problems earlier, but it seems to actually be behaving properly now (not sure why). Basically, a new scene with new sources would get built, but the reference to the source in the TileSets is a shared_ptr, and it's reference hasn't been updated to the new DataSource object that was just built. It is instead referencing that old object.

// in tileManager.h
struct TileSet {
        TileSet(std::shared_ptr<DataSource> _source, bool _clientDataSource)
            : source(_source), clientDataSource(_clientDataSource) {}

        std::shared_ptr<DataSource> source;
        std::map<TileID, TileEntry> tiles;
        int64_t sourceGeneration = 0;
        bool clientDataSource;
    };

It turns out, after quite a bit of tinkering, I hadn't added the mbtiles property to the DataSource::equals method. Without this being updated, the TileManager::setDataSources was thinking that the new data source is the same as the old data source, therefore leaving the old source pointer in place.

void TileManager::setDataSources(const std::vector<std::shared_ptr<DataSource>>& _sources) {
    m_tileCache->clear();

    // remove sources that are not in new scene - there must be a better way..
    auto it = std::remove_if(
        m_tileSets.begin(), m_tileSets.end(),
        [&](auto& tileSet) {
            if (!tileSet.clientDataSource) {
                auto sIt = std::find_if(_sources.begin(), _sources.end(),
                                        [&](auto& source){ return source->equals(*tileSet.source); });

                if (sIt == _sources.end() || !(*sIt)->generateGeometry()) {
                    LOGD("remove source %s", tileSet.source->name().c_str());
                    return true;
                }
            }
            // Clear cache
            tileSet.tiles.clear();
            return false;
        });

    m_tileSets.erase(it, m_tileSets.end());

    // add new sources
    for (const auto& source : _sources) {

        if (std::find_if(m_tileSets.begin(), m_tileSets.end(),
                         [&](const TileSet& a) {
                             return a.source->name() == source->name();
                         }) == m_tileSets.end()
                && source->generateGeometry()) {

            LOGD("add source %s", source->name().c_str());

            m_tileSets.push_back({ source, false });
        }
    }
}

Now this approach seems all good with the right DataSource::equals.

bool DataSource::equals(const DataSource& other) const {
    if (m_name != other.m_name) { return false; }
    if (m_urlTemplate != other.m_urlTemplate) { return false; }
    if (m_mbtilesPath != other.m_mbtilesPath) { return false; }
    if (m_minDisplayZoom != other.m_minDisplayZoom) { return false; }
    if (m_maxDisplayZoom != other.m_maxDisplayZoom) { return false; }
    if (m_maxZoom != other.m_maxZoom) { return false; }
    if (m_rasterSources.size() != other.m_rasterSources.size()) { return false; }
    for (size_t i = 0, end = m_rasterSources.size(); i < end; ++i) {
        if (!m_rasterSources[i]->equals(*other.m_rasterSources[i])) { return false; }
    }

    return true;
}

Update Properties in DataSource

https://github.com/hallahan/tangram-es/commit/8c8de4b7aac7416e9b6cf3147d3a54d7cc724af5

This approach adds a few extensions to the existing API, but it is a bit of a more direct. I don't have it working properly quite yet, and I may ditch this, unless @tallytalwar and @blair1618 think this is a better direction.

I added to bool DataSource::setMBTiles(const std::string& _mbtilesPath, const bool _offlineOnly) which added the MBTiles path to the data source. Offline only removes the url template so we stop trying to request from a URL if that was in the scene.yaml.

I also added bool Map::setMBTiles(const std::string& _dataSourceName, const std::string& _mbtilesPath, const bool _offlineOnly) which iterates through the scene's data sources and sets the mbtiles path and offline properties accordingly when it has a matching name.

The problems that I was having are:

  1. The current tiles in the view are not re-rendered.
  2. If we have no URL to start with the data source, adding MBTiles does not work. The view stays blank. No tile fetch attempts from the MBTiles are made.

I bet if I implement some of the dirty work done in TileManager::setDataSources, this can be resolved.

Serinox commented 7 years ago

I tried to get this working and ran into the following issue. If you go to http://osm2vectortiles.org they no longer offer any tile downloads and redirect you to https://openmaptiles.org/ which will give you download options. However these mbtile files do not appear to work with the example application. The metadata format claims it is pbf. Are these mbtile files supposed to work or did they change formats when they changed websites, does anybody know?

If I try the example application using the scene.yaml with the url and the cache (the first example above) I can get the cached mbtile file that results to work by itself in a new scene.yaml so I'm fairly confident that I've got things setup correctly.

Here is the output when trying to use the mbtile file from openmaptiles.com

DEBUG scene.cpp:51: Scene '' => '' : '' TANGRAM tangram.cpp:199: Loading scene file (async): /path_to_scene.yaml/scene.yaml DEBUG scene.cpp:51: Scene '/path_to_scene.yaml/scene.yaml' => '/path_to_scene.yaml/' : 'scene.yaml' DEBUG importer.cpp:80: Process: '/path_to_scene.yaml/scene.yaml' DEBUG importer.cpp:71: Processing scene import Stack: DEBUG importer.cpp:256: Starting importing Scene: /path_to_scene.yaml/scene.yaml TANGRAM mbtilesDataSource.cpp:241: SQLite database opened: /path_to_mbtiles/united_states_of_america.mbtiles WARNING sceneLoader.cpp:1694: Can't find data source touch for layer touch TANGRAM tangram.cpp:832: setup GL TANGRAM hardware.cpp:60: Driver supports map buffer: 0 TANGRAM hardware.cpp:61: Driver supports vaos: 1 TANGRAM hardware.cpp:62: Driver supports rgb8_rgba8: 0 TANGRAM hardware.cpp:63: Driver supports NPOT texture: 1 TANGRAM hardware.cpp:77: Hardware max texture size 16384 TANGRAM hardware.cpp:78: Hardware max combined texture units 16 ||snip GL info|| TANGRAM tangram.cpp:305: resize: 1600 x 1200 DEBUG tileManager.cpp:75: add source osm WARNING mbtilesDataSource.cpp:156: loaded tile: 4823/6160/14, 159525 TANGRAM tileWorker.cpp:51: Passed new TileBuilder to TileWorker WARNING mbtilesDataSource.cpp:156: loaded tile: 4824/6160/14, 169355 TANGRAM tileWorker.cpp:51: Passed new TileBuilder to TileWorker DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. recreate context TANGRAM tangram.cpp:832: setup GL TANGRAM hardware.cpp:60: Driver supports map buffer: 0 TANGRAM hardware.cpp:61: Driver supports vaos: 1 TANGRAM hardware.cpp:62: Driver supports rgb8_rgba8: 0 TANGRAM hardware.cpp:63: Driver supports NPOT texture: 1 TANGRAM hardware.cpp:77: Hardware max texture size 16384 TANGRAM hardware.cpp:78: Hardware max combined texture units 16 ||snip GL info|| TANGRAM tangram.cpp:305: resize: 1600 x 1200 DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined. DEBUG styleContext.cpp:468: duk evaluates JS method to null or undefined.

nvkelso commented 7 years ago

@lukasmartinelli do you what's going on with openmaptiles.org extracts?

On Sep 9, 2016, at 18:55, Varun notifications@github.com wrote:

Super cool. Havn't got a chance to look at this yet. But yes great progress.

On Sep 9, 2016 9:32 PM, "Nicholas Hallahan" notifications@github.com wrote:

Wohoo! Looks like we've got the basics of MBTiles functionality working!

[image: screenshot 2016-09-09 18 29 44] https://cloud.githubusercontent.com/assets/556367/18407057/c5026130-76bb-11e6-9818-2d7870b5e5c9.png

― You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/tangrams/tangram-es/issues/960#issuecomment-246079666, or mute the thread https://github.com/notifications/unsubscribe-auth/AAWAwcDyTr0dOLcDUavz1yBbWG4smX4Cks5qogjAgaJpZM4J4dHy .

― You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

lukasmartinelli commented 7 years ago

I tried to get this working and ran into the following issue. If you go to http://osm2vectortiles.org they no longer offer any tile downloads and redirect you to https://openmaptiles.org/ which will give you download options. However these mbtile files do not appear to work with the example application. The metadata format claims it is pbf. Are these mbtile files supposed to work or did they change formats when they changed websites, does anybody know?

Nothing changed format wise as we used the same components - what is a bit tricky is that the PBFs are gzipped inside the MBTiles (but they were for OSM2VectorTiles as well).

I only have an example of using the Tangram WebGL client as I did here: https://openmaptiles.org/docs/website/tangram/

Serinox commented 7 years ago

Ok thanks for letting me know, I've liberally sprinkled break points in the mvtSource.cpp file and in the parse method it does look like it is getting data as I can step through and watch it add points of interest and waterways etc to the tileData object. Chasing the data from the mvtSource file I've found that in the StyleBuilder.cpp addFeature method the line:

if (!checkRule(_rule)) { return false; }

always executes the return false because the breakpoint on the next block of code in the method never gets hit.

If I comment that return false bit then I see things getting drawn (although not correctly as things flash into and out of existance in nonsensical ways and I only seem to get waterways and continents). So any idea what I could be missing that makes that return fire every time?

hjanetzek commented 7 years ago

@Serinox To use openmaptiles you need a scene file with styling rules that match the tile data. See https://openmaptiles.org/schema for the layers/feature properties to match.

I made some (incomplete) modifications in scene.yaml to show openmaptiles with tangram https://gist.github.com/hjanetzek/8f2d8c4c7e485fdc0479e5ace6eb5d14 shot-2017-01-23_13-41-52

Serinox commented 7 years ago

@hjanetzek: Ok that got it working! Many Thanks!

karimnaaji commented 7 years ago

Merged as part of #1015

TGISer commented 7 years ago

@hjanetzek I use https://gist.github.com/hjanetzek/8f2d8c4c7e485fdc0479e5ace6eb5d14 but it can not show the map. Can you help me ,thank you!

matteblair commented 7 years ago

@TGISer Can you please create a new issue describing what you are trying to do? Thanks