FeatureSourceVectorTileSource¶
Namespace: ThinkGeo.Core
Serves classic feature sources (shapefile, in-memory, database, ...) as vector tiles cut on the fly, so they can be rendered from a MapLibre style JSON. Each source is keyed by the name style JSON layers reference as "source-layer"; a tile request queries that source for the tile extent, clips and quantizes the result into MVT tile space, and hands it back decoded.
public class FeatureSourceVectorTileSource : IVectorTileSource, IRawVectorTileSource, System.IDisposable
Inheritance object → FeatureSourceVectorTileSource
Implements IVectorTileSource, IRawVectorTileSource, IDisposable
Remarks:
This is a data source, not a layer: it has no styles and never draws — the renderer that consumes IVectorTileSource owns all drawing. The wrapped sources stay the authoritative data; the tiles are a display-only projection of them.
The cutting is Core's FeatureSourceVectorTileCutter, shared with every other consumer of vector tiles; what is here is the reading of its tiles into the features the GPU renderer's style pipeline takes, keyed the way that pipeline looks them up.
It is an IRawVectorTileSource as well: the bytes the cutter encodes are handed out as they are, so a Web API overlay serves them to a browser and a renderer that builds from bytes takes them without the decode to features.
The tile cutter reads each source the way its FeatureSource.ConcurrentAccess allows - the one instance shared or taking turns, or copies made once at open - and in every case the instance handed in is one of its readers. Share it with code of your own that queries it only when it is ConcurrentAccess.Safe; otherwise query a of it, 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". Adding without a key names the layer after the data itself.
public FeatureSourceLayerCollection FeatureSources { get; }
Property Value¶
SourceId¶
Gets or sets the source id the sources are exposed under. Style JSON layers reference the data as "source": SourceId, "source-layer": the key in FeatureSourceVectorTileSource.FeatureSources. Registering the source with a MapStyle - AddVectorTiles, AddStyle - sets it to the name given there, so the layers and the tiles agree; and because the tiles carry it, one source holds one name. A second registration under another name is refused: build a second source over the same feature sources for the second name.
public string SourceId { get; set; }
Property Value¶
TileMatrixSet¶
Gets the tile grid tiles are cut on.
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 empty coverage 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 the engine sets itself - two less than the processor count, between 1 and 4. How each source is shared across those cuts is the source's own FeatureSource.ConcurrentAccess, so an application has no reason to touch this; it is here for tests and diagnostics that need one cut at a time, and stays out of IntelliSense. Applied when the source is opened.
public int MaxConcurrentEncodes { get; set; }
Property Value¶
MaxCachedCutTiles¶
Gets or sets how many cut tiles this source keeps, least recently used first out. Zero keeps none. Cutting is the dominant cost, so panning back over ground already visited should not pay for it twice; the cache empties itself whenever the data changes. See FeatureSourceVectorTileCutter.MaxCachedCutTiles.
public int MaxCachedCutTiles { get; set; }
Property Value¶
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 cut into that tile as well as its own, so a wide stroke or a large symbol near the edge is drawn whole rather than cut off at it. Set it at least as wide as the widest stroke or symbol reaches; a wider buffer queries more ground and puts more features in every tile. FeatureLayerTranslator sets it to the widest DrawingMarginInPixel of the layers translated into this source, as the classic drawing pads its query by that margin. Whichever was set last is in effect: a translation replaces a value set before it, and a value set after a translation holds until the next one.
Changed while the source is open, it is treated as a change to the data behind every tile: the tiles already cut are dropped, along with this source's tiles in FeatureSourceVectorTileSource.VectorTileCache, and FeatureSourceVectorTileSource.DataChanged is raised for the whole source, so a map showing it forgets the tiles it decoded and cuts them again. Tiles kept in a FeatureSourceVectorTileSource.VectorTileCache by an earlier run are not told: when the buffer differs from the one they were cut with, clear that cache, or give the source another FeatureSourceVectorTileSource.SourceId.
VectorTileCache¶
Where cut tiles are kept between runs, or null to cut every time. The encoded tile - the same MVT bytes an MBTiles or PMTiles archive holds - is written under FeatureSourceVectorTileSource.SourceId and read back before the sources are queried again, so a tile that took seconds to cut costs a file read the next time. The same FileTileCache the vector tile sources and the classic MVT layer take. The cache does not watch the data: when it changes, tell the map (GpuBasemap.RefreshVectorTiles), which drops the cached tiles of the area as well, or clear the cache yourself. A tile the sources have nothing in is not kept; cutting one is a query that returns nothing. https://community.thinkgeo.com/t/wmsrastertilesource-wmtsrastertilesource-and-authentication/12470
public FileTileCache VectorTileCache { get; set; }
Property Value¶
IsOpen¶
Gets a value indicating whether the sources are open and ready to serve tiles.
public bool IsOpen { get; }
Property Value¶
Constructors¶
FeatureSourceVectorTileSource()¶
Initializes a new instance with no sources; add them to FeatureSourceVectorTileSource.FeatureSources.
public FeatureSourceVectorTileSource()
FeatureSourceVectorTileSource(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 FeatureSourceVectorTileSource(RectangleShape tileGridExtent, GeographyUnit tileGridUnit)
Parameters¶
tileGridExtent RectangleShape
The ground the root tile covers, square - see
.
tileGridUnit GeographyUnit
The unit is in.
Remarks:
A renderer reads the grid off this source, so a source built this way is what puts a map on that coordinate system rather than on Web Mercator.
Nothing else is needed. The map puts its camera on this grid's ladder of zoom scales when it opens - the two have to agree or nothing draws, and that is not something an application could be expected to know:
var source = new FeatureSourceVectorTileSource(gridExtent, GeographyUnit.Meter);
source.FeatureSources.Add("roads", myShapefileSource);
mapView.MapUnit = GeographyUnit.Meter;
mapView.CurrentExtent = new RectangleShape(...); // in the grid's own coordinates
A ladder the application sets itself for this grid is left alone.
What a map on a projected grid does NOT have: a display projection or the globe (their transforms take mercator metres), 3D terrain (its DEM is addressed on the mercator grid), a raster source published on any other grid, and data overlays (their conversion target is mercator). Each of those says so rather than drawing something plausible.
https://community.thinkgeo.com/t/wms-wfs-feedback-wishes/12476
FeatureSourceVectorTileSource(RectangleShape, Projection)¶
Initializes a new instance that cuts on a grid built around the data's ground, in the data's own coordinate system - the shape to reach for when the data is not on web mercator.
public FeatureSourceVectorTileSource(RectangleShape tileGridExtent, Projection projection)
Parameters¶
tileGridExtent RectangleShape
The ground the root tile covers, in - a shapefile's own
bounding box is the usual answer. A rectangle is grown into the smallest square that
covers it, centred on it.
projection Projection
The coordinate system the ground and the data are in. The grid states it, so the map
says what its coordinates mean and a basemap can be reprojected onto it -
basemap.ReprojectOnto(source.TileMatrixSet).
Remarks:
The ground-and-unit constructor builds the same grid without saying which system its metres are in, so nothing can be reprojected onto it.
FeatureSourceVectorTileSource(TileMatrixSet)¶
Initializes a new instance that cuts on a grid the caller built.
public FeatureSourceVectorTileSource(TileMatrixSet tileMatrixSet)
Parameters¶
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:
The shape to reach for when the data is not on web mercator. A grid that names its coordinate system lets the map say what its coordinates mean, which is what a geometry overlay is compared against before it is drawn, and what tells one source cut on a national grid from another cut on mercator.
Methods¶
A(int)¶
internal double A(int )
Parameters¶
`` int
Returns¶
A(float)¶
internal void A(float )
Parameters¶
`` float
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.
GetFeaturesFromTileAsync(int, long, long, CancellationToken)¶
Cuts the requested tile from the wrapped sources and returns its features, keyed as "SourceId|sourceLayerName" so style JSON source/source-layer lookups match.
public Task<Dictionary<string, Collection<Feature>>> GetFeaturesFromTileAsync(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.
cancellationToken CancellationToken
A cancellation token.
Returns¶
Task<Dictionary<string, Collection<Feature>>>
A task that represents the asynchronous operation and provides the result.
a(RectangleShape)¶
internal void a(RectangleShape )
Parameters¶
Returns¶
B(RectangleShape)¶
internal RectangleShape B(RectangleShape )
Parameters¶
Returns¶
Dispose()¶
Closes the wrapped sources.
public void Dispose()
Returns¶
Dispose(bool)¶
Releases the resources held by this source.
protected void Dispose(bool disposing)
Parameters¶
disposing bool
True when called from .
Returns¶
A(Feature, A&)¶
internal static void A(Feature , A& )
Parameters¶
`` Feature
`A&`
Returns¶
Events¶
DataChanged¶
Drops the cached files of the tiles meeting - every tile of this source when it is null - so the next request cuts them again. The map's RefreshVectorTiles reaches here; nothing to do without a cache.
public event EventHandler<TileSourceDataChangedEventArgs> DataChanged;
Remarks:
Raised for a committed transaction on any of the FeatureSourceVectorTileSource.FeatureSources, and for features added to or removed from an InMemoryFeatureSource's InternalFeatures collection directly. What it cannot see is a feature object that is already in the collection having its geometry changed in place - nothing announces that, and only a call to the map's RefreshVectorTiles will pick it up. https://community.thinkgeo.com/t/features-cut-off-on-tile-border-with-gpu-rendering/12481