Allow interpolation to be configured for data tile sources
This commit is contained in:
@@ -16,6 +16,8 @@ import TileState from './TileState.js';
|
|||||||
* @property {function(): Promise<Data>} loader Data loader.
|
* @property {function(): Promise<Data>} loader Data loader.
|
||||||
* @property {number} [transition=250] A duration for tile opacity
|
* @property {number} [transition=250] A duration for tile opacity
|
||||||
* transitions in milliseconds. A duration of 0 disables the opacity transition.
|
* transitions in milliseconds. A duration of 0 disables the opacity transition.
|
||||||
|
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||||
|
* the nearest neighbor is used when resampling.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -26,10 +28,27 @@ class DataTile extends Tile {
|
|||||||
constructor(options) {
|
constructor(options) {
|
||||||
const state = TileState.IDLE;
|
const state = TileState.IDLE;
|
||||||
|
|
||||||
super(options.tileCoord, state, {transition: options.transition});
|
super(options.tileCoord, state, {
|
||||||
|
transition: options.transition,
|
||||||
|
interpolate: options.interpolate,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {function(): Promise<Data>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
this.loader_ = options.loader;
|
this.loader_ = options.loader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Data}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
this.data_ = null;
|
this.data_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Error}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
this.error_ = null;
|
this.error_ = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ import {easeIn} from './easing.js';
|
|||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
* @property {number} [transition=250] A duration for tile opacity
|
* @property {number} [transition=250] A duration for tile opacity
|
||||||
* transitions in milliseconds. A duration of 0 disables the opacity transition.
|
* transitions in milliseconds. A duration of 0 disables the opacity transition.
|
||||||
|
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||||
|
* the nearest neighbor is used when resampling.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -123,6 +125,11 @@ class Tile extends EventTarget {
|
|||||||
* @type {Object<string, number>}
|
* @type {Object<string, number>}
|
||||||
*/
|
*/
|
||||||
this.transitionStarts_ = {};
|
this.transitionStarts_ = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.interpolate = !!options.interpolate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import {toPromise} from '../functions.js';
|
|||||||
* @property {boolean} [wrapX=false] Render tiles beyond the antimeridian.
|
* @property {boolean} [wrapX=false] Render tiles beyond the antimeridian.
|
||||||
* @property {number} [transition] Transition time when fading in new tiles (in miliseconds).
|
* @property {number} [transition] Transition time when fading in new tiles (in miliseconds).
|
||||||
* @property {number} [bandCount=4] Number of bands represented in the data.
|
* @property {number} [bandCount=4] Number of bands represented in the data.
|
||||||
|
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||||
|
* the nearest neighbor is used when resampling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,6 +73,7 @@ class DataTileSource extends TileSource {
|
|||||||
tilePixelRatio: options.tilePixelRatio,
|
tilePixelRatio: options.tilePixelRatio,
|
||||||
wrapX: options.wrapX,
|
wrapX: options.wrapX,
|
||||||
transition: options.transition,
|
transition: options.transition,
|
||||||
|
interpolate: options.interpolate,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,6 +93,12 @@ class DataTileSource extends TileSource {
|
|||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.bandCount = options.bandCount === undefined ? 4 : options.bandCount; // assume RGBA if undefined
|
this.bandCount = options.bandCount === undefined ? 4 : options.bandCount; // assume RGBA if undefined
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.interpolate_ = !!options.interpolate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -315,6 +315,8 @@ function getMaxForDataType(array) {
|
|||||||
* @property {number} [transition=250] Duration of the opacity transition for rendering.
|
* @property {number} [transition=250] Duration of the opacity transition for rendering.
|
||||||
* To disable the opacity transition, pass `transition: 0`.
|
* To disable the opacity transition, pass `transition: 0`.
|
||||||
* @property {boolean} [wrapX=false] Render tiles beyond the tile grid extent.
|
* @property {boolean} [wrapX=false] Render tiles beyond the tile grid extent.
|
||||||
|
* @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,
|
||||||
|
* the linear interpolation is used to resample the data. If false, nearest neighbor is used.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -333,6 +335,7 @@ class GeoTIFFSource extends DataTile {
|
|||||||
projection: null,
|
projection: null,
|
||||||
opaque: options.opaque,
|
opaque: options.opaque,
|
||||||
transition: options.transition,
|
transition: options.transition,
|
||||||
|
interpolate: options.interpolate !== false,
|
||||||
wrapX: options.wrapX,
|
wrapX: options.wrapX,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ import {scale as scaleSize, toSize} from '../size.js';
|
|||||||
* @property {number} [transition] Transition.
|
* @property {number} [transition] Transition.
|
||||||
* @property {string} [key] Key.
|
* @property {string} [key] Key.
|
||||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection.
|
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection.
|
||||||
|
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||||
|
* the nearest neighbor is used when resampling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +124,10 @@ class TileSource extends Source {
|
|||||||
* @protected
|
* @protected
|
||||||
* @type {import("../Tile.js").Options}
|
* @type {import("../Tile.js").Options}
|
||||||
*/
|
*/
|
||||||
this.tileOptions = {transition: options.transition};
|
this.tileOptions = {
|
||||||
|
transition: options.transition,
|
||||||
|
interpolate: options.interpolate,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zDirection hint, read by the renderer. Indicates which resolution should be used
|
* zDirection hint, read by the renderer. Indicates which resolution should be used
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ class TileImage extends UrlTile {
|
|||||||
urls: options.urls,
|
urls: options.urls,
|
||||||
wrapX: options.wrapX,
|
wrapX: options.wrapX,
|
||||||
transition: options.transition,
|
transition: options.transition,
|
||||||
|
interpolate: options.imageSmoothing !== false,
|
||||||
key: options.key,
|
key: options.key,
|
||||||
attributionsCollapsible: options.attributionsCollapsible,
|
attributionsCollapsible: options.attributionsCollapsible,
|
||||||
zDirection: options.zDirection,
|
zDirection: options.zDirection,
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import {getUid} from '../util.js';
|
|||||||
* @property {number} [transition] Transition.
|
* @property {number} [transition] Transition.
|
||||||
* @property {string} [key] Key.
|
* @property {string} [key] Key.
|
||||||
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection.
|
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection.
|
||||||
|
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||||
|
* the nearest neighbor is used when resampling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,6 +51,7 @@ class UrlTile extends TileSource {
|
|||||||
tilePixelRatio: options.tilePixelRatio,
|
tilePixelRatio: options.tilePixelRatio,
|
||||||
wrapX: options.wrapX,
|
wrapX: options.wrapX,
|
||||||
transition: options.transition,
|
transition: options.transition,
|
||||||
|
interpolate: options.interpolate,
|
||||||
key: options.key,
|
key: options.key,
|
||||||
attributionsCollapsible: options.attributionsCollapsible,
|
attributionsCollapsible: options.attributionsCollapsible,
|
||||||
zDirection: options.zDirection,
|
zDirection: options.zDirection,
|
||||||
|
|||||||
@@ -11,21 +11,28 @@ import WebGLArrayBuffer from './Buffer.js';
|
|||||||
import {ARRAY_BUFFER, STATIC_DRAW} from '../webgl.js';
|
import {ARRAY_BUFFER, STATIC_DRAW} from '../webgl.js';
|
||||||
import {toSize} from '../size.js';
|
import {toSize} from '../size.js';
|
||||||
|
|
||||||
function bindAndConfigure(gl, texture) {
|
/**
|
||||||
|
* @param {WebGLRenderingContext} gl The WebGL context.
|
||||||
|
* @param {WebGLTexture} texture The texture.
|
||||||
|
* @param {boolean} interpolate Interpolate when resampling.
|
||||||
|
*/
|
||||||
|
function bindAndConfigure(gl, texture, interpolate) {
|
||||||
|
const resampleFilter = interpolate ? gl.LINEAR : gl.NEAREST;
|
||||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, resampleFilter);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, resampleFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {WebGLRenderingContext} gl The WebGL context.
|
* @param {WebGLRenderingContext} gl The WebGL context.
|
||||||
* @param {WebGLTexture} texture The texture.
|
* @param {WebGLTexture} texture The texture.
|
||||||
* @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image The image.
|
* @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image The image.
|
||||||
|
* @param {boolean} interpolate Interpolate when resampling.
|
||||||
*/
|
*/
|
||||||
function uploadImageTexture(gl, texture, image) {
|
function uploadImageTexture(gl, texture, image, interpolate) {
|
||||||
bindAndConfigure(gl, texture);
|
bindAndConfigure(gl, texture, interpolate);
|
||||||
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
||||||
}
|
}
|
||||||
@@ -36,10 +43,18 @@ function uploadImageTexture(gl, texture, image) {
|
|||||||
* @param {import("../DataTile.js").Data} data The pixel data.
|
* @param {import("../DataTile.js").Data} data The pixel data.
|
||||||
* @param {import("../size.js").Size} size The pixel size.
|
* @param {import("../size.js").Size} size The pixel size.
|
||||||
* @param {number} bandCount The band count.
|
* @param {number} bandCount The band count.
|
||||||
|
* @param {boolean} interpolate Interpolate when resampling.
|
||||||
*/
|
*/
|
||||||
function uploadDataTexture(helper, texture, data, size, bandCount) {
|
function uploadDataTexture(
|
||||||
|
helper,
|
||||||
|
texture,
|
||||||
|
data,
|
||||||
|
size,
|
||||||
|
bandCount,
|
||||||
|
interpolate
|
||||||
|
) {
|
||||||
const gl = helper.getGL();
|
const gl = helper.getGL();
|
||||||
bindAndConfigure(gl, texture);
|
bindAndConfigure(gl, texture, interpolate);
|
||||||
|
|
||||||
const bytesPerRow = data.byteLength / size[1];
|
const bytesPerRow = data.byteLength / size[1];
|
||||||
let unpackAlignment = 1;
|
let unpackAlignment = 1;
|
||||||
@@ -174,7 +189,7 @@ class TileTexture extends EventTarget {
|
|||||||
const texture = gl.createTexture();
|
const texture = gl.createTexture();
|
||||||
this.textures.push(texture);
|
this.textures.push(texture);
|
||||||
this.bandCount = 4;
|
this.bandCount = 4;
|
||||||
uploadImageTexture(gl, texture, tile.getImage());
|
uploadImageTexture(gl, texture, tile.getImage(), tile.interpolate);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +206,14 @@ class TileTexture extends EventTarget {
|
|||||||
if (textureCount === 1) {
|
if (textureCount === 1) {
|
||||||
const texture = gl.createTexture();
|
const texture = gl.createTexture();
|
||||||
this.textures.push(texture);
|
this.textures.push(texture);
|
||||||
uploadDataTexture(helper, texture, data, this.size, this.bandCount);
|
uploadDataTexture(
|
||||||
|
helper,
|
||||||
|
texture,
|
||||||
|
data,
|
||||||
|
this.size,
|
||||||
|
this.bandCount,
|
||||||
|
tile.interpolate
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +251,14 @@ class TileTexture extends EventTarget {
|
|||||||
const texture = this.textures[textureIndex];
|
const texture = this.textures[textureIndex];
|
||||||
const textureData = textureDataArrays[textureIndex];
|
const textureData = textureDataArrays[textureIndex];
|
||||||
const bandCount = textureData.length / pixelCount;
|
const bandCount = textureData.length / pixelCount;
|
||||||
uploadDataTexture(helper, texture, textureData, this.size, bandCount);
|
uploadDataTexture(
|
||||||
|
helper,
|
||||||
|
texture,
|
||||||
|
textureData,
|
||||||
|
this.size,
|
||||||
|
bandCount,
|
||||||
|
tile.interpolate
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1010 B |
@@ -0,0 +1,31 @@
|
|||||||
|
import DataTile from '../../../../src/ol/source/DataTile.js';
|
||||||
|
import Map from '../../../../src/ol/Map.js';
|
||||||
|
import TileLayer from '../../../../src/ol/layer/WebGLTile.js';
|
||||||
|
import View from '../../../../src/ol/View.js';
|
||||||
|
|
||||||
|
const size = 256;
|
||||||
|
|
||||||
|
const data = new Uint8Array(size * size);
|
||||||
|
for (let row = 0; row < size; ++row) {
|
||||||
|
for (let col = 0; col < size; ++col) {
|
||||||
|
data[row * size + col] = (row + col) % 2 === 0 ? 255 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Map({
|
||||||
|
target: 'map',
|
||||||
|
layers: [
|
||||||
|
new TileLayer({
|
||||||
|
source: new DataTile({
|
||||||
|
maxZoom: 0,
|
||||||
|
loader: () => data,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
view: new View({
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 4,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
render();
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,32 @@
|
|||||||
|
import DataTile from '../../../../src/ol/source/DataTile.js';
|
||||||
|
import Map from '../../../../src/ol/Map.js';
|
||||||
|
import TileLayer from '../../../../src/ol/layer/WebGLTile.js';
|
||||||
|
import View from '../../../../src/ol/View.js';
|
||||||
|
|
||||||
|
const size = 256;
|
||||||
|
|
||||||
|
const data = new Uint8Array(size * size);
|
||||||
|
for (let row = 0; row < size; ++row) {
|
||||||
|
for (let col = 0; col < size; ++col) {
|
||||||
|
data[row * size + col] = (row + col) % 2 === 0 ? 255 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Map({
|
||||||
|
target: 'map',
|
||||||
|
layers: [
|
||||||
|
new TileLayer({
|
||||||
|
source: new DataTile({
|
||||||
|
maxZoom: 0,
|
||||||
|
interpolate: true,
|
||||||
|
loader: () => data,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
view: new View({
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 4,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
render();
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 105 KiB |
Reference in New Issue
Block a user