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