import { CustomLayerInterface, CustomRenderMethodInput, MapProjectionEvent, Map as MapSDK } from '@maptiler/sdk'; import { Extent } from 'ol/extent.js'; import { ColoringFragmentBase, MultiChannelGradientColoringFragment } from '../../core/ColoringFragment'; import { Tile, TileTextureSource } from '../../core/TileTextureSource'; import { TimeFrame, TimeFrameAnimation } from '../../core/TimeFrameAnimation'; import { GlobeTilesService } from '../../tiles/GlobeTilesService'; import { TileLayerOptions, TilePlacement, TileList } from './types'; import * as three from "three"; /** * Special layer that can be added to MapTiler SDK's Map. * Consists of multiple timeframes, every frame is a tile pyramid in a different moment in time. * The individual frames are smoothly animated. * Decoding of the data and their visual representation is configurable. */ declare class TileLayer extends TimeFrameAnimation implements CustomLayerInterface { id: string; type: "custom"; renderingMode: "3d"; /** * Instance of MapTiler SDK map */ protected map: MapSDK | null; protected dataMinZoom: number; protected dataMaxZoom: number; /** * Array of array of Tiles (plane geometry meshes) */ protected readonly slippyTiles: Array>; /** * Renderer to render the tiles */ protected renderer: three.WebGLRenderer | null; /** * Camera used to render the tiles */ protected readonly camera: three.Camera; /** * Scene to add the tiles to */ protected readonly scene: three.Scene; /** * The shader material of the tiles (with uniforms such as textures, time, etc.) * TODO: Fix the initialisation to get rid of the `!` operator */ private material; /** * The plane geometry used for all the tiles */ private geometry; /** * A TileGrid (from OL) that contains some tile logic such as mercator to index, etc. */ private tilegrid; /** * Extent as in OL */ private extent; /** * Indicated whether the the function `map.triggerRepaint()` should be called * when the animation is paused. */ private repaintOnPausedAnimation; /** * Manages a pool of rawshadermaterial to reuse, rather cloning endlessly */ private materialPool; private bluringNodePasses; /** * ratio to wich the extent is enlarged when using the method `.getVisibleExtent()` */ protected extentScale: number; /** * The event `"extentChanged"` is emitted when the intersection-over-union ration from the former extent to the new * is below this.extentChangedThreshold */ private extentChangedThreshold; private lastExtent; private timeInterpolation; protected isReady: boolean; private defaultTexture; private onMoveEndListener; private onResizeListener; private onMoveListener; private onProjectionChangedListener; private coloringFragments; private multiChannelColoringFragment; private loadLowerZoomLevels; private interpolateTileEdge; private flusher; /** * Globe related changes */ protected globeTilesService: GlobeTilesService; protected threeWorldGroup: three.Group; protected slippyTilesGroup: three.Group; /** * @param id Unique identifier of the layer in the map. * @param options * @param coloringFragments * @param multiChannelColoringFragment */ constructor(id: string, options: TileLayerOptions | null, coloringFragments?: ColoringFragmentBase[] | null, multiChannelColoringFragment?: MultiChannelGradientColoringFragment | null); /** * TODO: Add description */ protected init(options: TileLayerOptions, coloringFragments?: ColoringFragmentBase[] | null, multiChannelColoringFragment?: MultiChannelGradientColoringFragment | null): void; /** * @description Event handler - callback when the window is resized. */ protected onResize(): void; /** * @description Event handler - callback when the map is moved. */ protected onMove(): void; /** * @description Event handler - called when the map movement ends. */ protected onMoveEnd(): void; /** * @description Event handler - called when projection is changed */ onProjectionChanged(event: MapProjectionEvent): void; /** * Remove the current tiles of the tile grid from the scene and reinstanciate them all * (three.Mesh) based onthe arguments, then add them to the scene again. * Note: The tils positions are not updated yet, this is performed by `.updateSlippyTile()` * @param width * @param height */ private updateSlippyTileGrid; /** * TODO: Add description */ private validateSource; /** * Adds another frame to the animation. * @param time Time of the data in this frame. Should be unique. * @param url URL to the tiles. Expected to have `{zxy}` placeholder to be dynamically replaced with `z/x/y` coordinates. */ addSource(time: number, url: string, loadedCallback?: ((tile: Tile, url?: string, error?: ErrorEvent | null) => void) | null): void; /** * Removes frame */ removeSource(time: number): void; /** * Get the Extent as defined in OL * @param scale * @returns */ getVisibleExtent(scale?: number): Extent | null; /** * Get the list of all the tiles wanted for this extent and from the min zoom to the max zoom. * This is used to prevent updating tiles that are not in this list in `.updateSlippyTile()` * @param currentZ * @returns {TileList} */ getWantedTiles(currentZ: number, minZoom: number, maxZoom: number): TileList; /** * Changes the global opacity of the layer. * Default is `1` * * @param opacity Opacity 0-1. */ setOpacity(opacity: number): void; /** * Method from CustomLayerInterface, called when the layer is added to the map * @param map * @param gl */ onAdd(map: MapSDK, gl: WebGLRenderingContext | WebGL2RenderingContext): void; /** * Method which should be override by the child class * for additional logic which has to be done: * - on adding the layer to the map * - on mouseEnd event */ protected refresh(): void; /** * The method is called when the layer is removed from the map * `CustomLayerInterface` method */ onRemove(_map: MapSDK, _gl: WebGLRenderingContext | WebGL2RenderingContext): void; /** * Remove some data allocated (not of the tiles) */ protected disposeObjects(): void; /** * Get the TilePlacement from a zxy * @param source * @param load * @param z * @param x * @param y * @param originalTileCoordinates * @returns */ private getTilePlacement; /** * WARNING: Globe projection only * * Update the tiles textures * TODO: Make mercator mode also use this method instead of `updateSlippyTiles` */ private updateTilesMaterials; /** * WARNING: Mercator projection only * * Update the tile's mesh position and size, as well each tile material uniforms (time, texture, etc.) * * @returns {void} */ protected updateSlippyTiles(): void; /** * TODO: Add description */ protected getTilesPair(frameA: TimeFrame, frameB: TimeFrame, tileId: string): { tileA: TilePlacement; tileB: TilePlacement; } | null; /** * `CustomLayerInterface` method * This is used to apply the map matrix to the local camera */ prerender(_gl: WebGLRenderingContext | WebGL2RenderingContext, options: CustomRenderMethodInput): void; /** * The reason for this method is to allow child classes to do some work during the prerender phase */ protected prerenderInternal(): void; /** * `CustomLayerInterface` method * It is used to render the local tiles into the MapTiler SDK context */ render(_gl: WebGLRenderingContext | WebGL2RenderingContext, _options: CustomRenderMethodInput): void; /** * The reason for this method is to allow child classes to do some work during the render phase * (after renderer state reset and before the actual rendering) */ protected renderInternal(): void; /** * Get layer image decoded value (decoded means on the real world interval such as provided [decode.min, decode.max]) * @param lng * @param lat * @param source * @returns */ private pickFrame; /** * TODO: Add description */ private pickFrameBilinear; /** * Picks the best currently available values at the position. * * The values are read from the already loaded tiles at the current time. * * Return the interpolated array of decoded values * of the same length as the number of specified coloring fragments. * * If the coloring fragments uses more channels (e.g. "rg"), * the corresponding value is an array of `[r value, g value, sqrt(r^2 + g^2)]`. * * @param lng * @param lat * @returns Array of decoded interpolated values. In case of using a multi-channel coloring fragment, the returned value is an array where the first value is the value and the second is the category */ pick(lng: number, lat: number, options?: { /** * Enable bilinear interpolation if `true`, otherwise, the picking will be based on the nearest neighbor (NN) pixel. * NN has less impact on performance because it requires less texture reading, so it is generaly faster. Bilinear is more precise * and will retrieve values that are closer to what is being displayed (since tiles are rendered using a native-GPU bilinear method) * Default: `false` */ bilinear?: boolean; /** * If `true`, the picking will be perfomed on the highest resolution tile available. If `false`, the picking is done on the tile currently showing on the map. */ highestRes?: boolean; /** * Will force the loading of the tile if it was not already cached. * Usually unnecesary when the picking is done from hovering the pointer on the map, unless the option `.highRes` is `true`. * Default: `false`. */ load?: boolean; }): number[] | null; /** * The map is available only after the layer is attached to the map * The method simplifies the access to the map object */ protected getMapOrThrow: () => MapSDK; /** * The renderer is available only after the layer is attached to the map * The method simplifies the access to the renderer object */ protected getRendererOrThrow: () => three.WebGLRenderer; /** * The method simplifies the access to the triggerRepaint method */ forceRepaint(): void; /** * Get the current mixed image as a ImageData, meaning with pixel data, width, height and number of channels * Used by: Weather Plus * @param options.zxy The tile ID * @param options.blurKernel Size of the bluring kernel * @param options.outputSize Size of the outpout image (-1 means same as input). Note that the bluring is applied on an image of this size. * @returns ImageData | null */ computeCurrentMixedImage({ zxy, blurKernel, outputSize, channel, }: { zxy?: string; blurKernel?: number; outputSize?: number; channel?: string; }): ImageData | null; /** * Enables data interpolation between keyframes when true. Only shows keyframe data when false. * @param ti */ setTimeInterpolation(ti: boolean): void; /** * Enable smoothing category color when true. Hard edge between categories when false. * This seeting applies only to TileLayers using MultiChannelGradientColoringFragment * as the other types of oloring fragment do not use categories. * @param cst */ setCategorySmoothTransition(cst: boolean): void; /** * If `true`, enables the local smoothing * @param s */ setLocalSmoothing(s: boolean): void; /** * Defines the size of the smoothing kernel * @param d */ setMaxSmoothingDistance(d: number): void; /** * Defines by what factor the smoothing kernel size is reduced with increasing zoom level * @param f */ setSmoothingDistanceDecayFactor(f: number): void; /** * Get whether or not the frames continues to rendered on a paused animation * @returns */ getRepaintOnPausedAnimation(): boolean; /** * If `true`, even the paused animation is rendered up to 60 times * per seconds. If `false`, the rendering is paused when the animation is paused. * Pausing the animation has side effects: * - it lowers energy consumtion * - it prevents overheating * - it pauses time-independant annimation (arrows, particles) * @param r */ setRepaintOnPausedAnimation(r: boolean): void; /** * Wrapping telemetry registration with protected method to allow registration of modules which extends this class */ protected registerTelemetry(map: MapSDK): void; } export { TileLayer }; /** * TODO: * - Add explanation * - Export to separate file, somehow */ interface ImageData { /** * The pixel data */ data: Uint8Array; /** * The number of channels of the image (example: if image is RGBA then channels is 4) */ channels: number; /** * Width of the image */ width: number; /** * Height of the image */ height: number; }