@itwin/core-frontend
Version:
iTwin.js frontend components
135 lines • 8.04 kB
TypeScript
/** @packageDocumentation
* @module IModelConnection
*/
import { BeEvent, Dictionary, SortedArray } from "@itwin/core-bentley";
import { WritableXYAndZ, XYAndZ, XYZProps } from "@itwin/core-geometry";
import { GeoCoordinatesRequestProps, GeoCoordinatesResponseProps, GeographicCRSProps, IModelCoordinatesRequestProps, IModelCoordinatesResponseProps, PointWithStatus } from "@itwin/core-common";
import { IModelConnection } from "./IModelConnection";
/** Options used to create a [[CoordinateConverter]].
* @internal exported strictly for tests.
*/
export interface CoordinateConverterOptions {
isIModelClosed: () => boolean;
/** Asynchronously convert each point. The resultant array should have the same number and order of points as the input. */
requestPoints: (points: XYAndZ[]) => Promise<PointWithStatus[]>;
/** Maximum number of points to include in each request. Default: 300. */
maxPointsPerRequest?: number;
}
type CoordinateConverterState = "idle" | "scheduled" | "in-flight";
/** Performs conversion of coordinates from one coordinate system to another.
* A [[GeoConverter]] has a pair of these for converting between iModel coordinates and geographic coordinates.
* Uses a cache to avoid repeatedly requesting the same points, and a batching strategy to avoid making frequent small requests.
* The cache stores every point that was ever converted by [[convert]]. It is currently permitted to grow to unbounded size.
* The batching works as follows:
* When a conversion is requested via [[convert]], if all the requested points are in the cache, they are returned immediately.
* Otherwise, any points not in the cache and not in the current in-flight request (if any) are placed onto the queue of pending requests.
* A pending request is scheduled if one hasn't already been scheduled, via requestAnimationFrame.
* In the animation frame callback, the pending requests are split into batches of no more than options.maxPointsPerRequest and dispatched to the backend.
* Once the response is received, the results are loaded into and returned from the cache.
* If more calls to convert occurred while the request was in flight, another request is dispatched.
* @internal exported strictly for tests.
*/
export declare class CoordinateConverter {
protected readonly _cache: Dictionary<XYAndZ, PointWithStatus>;
protected _state: CoordinateConverterState;
protected _pending: SortedArray<XYAndZ>;
protected _inflight: SortedArray<XYAndZ>;
protected _onCompleted: BeEvent<() => void>;
protected readonly _scratchXYZ: {
x: number;
y: number;
z: number;
};
protected readonly _maxPointsPerRequest: number;
protected readonly _isIModelClosed: () => boolean;
protected readonly _requestPoints: (points: XYAndZ[]) => Promise<PointWithStatus[]>;
protected _redispatchOnCompletion: boolean;
get isIdle(): boolean;
protected toXYAndZ(input: XYZProps, output: WritableXYAndZ): XYAndZ;
constructor(opts: CoordinateConverterOptions);
protected dispatch(): Promise<void>;
protected enqueue(points: XYZProps[]): number;
protected getFromCache(inputs: XYZProps[]): PointWithStatus[];
protected scheduleDispatch(): Promise<void>;
convert(inputs: XYZProps[]): Promise<{
points: PointWithStatus[];
fromCache: number;
}>;
findCached(inputs: XYZProps[]): CachedIModelCoordinatesResponseProps;
}
/** Response to a request to obtain imodel coordinates from cache.
* @internal
*/
export interface CachedIModelCoordinatesResponseProps {
/** An array of the same length as the input array, with undefined entries at indices corresponding to points not found in cache. */
result: Array<PointWithStatus | undefined>;
/** An array of points in the input array which were not found in the cache, or undefined if all points were found in the cache. */
missing?: XYZProps[];
}
/** Options used to create a [[GeoConverter]].
* @internal exported strictly for tests.
*/
export interface GeoConverterOptions {
readonly datum: string;
isIModelClosed: () => boolean;
toIModelCoords: (request: IModelCoordinatesRequestProps) => Promise<PointWithStatus[]>;
fromIModelCoords: (request: GeoCoordinatesRequestProps) => Promise<PointWithStatus[]>;
}
/** An object capable of communicating with the backend to convert between coordinates in a geographic coordinate system and coordinates in an [[IModelConnection]]'s own coordinate system.
* @see [[GeoServices.getConverter]] to obtain a converter.
* @see [GeographicCRS]($common) for more information about geographic coordinate reference systems.
* @public
*/
export declare class GeoConverter {
private readonly _geoToIModel;
private readonly _iModelToGeo;
/** Used for removing this converter from GeoServices' cache after all requests are completed.
* @internal
*/
readonly onAllRequestsCompleted: BeEvent<() => void>;
/** @internal */
constructor(opts: GeoConverterOptions);
/** Convert the specified geographic coordinates into iModel coordinates. */
convertToIModelCoords(geoPoints: XYZProps[]): Promise<PointWithStatus[]>;
/** Convert the specified iModel coordinates into geographic coordinates. */
convertFromIModelCoords(iModelCoords: XYZProps[]): Promise<PointWithStatus[]>;
/** @internal */
getIModelCoordinatesFromGeoCoordinates(geoPoints: XYZProps[]): Promise<IModelCoordinatesResponseProps>;
/** @internal */
getGeoCoordinatesFromIModelCoordinates(iModelPoints: XYZProps[]): Promise<GeoCoordinatesResponseProps>;
private checkCompletion;
/** @internal */
getCachedIModelCoordinatesFromGeoCoordinates(geoPoints: XYZProps[]): CachedIModelCoordinatesResponseProps;
}
/** @internal */
export type GeoServicesOptions = Omit<GeoConverterOptions, "datum">;
/** The Geographic Services available for an [[IModelConnection]].
* @see [[IModelConnection.geoServices]] to obtain the GeoServices for a specific iModel.
* @public
*/
export declare class GeoServices {
private readonly _options;
/** Each GeoConverter has its own independent request queue and cache of previously-converted points.
* Some callers like RealityTileTree obtain a single GeoConverter and reuse it throughout their own lifetime. Therefore they benefit from both batching and caching, and
* the cache gets deleted once the RealityTileTree becomes disused.
*
* Other callers like IModelConnection.spatialToCartographic obtain a new GeoConverter every time they need one, use it to convert a single point(!), and then discard the converter.
* This entirely prevents batching - e.g., calling spatialToCartographic 20 times in one frame results in 20 http requests.
* To address that, we cache each GeoConverter returned by getConverter until it has converted at least one point and has no further outstanding conversion requests.
* In this way, the converter lives for as long as (and no longer than) any caller is awaiting conversion to/from its datum - it and its cache are deleted once it becomes disused.
* This makes the coordinate caching generally less useful, but at least bounded - and maximizes batching of requests.
*/
private readonly _cache;
/** @internal */
constructor(options: GeoServicesOptions);
/** @internal */
static createForIModel(iModel: IModelConnection): GeoServices;
/** Obtain a converter that can convert between a geographic coordinate system and the iModel's own coordinate system.
* @param datumOrGCRS The name or JSON representation of the geographic coordinate system datum - for example, "WGS84".
* @returns a converter, or `undefined` if the iModel is not open.
* @note A [[BlankConnection]] has no connection to a backend, so it is never "open"; therefore it always returns `undefined`.
*/
getConverter(datumOrGCRS?: string | GeographicCRSProps): GeoConverter | undefined;
}
export {};
//# sourceMappingURL=GeoServices.d.ts.map