module.exports = Polygon; var util = require('util'); var Geometry = require('./geometry'); var Types = require('./types'); var Point = require('./point'); var BinaryWriter = require('./binarywriter'); function Polygon(exteriorRing, interiorRings, srid) { Geometry.call(this); this.exteriorRing = exteriorRing || []; this.interiorRings = interiorRings || []; this.srid = srid; if (this.exteriorRing.length > 0) { this.hasZ = this.exteriorRing[0].hasZ; this.hasM = this.exteriorRing[0].hasM; } } util.inherits(Polygon, Geometry); Polygon.Z = function (exteriorRing, interiorRings, srid) { var polygon = new Polygon(exteriorRing, interiorRings, srid); polygon.hasZ = true; return polygon; }; Polygon.M = function (exteriorRing, interiorRings, srid) { var polygon = new Polygon(exteriorRing, interiorRings, srid); polygon.hasM = true; return polygon; }; Polygon.ZM = function (exteriorRing, interiorRings, srid) { var polygon = new Polygon(exteriorRing, interiorRings, srid); polygon.hasZ = true; polygon.hasM = true; return polygon; }; Polygon._parseWkt = function (value, options) { var polygon = new Polygon(); polygon.srid = options.srid; polygon.hasZ = options.hasZ; polygon.hasM = options.hasM; if (value.isMatch(['EMPTY'])) return polygon; value.expectGroupStart(); value.expectGroupStart(); polygon.exteriorRing.push.apply(polygon.exteriorRing, value.matchCoordinates(options)); value.expectGroupEnd(); while (value.isMatch([','])) { value.expectGroupStart(); polygon.interiorRings.push(value.matchCoordinates(options)); value.expectGroupEnd(); } value.expectGroupEnd(); return polygon; }; Polygon._parseWkb = function (value, options) { var polygon = new Polygon(); polygon.srid = options.srid; polygon.hasZ = options.hasZ; polygon.hasM = options.hasM; var ringCount = value.readUInt32(); if (ringCount > 0) { var exteriorRingCount = value.readUInt32(); for (var i = 0; i < exteriorRingCount; i++) polygon.exteriorRing.push(Point._readWkbPoint(value, options)); for (i = 1; i < ringCount; i++) { var interiorRing = []; var interiorRingCount = value.readUInt32(); for (var j = 0; j < interiorRingCount; j++) interiorRing.push(Point._readWkbPoint(value, options)); polygon.interiorRings.push(interiorRing); } } return polygon; }; Polygon._parseTwkb = function (value, options) { var polygon = new Polygon(); polygon.hasZ = options.hasZ; polygon.hasM = options.hasM; if (options.isEmpty) return polygon; var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined); var ringCount = value.readVarInt(); var exteriorRingCount = value.readVarInt(); for (var i = 0; i < exteriorRingCount; i++) polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint)); for (i = 1; i < ringCount; i++) { var interiorRing = []; var interiorRingCount = value.readVarInt(); for (var j = 0; j < interiorRingCount; j++) interiorRing.push(Point._readTwkbPoint(value, options, previousPoint)); polygon.interiorRings.push(interiorRing); } return polygon; }; Polygon._parseGeoJSON = function (value) { var polygon = new Polygon(); if (value.coordinates.length > 0 && value.coordinates[0].length > 0) polygon.hasZ = value.coordinates[0][0].length > 2; for (var i = 0; i < value.coordinates.length; i++) { if (i > 0) polygon.interiorRings.push([]); for (var j = 0; j < value.coordinates[i].length; j++) { if (i === 0) polygon.exteriorRing.push(Point._readGeoJSONPoint(value.coordinates[i][j])); else polygon.interiorRings[i - 1].push(Point._readGeoJSONPoint(value.coordinates[i][j])); } } return polygon; }; Polygon.prototype.toWkt = function () { if (this.exteriorRing.length === 0) return this._getWktType(Types.wkt.Polygon, true); return this._getWktType(Types.wkt.Polygon, false) + this._toInnerWkt(); }; Polygon.prototype._toInnerWkt = function () { var innerWkt = '(('; for (var i = 0; i < this.exteriorRing.length; i++) innerWkt += this._getWktCoordinate(this.exteriorRing[i]) + ','; innerWkt = innerWkt.slice(0, -1); innerWkt += ')'; for (i = 0; i < this.interiorRings.length; i++) { innerWkt += ',('; for (var j = 0; j < this.interiorRings[i].length; j++) { innerWkt += this._getWktCoordinate(this.interiorRings[i][j]) + ','; } innerWkt = innerWkt.slice(0, -1); innerWkt += ')'; } innerWkt += ')'; return innerWkt; }; Polygon.prototype.toWkb = function (parentOptions) { var wkb = new BinaryWriter(this._getWkbSize()); wkb.writeInt8(1); this._writeWkbType(wkb, Types.wkb.Polygon, parentOptions); if (this.exteriorRing.length > 0) { wkb.writeUInt32LE(1 + this.interiorRings.length); wkb.writeUInt32LE(this.exteriorRing.length); } else { wkb.writeUInt32LE(0); } for (var i = 0; i < this.exteriorRing.length; i++) this.exteriorRing[i]._writeWkbPoint(wkb); for (i = 0; i < this.interiorRings.length; i++) { wkb.writeUInt32LE(this.interiorRings[i].length); for (var j = 0; j < this.interiorRings[i].length; j++) this.interiorRings[i][j]._writeWkbPoint(wkb); } return wkb.buffer; }; Polygon.prototype.toTwkb = function () { var twkb = new BinaryWriter(0, true); var precision = Geometry.getTwkbPrecision(5, 0, 0); var isEmpty = this.exteriorRing.length === 0; this._writeTwkbHeader(twkb, Types.wkb.Polygon, precision, isEmpty); if (this.exteriorRing.length > 0) { twkb.writeVarInt(1 + this.interiorRings.length); twkb.writeVarInt(this.exteriorRing.length); var previousPoint = new Point(0, 0, 0, 0); for (var i = 0; i < this.exteriorRing.length; i++) this.exteriorRing[i]._writeTwkbPoint(twkb, precision, previousPoint); for (i = 0; i < this.interiorRings.length; i++) { twkb.writeVarInt(this.interiorRings[i].length); for (var j = 0; j < this.interiorRings[i].length; j++) this.interiorRings[i][j]._writeTwkbPoint(twkb, precision, previousPoint); } } return twkb.buffer; }; Polygon.prototype._getWkbSize = function () { var coordinateSize = 16; if (this.hasZ) coordinateSize += 8; if (this.hasM) coordinateSize += 8; var size = 1 + 4 + 4; if (this.exteriorRing.length > 0) size += 4 + (this.exteriorRing.length * coordinateSize); for (var i = 0; i < this.interiorRings.length; i++) size += 4 + (this.interiorRings[i].length * coordinateSize); return size; }; Polygon.prototype.toGeoJSON = function (options) { var geoJSON = Geometry.prototype.toGeoJSON.call(this, options); geoJSON.type = Types.geoJSON.Polygon; geoJSON.coordinates = []; if (this.exteriorRing.length > 0) { var exteriorRing = []; for (var i = 0; i < this.exteriorRing.length; i++) { if (this.hasZ) exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y, this.exteriorRing[i].z]); else exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y]); } geoJSON.coordinates.push(exteriorRing); } for (var j = 0; j < this.interiorRings.length; j++) { var interiorRing = []; for (var k = 0; k < this.interiorRings[j].length; k++) { if (this.hasZ) interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y, this.interiorRings[j][k].z]); else interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y]); } geoJSON.coordinates.push(interiorRing); } return geoJSON; };