well-known-parser
Version:
A WKT/WKB/EWKT/EWKB/TWKB/GeoJSON parser and serializer
198 lines (158 loc) • 5.04 kB
text/typescript
import { Geometry } from './geometry';
import type { Coordinates, GeometryOptions } from './types';
import { GEOMETRY_TYPES } from './constants';
import { BinaryWriter } from './binarywriter';
import * as ZigZag from './zigzag';
import type { Point as GeoJSONPoint } from 'geojson';
export class Point extends Geometry {
x: number;
y: number;
z: number | undefined;
m: number | undefined;
constructor(x?: number, y?: number, z?: number, m?: number, srid?: number) {
super();
this.x = x;
this.y = y;
this.z = z;
this.m = m;
this.srid = srid;
this.hasZ = typeof this.z !== 'undefined';
this.hasM = typeof this.m !== 'undefined';
}
static Z(x: number, y: number, z: number, srid?: number): Point {
const point = new Point(x, y, z, undefined, srid);
point.hasZ = true;
return point;
}
static M(x: number, y: number, m: number, srid?: number): Point {
const point = new Point(x, y, undefined, m, srid);
point.hasM = true;
return point;
}
static ZM(x: number, y: number, z: number, m: number, srid?: number): Point {
const point = new Point(x, y, z, m, srid);
point.hasZ = true;
point.hasM = true;
return point;
}
toWkt(isNested: boolean = false): string {
if (isNested) return this.getWktCoordinate();
if (
typeof this.x === 'undefined' &&
typeof this.y === 'undefined' &&
typeof this.z === 'undefined' &&
typeof this.m === 'undefined'
) {
return this.getWktType(GEOMETRY_TYPES.Point.wkt, true);
}
return this.getWktType(GEOMETRY_TYPES.Point.wkt, false) + '(' + this.getWktCoordinate() + ')';
}
private getWktCoordinate(): string {
let coordinates = `${this.x} ${this.y}`;
if (this.hasZ) {
coordinates += ` ${this.z}`;
}
if (this.hasM) {
coordinates += ` ${this.m}`;
}
return coordinates;
}
toWkb(parentOptions?: GeometryOptions, isNested: boolean = false): Buffer {
const wkb = new BinaryWriter(this.getWkbSize(isNested));
if (!isNested) {
wkb.writeInt8(1);
this.writeWkbType(wkb, GEOMETRY_TYPES.Point.wkb, parentOptions);
}
if (typeof this.x === 'undefined' && typeof this.y === 'undefined') {
wkb.writeDoubleLE(NaN);
wkb.writeDoubleLE(NaN);
if (this.hasZ) {
wkb.writeDoubleLE(NaN);
}
if (this.hasM) {
wkb.writeDoubleLE(NaN);
}
} else {
wkb.writeDoubleLE(this.x);
wkb.writeDoubleLE(this.y);
if (this.hasZ && this.z !== undefined) {
wkb.writeDoubleLE(this.z);
}
if (this.hasM && this.m !== undefined) {
wkb.writeDoubleLE(this.m);
}
}
return wkb.buffer;
}
toTwkb(previousPoint?: Point, isNested: boolean = false): Buffer {
const twkb = new BinaryWriter(0, true);
const precision = Geometry.getTwkbPrecision(5, 0, 0);
const isEmpty = typeof this.x === 'undefined' && typeof this.y === 'undefined';
if (!isNested) {
this.writeTwkbHeader(twkb, GEOMETRY_TYPES.Point.wkb, precision, isEmpty);
}
if (isEmpty) {
return twkb.buffer;
}
const x = this.x * precision.xyFactor;
const y = this.y * precision.xyFactor;
// Use 0 as default value if z or m is undefined
const z = this.hasZ ? (this.z ?? 0) * precision.zFactor : 0;
const m = this.hasM ? (this.m ?? 0) * precision.mFactor : 0;
// Write delta from previous point
twkb.writeVarInt(ZigZag.encode(x - (previousPoint?.x ?? 0)));
twkb.writeVarInt(ZigZag.encode(y - (previousPoint?.y ?? 0)));
if (this.hasZ) {
// Use 0 as default if z is undefined in previous point
const prevZ = previousPoint?.z ?? 0;
twkb.writeVarInt(ZigZag.encode(z - prevZ));
}
if (this.hasM) {
// Use 0 as default if m is undefined in previous point
const prevM = previousPoint?.m ?? 0;
twkb.writeVarInt(ZigZag.encode(m - prevM));
}
if (previousPoint) {
// Update the previous point with the current values
previousPoint.x = x;
previousPoint.y = y;
if (this.hasZ) {
previousPoint.z = z;
}
if (this.hasM) {
previousPoint.m = m;
}
}
return twkb.buffer;
}
getWkbSize(isNested: boolean = false): number {
let size = 8 + 8;
if (!isNested) {
size += 1 + 4;
}
if (this.hasZ) {
size += 8;
}
if (this.hasM) {
size += 8;
}
return size;
}
toGeoJSON(): GeoJSONPoint;
toGeoJSON(isNested: true): Coordinates<GeoJSONPoint>;
toGeoJSON(isNested: boolean = false): GeoJSONPoint | Coordinates<GeoJSONPoint> {
let coordinates: number[];
if (typeof this.x === 'undefined' && typeof this.y === 'undefined') {
coordinates = [];
} else if (typeof this.z !== 'undefined') {
coordinates = [this.x, this.y, this.z];
} else {
coordinates = [this.x, this.y];
}
if (isNested) return coordinates;
return {
type: GEOMETRY_TYPES.Point.geoJSON,
coordinates,
};
}
}