UNPKG

@loaders.gl/geoarrow

Version:

GeoArrow columnar geometry encoding and decoding

173 lines (152 loc) 4.67 kB
// loaders.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import * as arrow from 'apache-arrow'; import type {GeoArrowEncoding} from './metadata/geoarrow-metadata'; /** * @see https://geoarrow.org/format.html#memory-layouts */ export type GeoArrowGeometryInfo = { /** Geometry encodings that are compatible with this column (Field) */ compatibleEncodings: GeoArrowEncoding[]; /** How many levels of List<> nesting */ nesting: 0 | 1 | 2 | 3; /** How many values per coordinate */ dimension: number; /** * - 0: A point is just a Coordinate * - 1: A line string or a multipoint is a List<Coordinate> * - 2: A polygon or a multilinestring are List<List<Coordinate>> * - 3: multipolygons are List<List<List<Coordinate>>> */ /** Coordinate memory layout {x,y,...} vs [x,y,...] */ coordinates: 'separated' | 'interleaved'; /** Coordinate */ valueType: 'double'; // 'float' }; /** Helper type used to test coordinates */ type CoordinateFieldInfo = { coordinates: 'interleaved' | 'separated'; dimension: 2 | 3 | 4; valueType: 'double'; }; /** * Examines a column containing GeoArrow formatted data and returns information about the geometry type * that can be useful during traversal * @see https://geoarrow.org/format.html#memory-layouts */ // eslint-disable-next-line max-statements export function getGeoArrowGeometryInfo(arrowField: arrow.Field): GeoArrowGeometryInfo | null { if (arrowField.type instanceof arrow.Utf8) { return { compatibleEncodings: ['geoarrow.wkt'], nesting: 0, /** @note: Dimension encoded in WKT */ dimension: 2, coordinates: 'interleaved', valueType: 'double' }; } if (arrowField.type instanceof arrow.Binary || arrowField.type instanceof arrow.LargeBinary) { return { compatibleEncodings: ['geoarrow.wkb'], nesting: 0, /** @note: Dimension encoded in WKB */ dimension: 2, coordinates: 'interleaved', valueType: 'double' }; } let coordinateInfo = getCoordinateFieldInfo(arrowField); // A point is just a Coordinate if (coordinateInfo) { return { compatibleEncodings: ['geoarrow.point'], nesting: 0, ...coordinateInfo }; } // A line string or a multipoint is a List<Coordinate> if (!(arrowField.type instanceof arrow.List)) { return null; } arrowField = arrowField.type.children[0]; coordinateInfo = getCoordinateFieldInfo(arrowField); if (coordinateInfo) { return { compatibleEncodings: ['geoarrow.linestring', 'geoarrow.multipoint'], nesting: 1, ...coordinateInfo }; } // A polygon or a multiline string are List<List<Coordinate>> if (!(arrowField.type instanceof arrow.List)) { return null; } arrowField = arrowField.type.children[0]; coordinateInfo = getCoordinateFieldInfo(arrowField); if (coordinateInfo) { return { compatibleEncodings: ['geoarrow.polygon', 'geoarrow.multilinestring'], nesting: 2, ...coordinateInfo }; } // A multipolygons are List<List<List<Coordinate>>> if (!(arrowField.type instanceof arrow.List)) { return null; } arrowField = arrowField.type.children[0]; coordinateInfo = getCoordinateFieldInfo(arrowField); if (coordinateInfo) { return { compatibleEncodings: ['geoarrow.multipolygon'], nesting: 3, ...coordinateInfo }; } return null; } /** * @see https://geoarrow.org/format.html#memory-layouts */ function getCoordinateFieldInfo(arrowField: arrow.Field): CoordinateFieldInfo | null { // interleaved case if (arrowField.type instanceof arrow.FixedSizeList) { const dimension = arrowField.type.listSize; if (dimension < 2 || dimension > 4) { return null; } const child = arrowField.type.children[0]; // Spec currently only supports 64 bit coordinates if (!(child.type instanceof arrow.Float)) { return null; } return { coordinates: 'interleaved', dimension: dimension as 2 | 3 | 4, valueType: 'double' }; } // separated case if (arrowField.type instanceof arrow.Struct) { const children = arrowField.type.children; const dimension = children.length; if (dimension < 2 || dimension > 4) { return null; } // Spec currently only supports 64 bit coordinates for (const child of children) { if (!(child.type instanceof arrow.Float)) { return null; } } return { coordinates: 'separated', dimension: dimension as 2 | 3 | 4, valueType: 'double' }; } // No other types are valid coordinates return null; }