well-known-parser
Version:
A WKT/WKB/EWKT/EWKB/TWKB/GeoJSON parser and serializer
135 lines (103 loc) • 3.97 kB
text/typescript
import type { BinaryReader } from '../binaryreader';
import type { WktParser } from '../wktparser';
import type { GeometryOptions } from '../types';
import { MultiPolygon } from '../multipolygon';
import { Polygon } from '../polygon';
import { Point } from '../point';
import { parsePolygonGeoJSON } from './polygon';
import { parseRelativePointTwkb } from './point';
import { parseWkb } from './index';
import type { MultiPolygon as GeoJSONMultiPoint } from 'geojson';
export function parseMultiPolygonWkt(value: WktParser, options: GeometryOptions): MultiPolygon {
const multiPolygon = new MultiPolygon();
multiPolygon.srid = options.srid;
multiPolygon.hasZ = options.hasZ ?? false;
multiPolygon.hasM = options.hasM ?? false;
if (value.isMatch(['EMPTY'])) {
return multiPolygon;
}
value.expectGroupStart();
do {
value.expectGroupStart();
const exteriorRing: Point[] = [];
const interiorRings: Point[][] = [];
value.expectGroupStart();
const exteriorCoords = value.matchCoordinates(options);
for (const coord of exteriorCoords) {
exteriorRing.push(coord);
}
value.expectGroupEnd();
while (value.isMatch([','])) {
value.expectGroupStart();
const interiorCoords = value.matchCoordinates(options);
const ring = [];
for (const coord of interiorCoords) {
ring.push(coord);
}
interiorRings.push(ring);
value.expectGroupEnd();
}
multiPolygon.polygons.push(new Polygon(exteriorRing, interiorRings));
value.expectGroupEnd();
} while (value.isMatch([',']));
value.expectGroupEnd();
return multiPolygon;
}
export function parseMultiPolygonWkb(value: BinaryReader, options: GeometryOptions): MultiPolygon {
const multiPolygon = new MultiPolygon();
multiPolygon.srid = options.srid;
multiPolygon.hasZ = options.hasZ ?? false;
multiPolygon.hasM = options.hasM ?? false;
const polygonCount = value.readUInt32();
for (let i = 0; i < polygonCount; i++) {
// This can only return a Polygon, but we need to call parseWkb in order to make sure wkb headers are read
multiPolygon.polygons.push(parseWkb(value, options) as Polygon);
}
return multiPolygon;
}
export function parseMultiPolygonTwkb(value: BinaryReader, options: GeometryOptions): MultiPolygon {
const multiPolygon = new MultiPolygon();
multiPolygon.hasZ = options.hasZ ?? false;
multiPolygon.hasM = options.hasM ?? false;
if (options.isEmpty) {
return multiPolygon;
}
const previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined);
const polygonCount = value.readVarInt();
for (let i = 0; i < polygonCount; i++) {
const polygon = new Polygon();
polygon.hasZ = options.hasZ ?? false;
polygon.hasM = options.hasM ?? false;
const ringCount = value.readVarInt();
const exteriorRingCount = value.readVarInt();
for (let j = 0; j < exteriorRingCount; j++) {
polygon.exteriorRing.push(parseRelativePointTwkb(value, options, previousPoint));
}
for (let j = 1; j < ringCount; j++) {
const interiorRing: Point[] = [];
const interiorRingCount = value.readVarInt();
for (let k = 0; k < interiorRingCount; k++) {
interiorRing.push(parseRelativePointTwkb(value, options, previousPoint));
}
polygon.interiorRings.push(interiorRing);
}
multiPolygon.polygons.push(polygon);
}
return multiPolygon;
}
export function parseMultiPolygonGeoJSON(
value: Pick<GeoJSONMultiPoint, 'coordinates'>
): MultiPolygon {
const multiPolygon = new MultiPolygon();
if (
value.coordinates.length > 0 &&
value.coordinates[0].length > 0 &&
value.coordinates[0][0].length > 0
) {
multiPolygon.hasZ = value.coordinates[0][0][0].length > 2;
}
for (let i = 0; i < value.coordinates.length; i++) {
multiPolygon.polygons.push(parsePolygonGeoJSON({ coordinates: value.coordinates[i] }));
}
return multiPolygon;
}