UNPKG

@giro3d/giro3d

Version:

A JS/WebGL framework for 3D geospatial data visualization

510 lines 17.4 kB
import { Color, type ColorRepresentation, EventDispatcher, type MagnificationTextureFilter, type Material, type MinificationTextureFilter, type Object3D, type Object3DEventMap, type PixelFormat, type Texture, type TextureDataType, Vector2, type WebGLRenderTarget } from 'three'; import type RenderingContextHandler from '../../renderer/RenderingContextHandler'; import type ImageSource from '../../sources/ImageSource'; import type ColorMap from '../ColorMap'; import type Context from '../Context'; import type Disposable from '../Disposable'; import type ElevationRange from '../ElevationRange'; import type Coordinates from '../geographic/Coordinates'; import type CoordinateSystem from '../geographic/CoordinateSystem'; import type { GridExtent } from '../geographic/Extent'; import type Instance from '../Instance'; import type MemoryUsage from '../MemoryUsage'; import type OffsetScale from '../OffsetScale'; import type Progress from '../Progress'; import type RequestQueue from '../RequestQueue'; import type ColorLayer from './ColorLayer'; import type NoDataOptions from './NoDataOptions'; import Extent from '../geographic/Extent'; import { type GetMemoryUsageContext } from '../MemoryUsage'; import Shared from '../Shared'; import Interpretation from './Interpretation'; import LayerComposer from './LayerComposer'; export interface TextureAndPitch { texture: Texture; pitch: OffsetScale; } /** * Events for nodes. */ export interface LayerNodeEventMap extends Object3DEventMap { dispose: unknown; 'visibility-changed': unknown; } /** * A node material. */ export interface LayerNodeMaterial extends Material { setColorTextures(layer: ColorLayer, textureAndPitch: TextureAndPitch): void; setLayerVisibility(layer: ColorLayer, visible: boolean): void; setLayerOpacity(layer: ColorLayer, opacity: number): void; setLayerElevationRange(layer: ColorLayer, range: ElevationRange | null): void; setColorimetry(layer: ColorLayer, brightness: number, contrast: number, saturation: number): void; hasColorLayer(layer: ColorLayer): boolean; indexOfColorLayer(layer: ColorLayer): number; removeColorLayer(layer: ColorLayer): void; pushColorLayer(layer: ColorLayer, extent: Extent): void; } /** * Represents an object that can be painted by this layer. * Nodes might be map tiles or anything else that matches the interface definition. */ export interface LayerNode extends Object3D<LayerNodeEventMap> { /** * Is this node disposed ? */ disposed: boolean; /** * The node material. */ material: LayerNodeMaterial; /** * The node texture size, in pixels. */ textureSize: Vector2; /** * Gets whether this node can accept a color layer texture. */ canProcessColorLayer(): boolean; /** * The node's extent. */ getExtent(): Extent; /** * The LOD or depth level of this node in the hierarchy (the root node is level zero). */ lod: number; } declare enum TargetState { Pending = 0, Processing = 1, Complete = 2 } export declare class Target implements MemoryUsage { readonly isMemoryUsage: true; node: LayerNode; pitch: OffsetScale; extent: Extent; width: number; height: number; renderTarget: Shared<WebGLRenderTarget, this> | null; imageIds: Set<string>; controller: AbortController; state: TargetState; textureIsFinal: boolean; geometryExtent: Extent; paintCount: number; private _disposed; private _onVisibilityChanged; isDisposed(): boolean; getMemoryUsage(context: GetMemoryUsageContext): void; constructor(options: { node: LayerNode; extent: Extent; geometryExtent: Extent; pitch: OffsetScale; width: number; height: number; }); dispose(): void; private onVisibilityChanged; reset(): void; abort(): void; abortAndThrow(): void; } export interface LayerEvents { /** * Fires when layer visibility changes. */ 'visible-property-changed': { visible: boolean; }; /** * Fires when the layer is disposed. */ dispose: unknown; /** * Fires when a node has been completed. */ 'node-complete': { node: LayerNode; layer: Layer; }; } export interface LayerOptions { /** * An optional name for this layer. */ name?: string; /** * The source of the layer. */ source: ImageSource; /** * The optional extent to use for this layer. If none is provided, then the extent from the * source is used instead. The layer will not be visible outside this extent. */ extent?: Extent; /** * How to interpret the pixel data of the source. */ interpretation?: Interpretation; /** * Displays the border of source images. */ showTileBorders?: boolean; /** * Displays empty textures as colored rectangles. */ showEmptyTextures?: boolean; /** * How to treat no-data values. */ noDataOptions?: NoDataOptions; /** * Enables min/max computation of source images. Mainly used for elevation data. */ computeMinMax?: boolean; /** * The optional color map to use. */ colorMap?: ColorMap; /** * Enables or disable preloading of low resolution fallback images. Those fallback images * are used when no data is available yet on a particular region of the layer. */ preloadImages?: boolean; /** * The optional background color of the layer. */ backgroundColor?: ColorRepresentation; /** * The resolution factor applied to textures generated by this layer, compared to the pixel size * of the targets. Default is `1`. A value greater than one will create textures with a higher * resolution than what is asked by the targets. For example, if a map tile has a texture size * of 256\*256, and a layer has a resolution factor of 2, the generated textures will have a * size of 512\*512 pixels. */ resolutionFactor?: number; /** * The optional texture filter for minification. * @defaultValue Generally bilinear filtering, but some sources might provide different defaults. */ minFilter?: MinificationTextureFilter; /** * The optional texture filter for magnification. * @defaultValue Generally bilinear filtering, but some sources might provide different defaults. */ magFilter?: MagnificationTextureFilter; } export type LayerUserData = Record<string, unknown>; /** * Base class of layers. Layers are components of maps or any compatible entity. * * The same layer can be added to multiple entities. Don't forget to call {@link dispose} when the * layer should be destroyed, as removing a layer from an entity will not release memory associated * with the layer (such as textures). * * ## Layer nodes * * Layers generate textures to be applied to {@link LayerNode | nodes}. Nodes might be map tiles, point * cloud tiles or any object that matches the definition of the interface. * * ## Types of layers * * `Layer` is an abstract class. See subclasses for specific information. Main subclasses: * * - `ColorLayer` for color information, such as satellite imagery, vector data, etc. * - `ElevationLayer` for elevation and terrain data. * - `MaskLayer`: a special kind of layer that applies a mask on its host map. * * ## The `userData` property * * The `userData` property can be used to attach custom data to the layer, in a type safe manner. * It is recommended to use this property instead of attaching arbitrary properties to the object: * * ```ts * type MyCustomUserData = { * creationDate: Date; * owner: string; * }; * const newLayer = new ColorLayer<MyCustomUserData>({ ... }); * * newLayer.userData.creationDate = Date.now(); * newLayer.userData.owner = 'John Doe'; * ``` * * ## Reprojection capabilities * * When the {@link source} of the layer has a different coordinate system (CRS) than the instance, * the images from the source will be reprojected to the instance CRS. * * Note that doing so will have a performance cost in both CPU and memory. * * ```js * // Add and create a new Layer to an existing map. * const newLayer = new ColorLayer({ ... }); * * await map.addLayer(newLayer); * * // Change layer's visibilty * newLayer.visible = false; * instance.notifyChange(); // update instance * * // Change layer's opacity * newLayer.opacity = 0.5; * instance.notifyChange(); // update instance * * // Listen to properties * newLayer.addEventListener('visible-property-changed', (event) => console.log(event)); * ``` * @typeParam TEvents - The event map of the layer. * @typeParam TUserData - The type of the `userData` property. */ export declare abstract class Layer<TEvents extends LayerEvents = LayerEvents, TUserData extends LayerUserData = LayerUserData> extends EventDispatcher<TEvents & LayerEvents> implements Progress, MemoryUsage, RenderingContextHandler, Disposable { readonly isMemoryUsage: true; /** * Optional name of this layer. */ readonly name: string | undefined; /** * The unique identifier of this layer. */ readonly id: string; /** * Read-only flag to check if a given object is of type Layer. */ readonly isLayer: boolean; type: string; readonly interpretation: Interpretation; readonly showTileBorders: boolean; readonly showEmptyTextures: boolean; readonly noDataOptions: NoDataOptions; readonly computeMinMax: boolean; private _visible; /** The colormap of this layer */ readonly colorMap: ColorMap | null; /** The extent of this layer */ readonly extent: Extent | null; /** The source of this layer */ readonly source: ImageSource; /** @internal */ protected _composer: LayerComposer | null; private readonly _targets; private readonly _targetsToDestroy; private readonly _filter; /** @internal */ protected readonly _queue: RequestQueue; private readonly _opCounter; private _sortedTargets; private _instance; private _composerProjection; private readonly _createReadableTextures; private readonly _preloadImages; private readonly _minFilter?; private readonly _magFilter?; private _fallbackImagesPromise; /** The resolution factor applied to the textures generated by this layer. */ readonly resolutionFactor: number; private _preprocessOnce; private _onNodeDisposed; private _ready; backgroundColor: Color; /** * An object that can be used to store custom data about the {@link Layer}. */ readonly userData: TUserData; /** * Disables automatic updates of this layer. Useful for debugging purposes. */ frozen: boolean; get ready(): boolean; getMemoryUsage(context: GetMemoryUsageContext): void; /** * Creates a layer. * * @param options - The layer options. */ constructor(options: LayerOptions); private shouldCancelRequest; private onSourceUpdated; onRenderingContextLost(): void; onRenderingContextRestored(): void; /** * Resets all render targets to a blank state and repaint all the targets. * @param extent - An optional extent to limit the region to clear. */ clear(extent?: Extent): void; /** * Gets or sets the visibility of this layer. */ get visible(): boolean; set visible(v: boolean); get loading(): boolean; get progress(): number; /** * Initializes this layer. Note: this method is automatically called when the layer is added * to an entity. * * @param options - Initialization options. * @returns A promise that resolves when the initialization is complete. * @internal */ initialize(options: { /** * The instance to associate this layer. * Once set, the layer cannot be used with any other instance. */ instance: Instance; composerProjection: CoordinateSystem; }): Promise<this>; protected get instance(): Instance; /** * Perform the initialization. This should be called exactly once in the lifetime of the layer. */ private initializeOnce; /** * Returns the final extent of this layer. If this layer has its own extent defined, * this will be used. * Otherwise, will return the source extent (if any). * May return undefined if not pre-processed yet. * * @returns The layer final extent. */ getExtent(): Extent | undefined; loadFallbackImagesInternal(): Promise<void>; protected onTextureCreated(texture: Texture): void; private addToComposer; loadFallbackImages(): Promise<void>; /** * Called when the layer has finished initializing. */ protected onInitialized(): Promise<void>; private fetchImagesSync; private getExtentAsSourceCRS; /** * @param options - Options. * @returns A promise that is settled when all images have been fetched. */ private fetchImages; private destroyTarget; /** * Removes the node from this layer. * * @param node - The disposed node. */ unregisterNode(node: LayerNode, immediate?: boolean): void; protected adjustExtent(extent: Extent): Extent; /** * Adjusts the extent to avoid visual artifacts. * * @param originalExtent - The original extent. * @param originalWidth - The width, in pixels, of the original extent. * @param originalHeight - The height, in pixels, of the original extent. * @returns And object containing the adjusted extent, as well as adjusted pixel size. */ protected adjustExtentAndPixelSize(originalExtent: Extent, originalWidth: number, originalHeight: number): GridExtent; /** * @returns Targets sorted by extent dimension. */ private getSortedTargets; /** * Get the pixels colors of this layer at coordinate. * This will samples all pixel colors within a square region of specified size, centered at the given coordinate. * Returns undefined if no non-transparent (colored) pixels are found, or if no texture is available for this coordinate. * * Note: only 8-bit layers are supported. If the layer has non 8-bit pixels, returns `undefined`. * @returns The colors */ getPixel(params: { /** * The coordinate to sample. */ coordinates: Coordinates; /** * The size, in pixels, of the square to sample * @defaultValue 1 */ size?: number; }): Color[] | undefined; /** * Returns the first ancestor that is completely loaded, or null if not found. * @param target - The target. * @returns The smallest target that still contains this extent. */ private getLoadedAncestor; private getLoadedDirectChildren; private borrowTextureFromAncestor; private borrowTexturesFromChildren; private generateDefaultTextureFromExistingComposerImages; /** * Immediately applies a temporary texture to the target while * the actual texture is being asynchronously processed, to * avoid displaying a black texture. */ protected applyInterimTexture(target: Target): void; /** * @internal */ getInfo(node: LayerNode): { state: string; imageCount: number; paintCount: number; }; /** * Processes the target once, fetching all images relevant for this target, * then paints those images to the target's texture. * * @param target - The target to paint. */ private processTarget; private createRenderTargetIfNecessary; private paintTarget; private setTargetState; /** * Updates the provided node with content from this layer. * * @param context - the context * @param node - the node to update */ update(context: Context, node: LayerNode): void; /** * @param extent - The extent to test. * @returns `true` if this layer contains the specified extent, `false` otherwise. */ contains(extent: Extent): boolean; abstract getRenderTargetPixelFormat(): PixelFormat; abstract getRenderTargetDataType(): TextureDataType; /** * @param target - The render target to release. */ private releaseRenderTarget; /** * @param width - Width * @param height - Height * @returns The render target. */ private acquireRenderTarget; postUpdate(): void; /** * @internal */ get composer(): Readonly<LayerComposer | null>; protected updateMaterial(material: Material): void; /** * Returns true if this layer has loaded data for this node. */ isLoaded(nodeId: LayerNode['id']): boolean; protected abstract applyTextureToNode(texture: TextureAndPitch, target: Target, isLastRender: boolean): void; protected abstract applyEmptyTextureToNode(target: Target): void; /** * Disposes the layer. This releases all resources held by this layer. */ dispose(): void; } /** * Returns `true` if the given object is a {@link Layer}. */ export declare function isLayer(obj: unknown): obj is Layer; export default Layer; //# sourceMappingURL=Layer.d.ts.map