1 #include <mbgl/tile/custom_geometry_tile.hpp>
2 #include <mbgl/tile/geojson_tile_data.hpp>
3 #include <mbgl/renderer/query.hpp>
4 #include <mbgl/renderer/tile_parameters.hpp>
5 #include <mbgl/actor/scheduler.hpp>
6 #include <mbgl/util/string.hpp>
7 #include <mbgl/tile/tile_observer.hpp>
8 #include <mbgl/style/custom_tile_loader.hpp>
9
10 #include <mapbox/geojsonvt.hpp>
11
12 namespace mbgl {
13
CustomGeometryTile(const OverscaledTileID & overscaledTileID,std::string sourceID_,const TileParameters & parameters,const style::CustomGeometrySource::TileOptions options_,ActorRef<style::CustomTileLoader> loader_)14 CustomGeometryTile::CustomGeometryTile(const OverscaledTileID& overscaledTileID,
15 std::string sourceID_,
16 const TileParameters& parameters,
17 const style::CustomGeometrySource::TileOptions options_,
18 ActorRef<style::CustomTileLoader> loader_)
19 : GeometryTile(overscaledTileID, sourceID_, parameters),
20 necessity(TileNecessity::Optional),
21 options(options_),
22 loader(loader_),
23 mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())),
24 actorRef(*this, mailbox) {
25 }
26
~CustomGeometryTile()27 CustomGeometryTile::~CustomGeometryTile() {
28 loader.invoke(&style::CustomTileLoader::removeTile, id);
29 }
30
setTileData(const GeoJSON & geoJSON)31 void CustomGeometryTile::setTileData(const GeoJSON& geoJSON) {
32
33 auto featureData = mapbox::geometry::feature_collection<int16_t>();
34 if (geoJSON.is<FeatureCollection>() && !geoJSON.get<FeatureCollection>().empty()) {
35 const double scale = util::EXTENT / options.tileSize;
36
37 mapbox::geojsonvt::TileOptions vtOptions;
38 vtOptions.extent = util::EXTENT;
39 vtOptions.buffer = ::round(scale * options.buffer);
40 vtOptions.tolerance = scale * options.tolerance;
41 featureData = mapbox::geojsonvt::geoJSONToTile(geoJSON,
42 id.canonical.z, id.canonical.x, id.canonical.y,
43 vtOptions, options.wrap, options.clip).features;
44 }
45 setData(std::make_unique<GeoJSONTileData>(std::move(featureData)));
46 }
47
invalidateTileData()48 void CustomGeometryTile::invalidateTileData() {
49 stale = true;
50 observer->onTileChanged(*this);
51 }
52
53 //Fetching tile data for custom sources is assumed to be an expensive operation.
54 // Only required tiles make fetchTile requests. Attempt to cancel a tile
55 // that is no longer required.
setNecessity(TileNecessity newNecessity)56 void CustomGeometryTile::setNecessity(TileNecessity newNecessity) {
57 if (newNecessity != necessity || stale ) {
58 necessity = newNecessity;
59 if (necessity == TileNecessity::Required) {
60 loader.invoke(&style::CustomTileLoader::fetchTile, id, actorRef);
61 stale = false;
62 } else if (!isRenderable()) {
63 loader.invoke(&style::CustomTileLoader::cancelTile, id);
64 }
65 }
66 }
67
querySourceFeatures(std::vector<Feature> & result,const SourceQueryOptions & queryOptions)68 void CustomGeometryTile::querySourceFeatures(
69 std::vector<Feature>& result,
70 const SourceQueryOptions& queryOptions) {
71
72 // Ignore the sourceLayer, there is only one
73 auto layer = getData()->getLayer({});
74
75 if (layer) {
76 auto featureCount = layer->featureCount();
77 for (std::size_t i = 0; i < featureCount; i++) {
78 auto feature = layer->getFeature(i);
79
80 // Apply filter, if any
81 if (queryOptions.filter && !(*queryOptions.filter)(style::expression::EvaluationContext { static_cast<float>(id.overscaledZ), feature.get() })) {
82 continue;
83 }
84
85 result.push_back(convertFeature(*feature, id.canonical));
86 }
87 }
88 }
89
90 } // namespace mbgl
91