well-known-parser
Version:
A WKT/WKB/EWKT/EWKB/TWKB/GeoJSON parser and serializer
134 lines (104 loc) • 3.71 kB
text/typescript
import type { BinaryReader } from '../binaryreader';
import type { WktParser } from '../wktparser';
import type { GeometryOptions } from '../types';
import { Polygon } from '../polygon';
import { Point } from '../point';
import { parsePointGeoJSON, parsePointWkb, parseRelativePointTwkb } from './point';
import type { Polygon as GeoJSONPolygon } from 'geojson';
export function parsePolygonWkt(value: WktParser, options: GeometryOptions): Polygon {
const polygon = new Polygon();
polygon.srid = options.srid;
polygon.hasZ = options.hasZ ?? false;
polygon.hasM = options.hasM ?? false;
if (value.isMatch(['EMPTY'])) {
return polygon;
}
value.expectGroupStart();
value.expectGroupStart();
const exteriorCoords = value.matchCoordinates(options);
for (const coord of exteriorCoords) {
polygon.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);
}
polygon.interiorRings.push(ring);
value.expectGroupEnd();
}
value.expectGroupEnd();
return polygon;
}
export function parsePolygonWkb(value: BinaryReader, options: GeometryOptions): Polygon {
const polygon = new Polygon();
polygon.srid = options.srid;
polygon.hasZ = options.hasZ ?? false;
polygon.hasM = options.hasM ?? false;
const ringCount = value.readUInt32();
const childOptions: GeometryOptions = {
...options,
srid: undefined,
};
if (ringCount > 0) {
const exteriorRingCount = value.readUInt32();
for (let i = 0; i < exteriorRingCount; i++) {
polygon.exteriorRing.push(parsePointWkb(value, childOptions));
}
for (let i = 1; i < ringCount; i++) {
const interiorRing: Point[] = [];
const interiorRingCount = value.readUInt32();
for (let j = 0; j < interiorRingCount; j++) {
interiorRing.push(parsePointWkb(value, childOptions));
}
polygon.interiorRings.push(interiorRing);
}
}
return polygon;
}
export function parsePolygonTwkb(value: BinaryReader, options: GeometryOptions): Polygon {
const polygon = new Polygon();
polygon.hasZ = options.hasZ ?? false;
polygon.hasM = options.hasM ?? false;
if (options.isEmpty) {
return polygon;
}
const previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined);
const ringCount = value.readVarInt();
const exteriorRingCount = value.readVarInt();
for (let i = 0; i < exteriorRingCount; i++) {
polygon.exteriorRing.push(parseRelativePointTwkb(value, options, previousPoint));
}
for (let i = 1; i < ringCount; i++) {
const interiorRing: Point[] = [];
const interiorRingCount = value.readVarInt();
for (let j = 0; j < interiorRingCount; j++) {
interiorRing.push(parseRelativePointTwkb(value, options, previousPoint));
}
polygon.interiorRings.push(interiorRing);
}
return polygon;
}
export function parsePolygonGeoJSON(value: Pick<GeoJSONPolygon, 'coordinates'>): Polygon {
const polygon = new Polygon();
if (value.coordinates.length > 0 && value.coordinates[0].length > 0) {
polygon.hasZ = value.coordinates[0][0].length > 2;
}
for (let i = 0; i < value.coordinates.length; i++) {
if (i > 0) {
polygon.interiorRings.push([]);
}
for (let j = 0; j < value.coordinates[i].length; j++) {
const pointData = parsePointGeoJSON(value.coordinates[i][j]);
if (i === 0) {
polygon.exteriorRing.push(pointData);
} else {
polygon.interiorRings[i - 1].push(pointData);
}
}
}
return polygon;
}