Simplify vector tile projection handling
This commit is contained in:
@@ -24,10 +24,10 @@ class VectorTile extends Tile {
|
||||
this.consumers = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Extent of this tile; set by the source.
|
||||
* @type {import("./extent.js").Extent}
|
||||
*/
|
||||
this.extent_ = null;
|
||||
this.extent = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -48,11 +48,16 @@ class VectorTile extends Tile {
|
||||
this.loader_;
|
||||
|
||||
/**
|
||||
* Data projection
|
||||
* @private
|
||||
* Feature projection of this tile; set by the source.
|
||||
* @type {import("./proj/Projection.js").default}
|
||||
*/
|
||||
this.projection_ = null;
|
||||
this.projection = null;
|
||||
|
||||
/**
|
||||
* Resolution of this tile; set by the source.
|
||||
* @type {number}
|
||||
*/
|
||||
this.resolution;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -76,15 +81,6 @@ class VectorTile extends Tile {
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extent of the vector tile.
|
||||
* @return {import("./extent.js").Extent} The extent.
|
||||
* @api
|
||||
*/
|
||||
getExtent() {
|
||||
return this.extent_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the feature format assigned for reading this tile's features.
|
||||
* @return {import("./format/Feature.js").default} Feature format.
|
||||
@@ -95,8 +91,7 @@ class VectorTile extends Tile {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the features for this tile. Geometries will be in the projection returned
|
||||
* by {@link module:ol/VectorTile~VectorTile#getProjection}.
|
||||
* Get the features for this tile. Geometries will be in the view projection.
|
||||
* @return {Array<import("./Feature.js").FeatureLike>} Features.
|
||||
* @api
|
||||
*/
|
||||
@@ -111,16 +106,6 @@ class VectorTile extends Tile {
|
||||
return this.url_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the feature projection of features returned by
|
||||
* {@link module:ol/VectorTile~VectorTile#getFeatures}.
|
||||
* @return {import("./proj/Projection.js").default} Feature projection.
|
||||
* @api
|
||||
*/
|
||||
getProjection() {
|
||||
return this.projection_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -128,7 +113,7 @@ class VectorTile extends Tile {
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.setState(TileState.LOADING);
|
||||
this.tileLoadFunction_(this, this.url_);
|
||||
this.loader_(null, NaN, null);
|
||||
this.loader_(this.extent, this.resolution, this.projection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,11 +121,8 @@ class VectorTile extends Tile {
|
||||
* Handler for successful tile load.
|
||||
* @param {Array<import("./Feature.js").default>} features The loaded features.
|
||||
* @param {import("./proj/Projection.js").default} dataProjection Data projection.
|
||||
* @param {import("./extent.js").Extent} extent Extent.
|
||||
*/
|
||||
onLoad(features, dataProjection, extent) {
|
||||
this.setProjection(dataProjection);
|
||||
this.setExtent(extent);
|
||||
onLoad(features, dataProjection) {
|
||||
this.setFeatures(features);
|
||||
}
|
||||
|
||||
@@ -151,22 +133,6 @@ class VectorTile extends Tile {
|
||||
this.setState(TileState.ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s
|
||||
* `tileLoadFunction`. Sets the extent of the vector tile. This is only required
|
||||
* for tiles in projections with `tile-pixels` as units. The extent should be
|
||||
* set to `[0, 0, tilePixelSize, tilePixelSize]`, where `tilePixelSize` is
|
||||
* calculated by multiplying the tile size with the tile pixel ratio. For
|
||||
* sources using {@link module:ol/format/MVT~MVT} as feature format, the
|
||||
* {@link module:ol/format/MVT~MVT#getLastExtent} method will return the correct
|
||||
* extent.
|
||||
* @param {import("./extent.js").Extent} extent The extent.
|
||||
* @api
|
||||
*/
|
||||
setExtent(extent) {
|
||||
this.extent_ = extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
||||
* Sets the features for the tile.
|
||||
@@ -178,17 +144,6 @@ class VectorTile extends Tile {
|
||||
this.setState(TileState.LOADED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
||||
* Sets the projection of the features that were added with
|
||||
* {@link module:ol/VectorTile~VectorTile#setFeatures}.
|
||||
* @param {import("./proj/Projection.js").default} projection Feature projection.
|
||||
* @api
|
||||
*/
|
||||
setProjection(projection) {
|
||||
this.projection_ = projection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the feature loader for reading this tile's features.
|
||||
* @param {import("./featureloader.js").FeatureLoader} loader Feature loader.
|
||||
|
||||
@@ -83,9 +83,11 @@ export function loadFeaturesXhr(url, format, success, failure) {
|
||||
source = /** @type {ArrayBuffer} */ (xhr.response);
|
||||
}
|
||||
if (source) {
|
||||
success.call(this, format.readFeatures(source,
|
||||
{featureProjection: projection}),
|
||||
format.readProjection(source), format.getLastExtent());
|
||||
success.call(this, format.readFeatures(source, {
|
||||
extent: extent,
|
||||
featureProjection: projection
|
||||
}),
|
||||
format.readProjection(source));
|
||||
} else {
|
||||
failure.call(this);
|
||||
}
|
||||
|
||||
@@ -111,14 +111,6 @@ class FeatureFormat {
|
||||
}, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extent from the source of the last {@link readFeatures} call.
|
||||
* @return {import("../extent.js").Extent} Tile extent.
|
||||
*/
|
||||
getLastExtent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @return {import("./FormatType.js").default} Format.
|
||||
|
||||
@@ -19,6 +19,7 @@ import {linearRingIsClockwise} from '../geom/flat/orient.js';
|
||||
import Projection from '../proj/Projection.js';
|
||||
import Units from '../proj/Units.js';
|
||||
import RenderFeature from '../render/Feature.js';
|
||||
import {get} from '../proj.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -83,12 +84,6 @@ class MVT extends FeatureFormat {
|
||||
*/
|
||||
this.layers_ = options.layers ? options.layers : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../extent.js").Extent}
|
||||
*/
|
||||
this.extent_ = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,10 +154,10 @@ class MVT extends FeatureFormat {
|
||||
* @private
|
||||
* @param {PBF} pbf PBF
|
||||
* @param {Object} rawFeature Raw Mapbox feature.
|
||||
* @param {import("./Feature.js").ReadOptions=} opt_options Read options.
|
||||
* @param {import("./Feature.js").ReadOptions} options Read options.
|
||||
* @return {import("../Feature.js").FeatureLike} Feature.
|
||||
*/
|
||||
createFeature_(pbf, rawFeature, opt_options) {
|
||||
createFeature_(pbf, rawFeature, options) {
|
||||
const type = rawFeature.type;
|
||||
if (type === 0) {
|
||||
return null;
|
||||
@@ -181,6 +176,7 @@ class MVT extends FeatureFormat {
|
||||
|
||||
if (this.featureClass_ === RenderFeature) {
|
||||
feature = new this.featureClass_(geometryType, flatCoordinates, ends, values, id);
|
||||
feature.transform(options.dataProjection, options.featureProjection);
|
||||
} else {
|
||||
let geom;
|
||||
if (geometryType == GeometryType.POLYGON) {
|
||||
@@ -213,7 +209,7 @@ class MVT extends FeatureFormat {
|
||||
if (this.geometryName_) {
|
||||
feature.setGeometryName(this.geometryName_);
|
||||
}
|
||||
const geometry = transformGeometryWithOptions(geom, false, this.adaptOptions(opt_options));
|
||||
const geometry = transformGeometryWithOptions(geom, false, options);
|
||||
feature.setGeometry(geometry);
|
||||
feature.setId(id);
|
||||
feature.setProperties(values, true);
|
||||
@@ -222,14 +218,6 @@ class MVT extends FeatureFormat {
|
||||
return feature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getLastExtent() {
|
||||
return this.extent_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -238,15 +226,22 @@ class MVT extends FeatureFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Read all features.
|
||||
*
|
||||
* @param {ArrayBuffer} source Source.
|
||||
* @param {import("./Feature.js").ReadOptions=} opt_options Read options.
|
||||
* @return {Array<import("../Feature.js").FeatureLike>} Features.
|
||||
* @api
|
||||
*/
|
||||
readFeatures(source, opt_options) {
|
||||
const layers = this.layers_;
|
||||
const options = /** @type {import("./Feature.js").ReadOptions} */ (this.adaptOptions(opt_options));
|
||||
const dataProjection = get(options.dataProjection);
|
||||
dataProjection.setWorldExtent(options.extent);
|
||||
options.dataProjection = dataProjection;
|
||||
|
||||
const pbf = new PBF(/** @type {ArrayBuffer} */ (source));
|
||||
const pbfLayers = pbf.readFields(layersPBFReader, {});
|
||||
/** @type {Array<import("../Feature.js").FeatureLike>} */
|
||||
const features = [];
|
||||
for (const name in pbfLayers) {
|
||||
if (layers && layers.indexOf(name) == -1) {
|
||||
@@ -254,11 +249,13 @@ class MVT extends FeatureFormat {
|
||||
}
|
||||
const pbfLayer = pbfLayers[name];
|
||||
|
||||
const extent = pbfLayer ? [0, 0, pbfLayer.extent, pbfLayer.extent] : null;
|
||||
dataProjection.setExtent(extent);
|
||||
|
||||
for (let i = 0, ii = pbfLayer.length; i < ii; ++i) {
|
||||
const rawFeature = readRawFeature(pbf, pbfLayer, i);
|
||||
features.push(this.createFeature_(pbf, rawFeature));
|
||||
features.push(this.createFeature_(pbf, rawFeature, options));
|
||||
}
|
||||
this.extent_ = pbfLayer ? [0, 0, pbfLayer.extent, pbfLayer.extent] : null;
|
||||
}
|
||||
|
||||
return features;
|
||||
|
||||
@@ -10,8 +10,6 @@ import EventType from '../../events/EventType.js';
|
||||
import rbush from 'rbush';
|
||||
import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js';
|
||||
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
|
||||
import {equivalent as equivalentProjection} from '../../proj.js';
|
||||
import Units from '../../proj/Units.js';
|
||||
import ReplayType from '../../render/canvas/BuilderType.js';
|
||||
import {labelCache} from '../../render/canvas.js';
|
||||
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
|
||||
@@ -264,12 +262,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
const sharedExtent = getIntersection(tileExtent, sourceTileExtent);
|
||||
const bufferedExtent = equals(sourceTileExtent, sharedExtent) ? null :
|
||||
buffer(sharedExtent, layer.getRenderBuffer() * resolution, this.tmpExtent);
|
||||
const tileProjection = sourceTile.getProjection();
|
||||
let reproject = false;
|
||||
if (!equivalentProjection(projection, tileProjection)) {
|
||||
reproject = true;
|
||||
sourceTile.setProjection(projection);
|
||||
}
|
||||
builderState.dirty = false;
|
||||
const builderGroup = new CanvasBuilderGroup(0, sharedExtent, resolution,
|
||||
pixelRatio, !!this.declutterTree_);
|
||||
@@ -298,15 +290,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
}
|
||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||
const feature = features[i];
|
||||
if (reproject) {
|
||||
if (tileProjection.getUnits() == Units.TILE_PIXELS) {
|
||||
// projected tile extent
|
||||
tileProjection.setWorldExtent(sourceTileExtent);
|
||||
// tile extent in tile pixel space
|
||||
tileProjection.setExtent(sourceTile.getExtent());
|
||||
}
|
||||
feature.getGeometry().transform(tileProjection, projection);
|
||||
}
|
||||
if (!bufferedExtent || intersects(bufferedExtent, feature.getGeometry().getExtent())) {
|
||||
render.call(this, feature);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import {equals} from '../array.js';
|
||||
* to `false` (e.g. for sources with polygons that represent administrative
|
||||
* boundaries or TopoJSON sources) allows the renderer to optimise fill and
|
||||
* stroke operations.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Projection of the tile grid.
|
||||
* @property {import("./State.js").default} [state] Source state.
|
||||
* @property {typeof import("../VectorTile.js").default} [tileClass] Class used to instantiate image tiles.
|
||||
* Default is {@link module:ol/VectorTile}.
|
||||
@@ -35,18 +35,20 @@ import {equals} from '../array.js';
|
||||
* @property {number|import("../size.js").Size} [tileSize=512] Optional tile size.
|
||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction]
|
||||
* Optional function to load a tile given a URL. Could look like this:
|
||||
* Optional function to load a tile given a URL. Could look like this for pbf tiles:
|
||||
* ```js
|
||||
* function(tile, url) {
|
||||
* tile.setLoader(function() {
|
||||
* var data = // ... fetch data
|
||||
* var format = tile.getFormat();
|
||||
* tile.setProjection(format.readProjection(data));
|
||||
* tile.setExtent(format.getLastExtent()); // line only required for ol/format/MVT
|
||||
* tile.setFeatures(format.readFeatures(data, {
|
||||
* // featureProjection is not required for ol/format/MVT
|
||||
* featureProjection: map.getView().getProjection()
|
||||
* }));
|
||||
* tile.setLoader(function(extent, resolution, projection) {
|
||||
* fetch(url).then(function(response) {
|
||||
* response.arrayBuffer().then(function(data) {
|
||||
* const format = tile.getFormat() // ol/format/MVT configured as source format
|
||||
* const features = format.readFeatures(data, {
|
||||
* extent: extent,
|
||||
* featureProjection: projection
|
||||
* });
|
||||
* tile.setFeatures(features);
|
||||
* });
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
@@ -187,9 +189,9 @@ class VectorTile extends UrlTile {
|
||||
const sourceTileGrid = this.tileGrid;
|
||||
const sourceExtent = sourceTileGrid.getExtent();
|
||||
if (sourceExtent) {
|
||||
getIntersection(extent, sourceTileGrid.getExtent(), extent);
|
||||
getIntersection(extent, sourceExtent, extent);
|
||||
}
|
||||
const sourceZ = sourceTileGrid.getZForResolution(resolution);
|
||||
const sourceZ = sourceTileGrid.getZForResolution(resolution/*, 1*/);
|
||||
const minZoom = sourceTileGrid.getMinZoom();
|
||||
|
||||
let loadedZ = sourceZ + 1;
|
||||
@@ -215,6 +217,9 @@ class VectorTile extends UrlTile {
|
||||
tileUrl == undefined ? TileState.EMPTY : TileState.IDLE,
|
||||
tileUrl == undefined ? '' : tileUrl,
|
||||
this.format_, this.tileLoadFunction);
|
||||
sourceTile.extent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
|
||||
sourceTile.projection = projection;
|
||||
sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
|
||||
this.sourceTiles_[tileKey] = sourceTile;
|
||||
empty = empty && sourceTile.getState() === TileState.EMPTY;
|
||||
listen(sourceTile, EventType.CHANGE, this.handleTileChange, this);
|
||||
|
||||
Reference in New Issue
Block a user