123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- module.exports = Geometry;
- var Types = require('./types');
- var Point = require('./point');
- var LineString = require('./linestring');
- var Polygon = require('./polygon');
- var MultiPoint = require('./multipoint');
- var MultiLineString = require('./multilinestring');
- var MultiPolygon = require('./multipolygon');
- var GeometryCollection = require('./geometrycollection');
- var BinaryReader = require('./binaryreader');
- var BinaryWriter = require('./binarywriter');
- var WktParser = require('./wktparser');
- var ZigZag = require('./zigzag.js');
- function Geometry() {
- this.srid = undefined;
- this.hasZ = false;
- this.hasM = false;
- }
- Geometry.parse = function (value, options) {
- var valueType = typeof value;
- if (valueType === 'string' || value instanceof WktParser)
- return Geometry._parseWkt(value);
- else if (Buffer.isBuffer(value) || value instanceof BinaryReader)
- return Geometry._parseWkb(value, options);
- else
- throw new Error('first argument must be a string or Buffer');
- };
- Geometry._parseWkt = function (value) {
- var wktParser,
- srid;
- if (value instanceof WktParser)
- wktParser = value;
- else
- wktParser = new WktParser(value);
- var match = wktParser.matchRegex([/^SRID=(\d+);/]);
- if (match)
- srid = parseInt(match[1], 10);
- var geometryType = wktParser.matchType();
- var dimension = wktParser.matchDimension();
- var options = {
- srid: srid,
- hasZ: dimension.hasZ,
- hasM: dimension.hasM
- };
- switch (geometryType) {
- case Types.wkt.Point:
- return Point._parseWkt(wktParser, options);
- case Types.wkt.LineString:
- return LineString._parseWkt(wktParser, options);
- case Types.wkt.Polygon:
- return Polygon._parseWkt(wktParser, options);
- case Types.wkt.MultiPoint:
- return MultiPoint._parseWkt(wktParser, options);
- case Types.wkt.MultiLineString:
- return MultiLineString._parseWkt(wktParser, options);
- case Types.wkt.MultiPolygon:
- return MultiPolygon._parseWkt(wktParser, options);
- case Types.wkt.GeometryCollection:
- return GeometryCollection._parseWkt(wktParser, options);
- }
- };
- Geometry._parseWkb = function (value, parentOptions) {
- var binaryReader,
- wkbType,
- geometryType,
- options = {};
- if (value instanceof BinaryReader)
- binaryReader = value;
- else
- binaryReader = new BinaryReader(value);
- binaryReader.isBigEndian = !binaryReader.readInt8();
- wkbType = binaryReader.readUInt32();
- options.hasSrid = (wkbType & 0x20000000) === 0x20000000;
- options.isEwkb = (wkbType & 0x20000000) || (wkbType & 0x40000000) || (wkbType & 0x80000000);
- if (options.hasSrid)
- options.srid = binaryReader.readUInt32();
- options.hasZ = false;
- options.hasM = false;
- if (!options.isEwkb && (!parentOptions || !parentOptions.isEwkb)) {
- if (wkbType >= 1000 && wkbType < 2000) {
- options.hasZ = true;
- geometryType = wkbType - 1000;
- }
- else if (wkbType >= 2000 && wkbType < 3000) {
- options.hasM = true;
- geometryType = wkbType - 2000;
- }
- else if (wkbType >= 3000 && wkbType < 4000) {
- options.hasZ = true;
- options.hasM = true;
- geometryType = wkbType - 3000;
- }
- else {
- geometryType = wkbType;
- }
- }
- else {
- if (wkbType & 0x80000000)
- options.hasZ = true;
- if (wkbType & 0x40000000)
- options.hasM = true;
- geometryType = wkbType & 0xF;
- }
- switch (geometryType) {
- case Types.wkb.Point:
- return Point._parseWkb(binaryReader, options);
- case Types.wkb.LineString:
- return LineString._parseWkb(binaryReader, options);
- case Types.wkb.Polygon:
- return Polygon._parseWkb(binaryReader, options);
- case Types.wkb.MultiPoint:
- return MultiPoint._parseWkb(binaryReader, options);
- case Types.wkb.MultiLineString:
- return MultiLineString._parseWkb(binaryReader, options);
- case Types.wkb.MultiPolygon:
- return MultiPolygon._parseWkb(binaryReader, options);
- case Types.wkb.GeometryCollection:
- return GeometryCollection._parseWkb(binaryReader, options);
- default:
- throw new Error('GeometryType ' + geometryType + ' not supported');
- }
- };
- Geometry.parseTwkb = function (value) {
- var binaryReader,
- options = {};
- if (value instanceof BinaryReader)
- binaryReader = value;
- else
- binaryReader = new BinaryReader(value);
- var type = binaryReader.readUInt8();
- var metadataHeader = binaryReader.readUInt8();
- var geometryType = type & 0x0F;
- options.precision = ZigZag.decode(type >> 4);
- options.precisionFactor = Math.pow(10, options.precision);
- options.hasBoundingBox = metadataHeader >> 0 & 1;
- options.hasSizeAttribute = metadataHeader >> 1 & 1;
- options.hasIdList = metadataHeader >> 2 & 1;
- options.hasExtendedPrecision = metadataHeader >> 3 & 1;
- options.isEmpty = metadataHeader >> 4 & 1;
- if (options.hasExtendedPrecision) {
- var extendedPrecision = binaryReader.readUInt8();
- options.hasZ = (extendedPrecision & 0x01) === 0x01;
- options.hasM = (extendedPrecision & 0x02) === 0x02;
- options.zPrecision = ZigZag.decode((extendedPrecision & 0x1C) >> 2);
- options.zPrecisionFactor = Math.pow(10, options.zPrecision);
- options.mPrecision = ZigZag.decode((extendedPrecision & 0xE0) >> 5);
- options.mPrecisionFactor = Math.pow(10, options.mPrecision);
- }
- else {
- options.hasZ = false;
- options.hasM = false;
- }
- if (options.hasSizeAttribute)
- binaryReader.readVarInt();
- if (options.hasBoundingBox) {
- var dimensions = 2;
- if (options.hasZ)
- dimensions++;
- if (options.hasM)
- dimensions++;
- for (var i = 0; i < dimensions; i++) {
- binaryReader.readVarInt();
- binaryReader.readVarInt();
- }
- }
- switch (geometryType) {
- case Types.wkb.Point:
- return Point._parseTwkb(binaryReader, options);
- case Types.wkb.LineString:
- return LineString._parseTwkb(binaryReader, options);
- case Types.wkb.Polygon:
- return Polygon._parseTwkb(binaryReader, options);
- case Types.wkb.MultiPoint:
- return MultiPoint._parseTwkb(binaryReader, options);
- case Types.wkb.MultiLineString:
- return MultiLineString._parseTwkb(binaryReader, options);
- case Types.wkb.MultiPolygon:
- return MultiPolygon._parseTwkb(binaryReader, options);
- case Types.wkb.GeometryCollection:
- return GeometryCollection._parseTwkb(binaryReader, options);
- default:
- throw new Error('GeometryType ' + geometryType + ' not supported');
- }
- };
- Geometry.parseGeoJSON = function (value) {
- return Geometry._parseGeoJSON(value);
- };
- Geometry._parseGeoJSON = function (value, isSubGeometry) {
- var geometry;
- switch (value.type) {
- case Types.geoJSON.Point:
- geometry = Point._parseGeoJSON(value); break;
- case Types.geoJSON.LineString:
- geometry = LineString._parseGeoJSON(value); break;
- case Types.geoJSON.Polygon:
- geometry = Polygon._parseGeoJSON(value); break;
- case Types.geoJSON.MultiPoint:
- geometry = MultiPoint._parseGeoJSON(value); break;
- case Types.geoJSON.MultiLineString:
- geometry = MultiLineString._parseGeoJSON(value); break;
- case Types.geoJSON.MultiPolygon:
- geometry = MultiPolygon._parseGeoJSON(value); break;
- case Types.geoJSON.GeometryCollection:
- geometry = GeometryCollection._parseGeoJSON(value); break;
- default:
- throw new Error('GeometryType ' + value.type + ' not supported');
- }
- if (value.crs && value.crs.type && value.crs.type === 'name' && value.crs.properties && value.crs.properties.name) {
- var crs = value.crs.properties.name;
- if (crs.indexOf('EPSG:') === 0)
- geometry.srid = parseInt(crs.substring(5));
- else if (crs.indexOf('urn:ogc:def:crs:EPSG::') === 0)
- geometry.srid = parseInt(crs.substring(22));
- else
- throw new Error('Unsupported crs: ' + crs);
- }
- else if (!isSubGeometry) {
- geometry.srid = 4326;
- }
- return geometry;
- };
- Geometry.prototype.toEwkt = function () {
- return 'SRID=' + this.srid + ';' + this.toWkt();
- };
- Geometry.prototype.toEwkb = function () {
- var ewkb = new BinaryWriter(this._getWkbSize() + 4);
- var wkb = this.toWkb();
- ewkb.writeInt8(1);
- ewkb.writeUInt32LE((wkb.slice(1, 5).readUInt32LE(0) | 0x20000000) >>> 0, true);
- ewkb.writeUInt32LE(this.srid);
- ewkb.writeBuffer(wkb.slice(5));
- return ewkb.buffer;
- };
- Geometry.prototype._getWktType = function (wktType, isEmpty) {
- var wkt = wktType;
- if (this.hasZ && this.hasM)
- wkt += ' ZM ';
- else if (this.hasZ)
- wkt += ' Z ';
- else if (this.hasM)
- wkt += ' M ';
- if (isEmpty && !this.hasZ && !this.hasM)
- wkt += ' ';
- if (isEmpty)
- wkt += 'EMPTY';
- return wkt;
- };
- Geometry.prototype._getWktCoordinate = function (point) {
- var coordinates = point.x + ' ' + point.y;
- if (this.hasZ)
- coordinates += ' ' + point.z;
- if (this.hasM)
- coordinates += ' ' + point.m;
- return coordinates;
- };
- Geometry.prototype._writeWkbType = function (wkb, geometryType, parentOptions) {
- var dimensionType = 0;
- if (typeof this.srid === 'undefined' && (!parentOptions || typeof parentOptions.srid === 'undefined')) {
- if (this.hasZ && this.hasM)
- dimensionType += 3000;
- else if (this.hasZ)
- dimensionType += 1000;
- else if (this.hasM)
- dimensionType += 2000;
- }
- else {
- if (this.hasZ)
- dimensionType |= 0x80000000;
- if (this.hasM)
- dimensionType |= 0x40000000;
- }
- wkb.writeUInt32LE((dimensionType + geometryType) >>> 0, true);
- };
- Geometry.getTwkbPrecision = function (xyPrecision, zPrecision, mPrecision) {
- return {
- xy: xyPrecision,
- z: zPrecision,
- m: mPrecision,
- xyFactor: Math.pow(10, xyPrecision),
- zFactor: Math.pow(10, zPrecision),
- mFactor: Math.pow(10, mPrecision)
- };
- };
- Geometry.prototype._writeTwkbHeader = function (twkb, geometryType, precision, isEmpty) {
- var type = (ZigZag.encode(precision.xy) << 4) + geometryType;
- var metadataHeader = (this.hasZ || this.hasM) << 3;
- metadataHeader += isEmpty << 4;
- twkb.writeUInt8(type);
- twkb.writeUInt8(metadataHeader);
- if (this.hasZ || this.hasM) {
- var extendedPrecision = 0;
- if (this.hasZ)
- extendedPrecision |= 0x1;
- if (this.hasM)
- extendedPrecision |= 0x2;
- twkb.writeUInt8(extendedPrecision);
- }
- };
- Geometry.prototype.toGeoJSON = function (options) {
- var geoJSON = {};
- if (this.srid) {
- if (options) {
- if (options.shortCrs) {
- geoJSON.crs = {
- type: 'name',
- properties: {
- name: 'EPSG:' + this.srid
- }
- };
- }
- else if (options.longCrs) {
- geoJSON.crs = {
- type: 'name',
- properties: {
- name: 'urn:ogc:def:crs:EPSG::' + this.srid
- }
- };
- }
- }
- }
- return geoJSON;
- };
|