FeatureSourceVectorTileCutter¶
Namespace: ThinkGeo.Core
Cuts classic feature sources (shapefile, in-memory, database, ...) into vector tiles on demand, so that whatever draws vector tiles - MapLibre in a browser, the GPU renderer on the desktop - can draw them from a style JSON. Each source is keyed by the name a style JSON layer gives as "source-layer"; a tile request queries that source for the tile's extent, clips and quantizes the result into tile space and hands back the encoded tile.
public class FeatureSourceVectorTileCutter : System.IDisposable
Inheritance object → FeatureSourceVectorTileCutter
Implements IDisposable
Remarks:
This is a data source, not a layer: it has no styles and never draws. The wrapped sources stay the authoritative data; the tiles are a display-only projection of them. The encoding itself is VectorMbTilesGenerator's - the same cutter that writes an MBTiles file - and so a tile comes back gzipped, the way that file stores them.
Three things stand between the encoder and being usable on demand, and they are what this type is for. A feature source usually cannot be queried from two threads at once and deep-cloning it per tile is ruinous, so each concurrent cut rents a slot, and each source decides through its FeatureSource.ConcurrentAccess what a slot holds: one instance shared by all of them, a copy made once at open, or the one instance with the reads taking turns. A source stored with continuous longitudes across the antimeridian is queried one world to either side and folded back into the square, so its far half is not silently lost. And a source declared to never change keeps its cut tiles, because cutting is the dominant cost and the second request for a tile is common.
A source that is shared rather than copied is queried directly, so it must not also be given to another consumer that queries it concurrently while this cutter is open unless that source is ConcurrentAccess.Safe. Give the other consumer a taken before either is opened.
Properties¶
FeatureSources¶
Gets the sources served as tile content. The key each source is added under is its source-layer name - what a style JSON layer names in "source-layer".
public GeoCollection<FeatureSource> FeatureSources { get; }
Property Value¶
TileMatrixSet¶
Gets the tile grid tiles are cut on, 512 pixels a tile. Web Mercator unless the constructor was given another one.
public TileMatrixSet TileMatrixSet { get; }
Property Value¶
MaxDataZoom¶
Gets or sets the deepest zoom level tiles are cut at. Cutting is on the fly and local, so the default lets every display zoom get tiles cut at its own level: overzooming would only magnify a tile's coordinate quantization into visibly stepped edges. Lower it to trade sharpness for fewer re-cuts.
public int MaxDataZoom { get; set; }
Property Value¶
MinDataZoom¶
Gets or sets the shallowest zoom level tiles are cut at. Below it a tile request returns nothing instead of querying the sources. The default of 0 is right for local data, which answers any extent instantly; set it when a source is a remote service (WFS, OGC API Features), where a low-zoom tile is a bounding-box query for half a country.
public int MinDataZoom { get; set; }
Property Value¶
MaxConcurrentEncodes¶
Gets or sets how many tiles may be cut at the same time: a CPU budget, two less than the processor count by default, between 1 and 4. How each source is shared across those cuts is the source's own FeatureSource.ConcurrentAccess. Here for tests and diagnostics that need one cut at a time; hidden from IntelliSense. Applied when the cutter is opened.
public int MaxConcurrentEncodes { get; set; }
Property Value¶
MaxCachedCutTiles¶
Gets or sets how many cut tiles to keep, least recently used first out. Zero keeps none and cuts every tile on every request.
public int MaxCachedCutTiles { get; set; }
Property Value¶
Remarks:
Cutting is what this class spends its time on - 0.3 to 1.9 s for a busy tile - so panning back over ground already visited should not pay for it twice. The cache is emptied whenever the data behind the cut changes, which is what lets it be on without a promise from the caller that the data is static.
The one change it cannot hear about is a feature object already in a source having its geometry edited in place: nothing announces that, and a cached tile will go on showing the old shape until the map's RefreshVectorTiles is called. Set this to 0 for data edited that way.
https://community.thinkgeo.com/t/features-cut-off-on-tile-border-with-gpu-rendering/12481
TileBufferInPixel¶
Gets or sets how far past its own edge a tile is cut, in tile pixels (a tile is 512). The default is 8.
public int TileBufferInPixel { get; set; }
Property Value¶
Exceptions¶
ArgumentOutOfRangeException
The value is negative or more than a tile wide.
Remarks:
A feature within this distance of a tile's edge is written into that tile as well as its own, so a stroke or a symbol that reaches across the edge is drawn whole on both sides. A wide stroke or a large symbol needs a buffer at least as wide as it reaches; a wider buffer queries more ground and writes more features into every tile.
Changed while the cutter is open, every tile already cut is dropped and each slot's encode options are taken again before the next cut, as a change to the data does ().
IsOpen¶
Gets a value indicating whether the sources are open and ready to cut.
public bool IsOpen { get; }
Property Value¶
Constructors¶
FeatureSourceVectorTileCutter()¶
Initializes a new instance with no sources; add them to FeatureSourceVectorTileCutter.FeatureSources.
public FeatureSourceVectorTileCutter()
FeatureSourceVectorTileCutter(GeoCollection<FeatureSource>)¶
Initializes a new instance over a collection the caller keeps hold of, so that a type wrapping this one can hand out the same collection under its own name.
public FeatureSourceVectorTileCutter(GeoCollection<FeatureSource> featureSources)
Parameters¶
featureSources GeoCollection<FeatureSource>
The sources served as tile content, keyed by source-layer name.
FeatureSourceVectorTileCutter(GeoCollection<FeatureSource>, RectangleShape, GeographyUnit)¶
Initializes a new instance that cuts on a grid of the caller's choosing, for data in a projected coordinate system of its own - EPSG:25832, say - that is to be served in that system rather than converted to Web Mercator.
public FeatureSourceVectorTileCutter(GeoCollection<FeatureSource> featureSources, RectangleShape tileGridExtent, GeographyUnit tileGridUnit)
Parameters¶
featureSources GeoCollection<FeatureSource>
The sources served as tile content, keyed by source-layer name.
tileGridExtent RectangleShape
The ground the root tile covers - the whole grid as one tile at zoom 0, quartered
at each level below. Hand over the ground you care about and not a grid: a
shapefile's own bounding box is the usual answer. A quadtree root is square, so a
rectangle is grown into the smallest square that covers it, centred on it - the
data is inside either way and what grows is the empty margin on the shorter axis.
A root already square is used exactly as given, so a grid that came from elsewhere
is never nudged.
tileGridUnit GeographyUnit
The unit is in.
Remarks:
The sources must deliver coordinates in that same system; this cutter does not reproject, exactly as the Web Mercator one does not. Nothing is folded across a world edge either - a projected grid is a region, not a world that closes onto itself. https://community.thinkgeo.com/t/wms-wfs-feedback-wishes/12476
FeatureSourceVectorTileCutter(GeoCollection<FeatureSource>, RectangleShape, Projection)¶
Initializes a new instance that cuts on a grid built around the ground given, in the coordinate system given - for data in a projected system of its own, EPSG:25832 say, served in that system rather than converted to Web Mercator.
public FeatureSourceVectorTileCutter(GeoCollection<FeatureSource> featureSources, RectangleShape tileGridExtent, Projection projection)
Parameters¶
featureSources GeoCollection<FeatureSource>
The sources served as tile content, keyed by source-layer name.
tileGridExtent RectangleShape
The ground the root tile covers, in : hand over the ground
you care about, a shapefile's own bounding box, and a rectangle is grown into the
smallest square that covers it, centred on it. A root already square is used exactly.
projection Projection
The coordinate system the ground and the data are in. The grid states it, so the map
can say what its coordinates mean and a raster can be reprojected onto it with
; the unit comes from it.
Remarks:
The ground-and-unit constructor builds the same grid without saying which system its metres are in, which is half of what a coordinate means.
FeatureSourceVectorTileCutter(GeoCollection<FeatureSource>, TileMatrixSet)¶
Initializes a new instance that cuts on a grid the caller built.
public FeatureSourceVectorTileCutter(GeoCollection<FeatureSource> featureSources, TileMatrixSet tileMatrixSet)
Parameters¶
featureSources GeoCollection<FeatureSource>
The sources served as tile content, keyed by source-layer name.
tileMatrixSet TileMatrixSet
The grid, which is the whole description: its root tile, its levels, its tile size, and the coordinate system it is laid out in.
Remarks:
Prefer this over the extent-and-unit constructor. A grid states its unit on every level and, when it names one, its coordinate system - so there is one thing to pass and nothing that can disagree with anything else. An extent and a unit handed over separately cannot say which system those metres are in, and metres on a national grid read as web mercator land on another continent.
Methods¶
A(int)¶
internal double A(int )
Parameters¶
`` int
Returns¶
a(int)¶
internal int a(int )
Parameters¶
`` int
Returns¶
OpenAsync(CancellationToken)¶
Opens the wrapped sources and prepares one set of tile encode options per concurrency slot.
public Task OpenAsync(CancellationToken cancellationToken)
Parameters¶
cancellationToken CancellationToken
A cancellation token.
Returns¶
Task
A task that represents the asynchronous operation.
b()¶
internal void b()
Returns¶
GetTileAsync(int, long, long, CancellationToken)¶
Cuts one tile from the wrapped sources.
public Task<Byte[]> GetTileAsync(int zoom, long x, long y, CancellationToken cancellationToken)
Parameters¶
zoom int
The tile zoom level.
x long
The tile column.
y long
The tile row, counted from the north.
cancellationToken CancellationToken
A cancellation token.
Returns¶
The tile as gzipped Mapbox Vector Tile bytes, or null when nothing falls in it. A
tile asked for beyond is the covering tile from that
level - on a power-of-two grid, column x >> (zoom - MaxDataZoom), row likewise.
Dispose()¶
Closes the wrapped sources and the clones made of them - at once when no tile is being cut, otherwise as soon as the cuts in flight are done.
public void Dispose()
Returns¶
Dispose(bool)¶
Releases the resources held by this cutter.
protected void Dispose(bool disposing)
Parameters¶
disposing bool
True when called from .