@giro3d/giro3d
Version:
A JS/WebGL framework for 3D geospatial data visualization
103 lines (77 loc) • 2.93 kB
text/typescript
/*
* Copyright (c) 2015-2018, IGN France.
* Copyright (c) 2018-2026, Giro3D team.
* SPDX-License-Identifier: MIT
*/
import type { Feature } from 'ol';
import type { Extent as OLExtent } from 'ol/extent';
import type { Geometry } from 'ol/geom';
import type CoordinateSystem from '../../core/geographic/CoordinateSystem';
import type Extent from '../../core/geographic/Extent';
import OpenLayersUtils from '../../utils/OpenLayersUtils';
import PromiseUtils from '../../utils/PromiseUtils';
export async function processFeatures(
features: Feature<Geometry>[],
sourceProjection: CoordinateSystem,
targetProjection: CoordinateSystem,
optionalProcessings?: {
getFeatureId?: (feature: Feature) => number | string;
transformer?: (feature: Feature, geometry: Geometry) => void;
},
): Promise<Feature<Geometry>[]> {
// Since everything happens in the main frame, we split the computation
// into several slices that are executed over time.
await PromiseUtils.nextFrame();
const shouldReproject = sourceProjection.id !== targetProjection.id;
const tmpExtent = [0, 0, 0, 0];
const transformer = (feature: Feature, index: number): Feature | null => {
const id =
optionalProcessings?.getFeatureId != null
? optionalProcessings.getFeatureId(feature)
: index;
feature.setId(id);
const geometry = feature.getGeometry();
// We ignore features without geometry as they cannot be represented.
if (geometry) {
if (shouldReproject) {
// Reproject geometry
geometry.transform(sourceProjection.id, targetProjection.id);
}
// Pre-compute extent to speedup ulterior computations
geometry.getExtent(tmpExtent);
if (optionalProcessings?.transformer) {
optionalProcessings.transformer(feature, geometry);
}
return feature;
}
return null;
};
// Process the features in batched slices
const actualFeatures = await PromiseUtils.batch(features, transformer);
return actualFeatures;
}
export function intersects(feature: Feature, olExtent: OLExtent): boolean {
const geom = feature.getGeometry();
if (!geom) {
return false;
}
if (geom.intersectsExtent(olExtent)) {
return true;
}
return false;
}
export async function filterByExtent(
features: Feature[],
extent: Extent,
options?: { signal?: AbortSignal },
): Promise<Feature[]> {
const olExtent = OpenLayersUtils.toOLExtent(extent);
const filter = (feature: Feature): Feature | null => {
if (intersects(feature, olExtent)) {
return feature;
}
return null;
};
const filtered = await PromiseUtils.batch(features, filter, { signal: options?.signal });
return filtered;
}