ParsePolygon.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _ParseGeoPoint = _interopRequireDefault(require("./ParseGeoPoint"));
  7. function _interopRequireDefault(obj) {
  8. return obj && obj.__esModule ? obj : {
  9. default: obj
  10. };
  11. }
  12. /**
  13. * @flow
  14. */
  15. /**
  16. * Creates a new Polygon with any of the following forms:<br>
  17. * <pre>
  18. * new Polygon([[0,0],[0,1],[1,1],[1,0]])
  19. * new Polygon([GeoPoint, GeoPoint, GeoPoint])
  20. * </pre>
  21. *
  22. * <p>Represents a coordinates that may be associated
  23. * with a key in a ParseObject or used as a reference point for geo queries.
  24. * This allows proximity-based queries on the key.</p>
  25. *
  26. * <p>Example:<pre>
  27. * var polygon = new Parse.Polygon([[0,0],[0,1],[1,1],[1,0]]);
  28. * var object = new Parse.Object("PlaceObject");
  29. * object.set("area", polygon);
  30. * object.save();</pre></p>
  31. *
  32. * @alias Parse.Polygon
  33. */
  34. class ParsePolygon {
  35. /*:: _coordinates: Array<Array<number>>;*/
  36. /**
  37. * @param {(number[][] | Parse.GeoPoint[])} coordinates An Array of coordinate pairs
  38. */
  39. constructor(coordinates /*: Array<Array<number>> | Array<ParseGeoPoint>*/) {
  40. this._coordinates = ParsePolygon._validate(coordinates);
  41. }
  42. /**
  43. * Coordinates value for this Polygon.
  44. * Throws an exception if not valid type.
  45. *
  46. * @property {(number[][] | Parse.GeoPoint[])} coordinates list of coordinates
  47. * @returns {number[][]}
  48. */
  49. get coordinates() /*: Array<Array<number>>*/{
  50. return this._coordinates;
  51. }
  52. set coordinates(coords /*: Array<Array<number>> | Array<ParseGeoPoint>*/) {
  53. this._coordinates = ParsePolygon._validate(coords);
  54. }
  55. /**
  56. * Returns a JSON representation of the Polygon, suitable for Parse.
  57. *
  58. * @returns {object}
  59. */
  60. toJSON() /*: { __type: string, coordinates: Array<Array<number>> }*/{
  61. ParsePolygon._validate(this._coordinates);
  62. return {
  63. __type: 'Polygon',
  64. coordinates: this._coordinates
  65. };
  66. }
  67. /**
  68. * Checks if two polygons are equal
  69. *
  70. * @param {(Parse.Polygon | object)} other
  71. * @returns {boolean}
  72. */
  73. equals(other /*: mixed*/) /*: boolean*/{
  74. if (!(other instanceof ParsePolygon) || this.coordinates.length !== other.coordinates.length) {
  75. return false;
  76. }
  77. let isEqual = true;
  78. for (let i = 1; i < this._coordinates.length; i += 1) {
  79. if (this._coordinates[i][0] != other.coordinates[i][0] || this._coordinates[i][1] != other.coordinates[i][1]) {
  80. isEqual = false;
  81. break;
  82. }
  83. }
  84. return isEqual;
  85. }
  86. /**
  87. *
  88. * @param {Parse.GeoPoint} point
  89. * @returns {boolean} Returns if the point is contained in the polygon
  90. */
  91. containsPoint(point /*: ParseGeoPoint*/) /*: boolean*/{
  92. let minX = this._coordinates[0][0];
  93. let maxX = this._coordinates[0][0];
  94. let minY = this._coordinates[0][1];
  95. let maxY = this._coordinates[0][1];
  96. for (let i = 1; i < this._coordinates.length; i += 1) {
  97. const p = this._coordinates[i];
  98. minX = Math.min(p[0], minX);
  99. maxX = Math.max(p[0], maxX);
  100. minY = Math.min(p[1], minY);
  101. maxY = Math.max(p[1], maxY);
  102. }
  103. const outside = point.latitude < minX || point.latitude > maxX || point.longitude < minY || point.longitude > maxY;
  104. if (outside) {
  105. return false;
  106. }
  107. let inside = false;
  108. for (let i = 0, j = this._coordinates.length - 1; i < this._coordinates.length; j = i++) {
  109. const startX = this._coordinates[i][0];
  110. const startY = this._coordinates[i][1];
  111. const endX = this._coordinates[j][0];
  112. const endY = this._coordinates[j][1];
  113. const intersect = startY > point.longitude != endY > point.longitude && point.latitude < (endX - startX) * (point.longitude - startY) / (endY - startY) + startX;
  114. if (intersect) {
  115. inside = !inside;
  116. }
  117. }
  118. return inside;
  119. }
  120. /**
  121. * Validates that the list of coordinates can form a valid polygon
  122. *
  123. * @param {Array} coords the list of coordinates to validate as a polygon
  124. * @throws {TypeError}
  125. * @returns {number[][]} Array of coordinates if validated.
  126. */
  127. static _validate(coords /*: Array<Array<number>> | Array<ParseGeoPoint>*/) /*: Array<Array<number>>*/{
  128. if (!Array.isArray(coords)) {
  129. throw new TypeError('Coordinates must be an Array');
  130. }
  131. if (coords.length < 3) {
  132. throw new TypeError('Polygon must have at least 3 GeoPoints or Points');
  133. }
  134. const points = [];
  135. for (let i = 0; i < coords.length; i += 1) {
  136. const coord = coords[i];
  137. let geoPoint;
  138. if (coord instanceof _ParseGeoPoint.default) {
  139. geoPoint = coord;
  140. } else if (Array.isArray(coord) && coord.length === 2) {
  141. geoPoint = new _ParseGeoPoint.default(coord[0], coord[1]);
  142. } else {
  143. throw new TypeError('Coordinates must be an Array of GeoPoints or Points');
  144. }
  145. points.push([geoPoint.latitude, geoPoint.longitude]);
  146. }
  147. return points;
  148. }
  149. }
  150. var _default = ParsePolygon;
  151. exports.default = _default;