polygon.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. module.exports = Polygon;
  2. var util = require('util');
  3. var Geometry = require('./geometry');
  4. var Types = require('./types');
  5. var Point = require('./point');
  6. var BinaryWriter = require('./binarywriter');
  7. function Polygon(exteriorRing, interiorRings, srid) {
  8. Geometry.call(this);
  9. this.exteriorRing = exteriorRing || [];
  10. this.interiorRings = interiorRings || [];
  11. this.srid = srid;
  12. if (this.exteriorRing.length > 0) {
  13. this.hasZ = this.exteriorRing[0].hasZ;
  14. this.hasM = this.exteriorRing[0].hasM;
  15. }
  16. }
  17. util.inherits(Polygon, Geometry);
  18. Polygon.Z = function (exteriorRing, interiorRings, srid) {
  19. var polygon = new Polygon(exteriorRing, interiorRings, srid);
  20. polygon.hasZ = true;
  21. return polygon;
  22. };
  23. Polygon.M = function (exteriorRing, interiorRings, srid) {
  24. var polygon = new Polygon(exteriorRing, interiorRings, srid);
  25. polygon.hasM = true;
  26. return polygon;
  27. };
  28. Polygon.ZM = function (exteriorRing, interiorRings, srid) {
  29. var polygon = new Polygon(exteriorRing, interiorRings, srid);
  30. polygon.hasZ = true;
  31. polygon.hasM = true;
  32. return polygon;
  33. };
  34. Polygon._parseWkt = function (value, options) {
  35. var polygon = new Polygon();
  36. polygon.srid = options.srid;
  37. polygon.hasZ = options.hasZ;
  38. polygon.hasM = options.hasM;
  39. if (value.isMatch(['EMPTY']))
  40. return polygon;
  41. value.expectGroupStart();
  42. value.expectGroupStart();
  43. polygon.exteriorRing.push.apply(polygon.exteriorRing, value.matchCoordinates(options));
  44. value.expectGroupEnd();
  45. while (value.isMatch([','])) {
  46. value.expectGroupStart();
  47. polygon.interiorRings.push(value.matchCoordinates(options));
  48. value.expectGroupEnd();
  49. }
  50. value.expectGroupEnd();
  51. return polygon;
  52. };
  53. Polygon._parseWkb = function (value, options) {
  54. var polygon = new Polygon();
  55. polygon.srid = options.srid;
  56. polygon.hasZ = options.hasZ;
  57. polygon.hasM = options.hasM;
  58. var ringCount = value.readUInt32();
  59. if (ringCount > 0) {
  60. var exteriorRingCount = value.readUInt32();
  61. for (var i = 0; i < exteriorRingCount; i++)
  62. polygon.exteriorRing.push(Point._readWkbPoint(value, options));
  63. for (i = 1; i < ringCount; i++) {
  64. var interiorRing = [];
  65. var interiorRingCount = value.readUInt32();
  66. for (var j = 0; j < interiorRingCount; j++)
  67. interiorRing.push(Point._readWkbPoint(value, options));
  68. polygon.interiorRings.push(interiorRing);
  69. }
  70. }
  71. return polygon;
  72. };
  73. Polygon._parseTwkb = function (value, options) {
  74. var polygon = new Polygon();
  75. polygon.hasZ = options.hasZ;
  76. polygon.hasM = options.hasM;
  77. if (options.isEmpty)
  78. return polygon;
  79. var previousPoint = new Point(0, 0, options.hasZ ? 0 : undefined, options.hasM ? 0 : undefined);
  80. var ringCount = value.readVarInt();
  81. var exteriorRingCount = value.readVarInt();
  82. for (var i = 0; i < exteriorRingCount; i++)
  83. polygon.exteriorRing.push(Point._readTwkbPoint(value, options, previousPoint));
  84. for (i = 1; i < ringCount; i++) {
  85. var interiorRing = [];
  86. var interiorRingCount = value.readVarInt();
  87. for (var j = 0; j < interiorRingCount; j++)
  88. interiorRing.push(Point._readTwkbPoint(value, options, previousPoint));
  89. polygon.interiorRings.push(interiorRing);
  90. }
  91. return polygon;
  92. };
  93. Polygon._parseGeoJSON = function (value) {
  94. var polygon = new Polygon();
  95. if (value.coordinates.length > 0 && value.coordinates[0].length > 0)
  96. polygon.hasZ = value.coordinates[0][0].length > 2;
  97. for (var i = 0; i < value.coordinates.length; i++) {
  98. if (i > 0)
  99. polygon.interiorRings.push([]);
  100. for (var j = 0; j < value.coordinates[i].length; j++) {
  101. if (i === 0)
  102. polygon.exteriorRing.push(Point._readGeoJSONPoint(value.coordinates[i][j]));
  103. else
  104. polygon.interiorRings[i - 1].push(Point._readGeoJSONPoint(value.coordinates[i][j]));
  105. }
  106. }
  107. return polygon;
  108. };
  109. Polygon.prototype.toWkt = function () {
  110. if (this.exteriorRing.length === 0)
  111. return this._getWktType(Types.wkt.Polygon, true);
  112. return this._getWktType(Types.wkt.Polygon, false) + this._toInnerWkt();
  113. };
  114. Polygon.prototype._toInnerWkt = function () {
  115. var innerWkt = '((';
  116. for (var i = 0; i < this.exteriorRing.length; i++)
  117. innerWkt += this._getWktCoordinate(this.exteriorRing[i]) + ',';
  118. innerWkt = innerWkt.slice(0, -1);
  119. innerWkt += ')';
  120. for (i = 0; i < this.interiorRings.length; i++) {
  121. innerWkt += ',(';
  122. for (var j = 0; j < this.interiorRings[i].length; j++) {
  123. innerWkt += this._getWktCoordinate(this.interiorRings[i][j]) + ',';
  124. }
  125. innerWkt = innerWkt.slice(0, -1);
  126. innerWkt += ')';
  127. }
  128. innerWkt += ')';
  129. return innerWkt;
  130. };
  131. Polygon.prototype.toWkb = function (parentOptions) {
  132. var wkb = new BinaryWriter(this._getWkbSize());
  133. wkb.writeInt8(1);
  134. this._writeWkbType(wkb, Types.wkb.Polygon, parentOptions);
  135. if (this.exteriorRing.length > 0) {
  136. wkb.writeUInt32LE(1 + this.interiorRings.length);
  137. wkb.writeUInt32LE(this.exteriorRing.length);
  138. }
  139. else {
  140. wkb.writeUInt32LE(0);
  141. }
  142. for (var i = 0; i < this.exteriorRing.length; i++)
  143. this.exteriorRing[i]._writeWkbPoint(wkb);
  144. for (i = 0; i < this.interiorRings.length; i++) {
  145. wkb.writeUInt32LE(this.interiorRings[i].length);
  146. for (var j = 0; j < this.interiorRings[i].length; j++)
  147. this.interiorRings[i][j]._writeWkbPoint(wkb);
  148. }
  149. return wkb.buffer;
  150. };
  151. Polygon.prototype.toTwkb = function () {
  152. var twkb = new BinaryWriter(0, true);
  153. var precision = Geometry.getTwkbPrecision(5, 0, 0);
  154. var isEmpty = this.exteriorRing.length === 0;
  155. this._writeTwkbHeader(twkb, Types.wkb.Polygon, precision, isEmpty);
  156. if (this.exteriorRing.length > 0) {
  157. twkb.writeVarInt(1 + this.interiorRings.length);
  158. twkb.writeVarInt(this.exteriorRing.length);
  159. var previousPoint = new Point(0, 0, 0, 0);
  160. for (var i = 0; i < this.exteriorRing.length; i++)
  161. this.exteriorRing[i]._writeTwkbPoint(twkb, precision, previousPoint);
  162. for (i = 0; i < this.interiorRings.length; i++) {
  163. twkb.writeVarInt(this.interiorRings[i].length);
  164. for (var j = 0; j < this.interiorRings[i].length; j++)
  165. this.interiorRings[i][j]._writeTwkbPoint(twkb, precision, previousPoint);
  166. }
  167. }
  168. return twkb.buffer;
  169. };
  170. Polygon.prototype._getWkbSize = function () {
  171. var coordinateSize = 16;
  172. if (this.hasZ)
  173. coordinateSize += 8;
  174. if (this.hasM)
  175. coordinateSize += 8;
  176. var size = 1 + 4 + 4;
  177. if (this.exteriorRing.length > 0)
  178. size += 4 + (this.exteriorRing.length * coordinateSize);
  179. for (var i = 0; i < this.interiorRings.length; i++)
  180. size += 4 + (this.interiorRings[i].length * coordinateSize);
  181. return size;
  182. };
  183. Polygon.prototype.toGeoJSON = function (options) {
  184. var geoJSON = Geometry.prototype.toGeoJSON.call(this, options);
  185. geoJSON.type = Types.geoJSON.Polygon;
  186. geoJSON.coordinates = [];
  187. if (this.exteriorRing.length > 0) {
  188. var exteriorRing = [];
  189. for (var i = 0; i < this.exteriorRing.length; i++) {
  190. if (this.hasZ)
  191. exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y, this.exteriorRing[i].z]);
  192. else
  193. exteriorRing.push([this.exteriorRing[i].x, this.exteriorRing[i].y]);
  194. }
  195. geoJSON.coordinates.push(exteriorRing);
  196. }
  197. for (var j = 0; j < this.interiorRings.length; j++) {
  198. var interiorRing = [];
  199. for (var k = 0; k < this.interiorRings[j].length; k++) {
  200. if (this.hasZ)
  201. interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y, this.interiorRings[j][k].z]);
  202. else
  203. interiorRing.push([this.interiorRings[j][k].x, this.interiorRings[j][k].y]);
  204. }
  205. geoJSON.coordinates.push(interiorRing);
  206. }
  207. return geoJSON;
  208. };