UNPKG

@giro3d/giro3d

Version:

A JS/WebGL framework for 3D geospatial data visualization

124 lines (111 loc) 3.56 kB
/* * Copyright (c) 2015-2018, IGN France. * Copyright (c) 2018-2026, Giro3D team. * SPDX-License-Identifier: MIT */ import type { View } from 'copc'; import type { DimensionName } from './dimension'; // A dimension filter wrapped into an index accessor. /** @internal */ export type FilterByIndex = (index: number) => boolean; export type FilterOperator = | 'equal' | 'less' | 'lessequal' | 'greater' | 'greaterequal' | 'not' | 'in' | 'not_in'; /** * A filter that can be applied to dimensions to filter out unwanted points during processing. */ export type DimensionFilter = | { /** * The dimension this filter applies to. * If this dimension is not present in the source, the filter is ignored. */ dimension: DimensionName; /** * The operator of the predicate to apply to a specific dimension value. */ operator: Exclude<FilterOperator, 'in' | 'not_in'>; /** * The value to apply the predicate to. */ value: number; } | { /** * The dimension this filter applies to. * If this dimension is not present in the source, the filter is ignored. */ dimension: DimensionName; /** * The operator of the predicate to apply to a specific dimension value. */ operator: Extract<FilterOperator, 'in' | 'not_in'>; /** * The values to apply the predicate to. */ values: Set<number>; }; /** * For a given point index, evaluate all filters in series. Returns `true` if all filters return * `true`, otherwise returns `false`. * @internal */ export function evaluateFilters(filters: FilterByIndex[] | null, pointIndex: number): boolean { if (filters == null || filters.length === 0) { return true; } return filters.every(f => f(pointIndex)); } /** @internal */ export function createPredicateFromFilter(filter: DimensionFilter): (value: number) => boolean { const operator = filter.operator; switch (operator) { case 'equal': return x => x === filter.value; case 'less': return x => x < filter.value; case 'lessequal': return x => x <= filter.value; case 'greater': return x => x > filter.value; case 'greaterequal': return x => x >= filter.value; case 'not': return x => x !== filter.value; case 'in': return x => filter.values.has(x); case 'not_in': return x => !filter.values.has(x); default: throw new Error(`invalid filter operator: '${operator}'`); } } /** * For a given set of dimension filters, return an array of ready-to-use functions to apply to each * point being read. * @internal */ export function getPerPointFilters(filters: DimensionFilter[], view: View): FilterByIndex[] | null { if (filters.length === 0) { return null; } const result: FilterByIndex[] = []; for (const filter of filters) { const predicate = createPredicateFromFilter(filter); if (view.dimensions[filter.dimension] != null) { const getter = view.getter(filter.dimension); const filterFn = (i: number): boolean => predicate(getter(i)); result.push(filterFn); } } if (result.length > 0) { return result; } return null; }