@giro3d/giro3d
Version:
A JS/WebGL framework for 3D geospatial data visualization
105 lines (91 loc) • 3.88 kB
text/typescript
/*
* Copyright (c) 2015-2018, IGN France.
* Copyright (c) 2018-2026, Giro3D team.
* SPDX-License-Identifier: MIT
*/
import type ElevationSample from './ElevationSample';
import type GetElevationOptions from './GetElevationOptions';
import type GetElevationResult from './GetElevationResult';
/**
* Represents an object that can provide elevations at given coordinates.
*
* Note: to combine multiple providers into one, you can use the {@link aggregateElevationProviders} function.
*/
export interface ElevationProvider {
/**
* Returns the elevation at the specified coordinates, without any coordinate conversion.
* @param x - The X coordinate of the location to sample, in the same coordinate system as this elevation provider.
* @param y - The Y coordinate of the location to sample, in the same coordinate system as this elevation provider.
*/
getElevationFast(x: number, y: number): ElevationSample | undefined;
/**
* Sample the elevation at the specified coordinate.
*
* Note: sampling might return more than one sample for any given coordinate. You can sort them
* by {@link core.ElevationSample.resolution | resolution} to select the best sample for your needs.
* @param options - The options.
* @param result - The result object to populate with the samples. If none is provided, a new
* empty result is created. The existing samples in the array are not removed. Useful to
* cumulate samples across different providers.
* @returns The {@link GetElevationResult} containing the updated sample array.
*/
getElevation(options: GetElevationOptions, result?: GetElevationResult): GetElevationResult;
}
/** @internal */
class AggregateProvider implements ElevationProvider {
private readonly _providers: Readonly<ElevationProvider[]>;
public constructor(providers: Readonly<ElevationProvider[]>) {
this._providers = providers;
}
public getElevationFast(x: number, y: number): ElevationSample | undefined {
const samples: ElevationSample[] = [];
// Accumulate elevation samples from all providers.
for (let i = 0; i < this._providers.length; i++) {
const provider = this._providers[i];
const sample = provider.getElevationFast(x, y);
if (sample) {
samples.push(sample);
}
}
if (samples.length > 0) {
samples.sort((a, b) => a.resolution - b.resolution);
return samples[0];
}
return undefined;
}
public getElevation(
options: GetElevationOptions,
result?: GetElevationResult,
): GetElevationResult {
result = result ?? {
coordinates: options.coordinates,
samples: [],
};
// Accumulate elevation samples from all providers.
for (let i = 0; i < this._providers.length; i++) {
const provider = this._providers[i];
provider.getElevation(options, result);
}
return result;
}
}
/**
* Returns an {@link ElevationProvider} that aggregates multiple providers into one.
* The {@link ElevationProvider.getElevation | getElevation} method will then sample
* all underlying providers and return a single {@link GetElevationResult} containing
* samples from all providers.
*
* This can be useful if a scene contains multiple overlapping terrains for example.
*
* @param providers - The providers to aggregate.
*/
export function aggregateElevationProviders(...providers: ElevationProvider[]): ElevationProvider {
if (providers == null || providers.length === 0) {
throw new Error('expected at least one provider');
}
if (providers.length === 1) {
return providers[0];
}
return new AggregateProvider(providers);
}
export default ElevationProvider;