EdgeRing.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import { orientationIndex, envelopeIsEqual, envelopeContains, coordinatesEqual, } from "./util.js";
  2. import { multiPoint, polygon, point, } from "@turf/helpers";
  3. import envelope from "@turf/envelope";
  4. import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
  5. /**
  6. * Ring of edges which form a polygon.
  7. *
  8. * The ring may be either an outer shell or a hole.
  9. *
  10. * This class is inspired in GEOS's geos::operation::polygonize::EdgeRing
  11. */
  12. var EdgeRing = /** @class */ (function () {
  13. function EdgeRing() {
  14. this.edges = [];
  15. this.polygon = undefined; //< Caches Polygon representation
  16. this.envelope = undefined; //< Caches Envelope representation
  17. }
  18. /**
  19. * Add an edge to the ring, inserting it in the last position.
  20. *
  21. * @memberof EdgeRing
  22. * @param {Edge} edge - Edge to be inserted
  23. */
  24. EdgeRing.prototype.push = function (edge) {
  25. this.edges.push(edge);
  26. this.polygon = this.envelope = undefined;
  27. };
  28. /**
  29. * Get Edge.
  30. *
  31. * @memberof EdgeRing
  32. * @param {number} i - Index
  33. * @returns {Edge} - Edge in the i position
  34. */
  35. EdgeRing.prototype.get = function (i) {
  36. return this.edges[i];
  37. };
  38. Object.defineProperty(EdgeRing.prototype, "length", {
  39. /**
  40. * Getter of length property.
  41. *
  42. * @memberof EdgeRing
  43. * @returns {number} - Length of the edge ring.
  44. */
  45. get: function () {
  46. return this.edges.length;
  47. },
  48. enumerable: true,
  49. configurable: true
  50. });
  51. /**
  52. * Similar to Array.prototype.forEach for the list of Edges in the EdgeRing.
  53. *
  54. * @memberof EdgeRing
  55. * @param {Function} f - The same function to be passed to Array.prototype.forEach
  56. */
  57. EdgeRing.prototype.forEach = function (f) {
  58. this.edges.forEach(f);
  59. };
  60. /**
  61. * Similar to Array.prototype.map for the list of Edges in the EdgeRing.
  62. *
  63. * @memberof EdgeRing
  64. * @param {Function} f - The same function to be passed to Array.prototype.map
  65. * @returns {Array} - The mapped values in the function
  66. */
  67. EdgeRing.prototype.map = function (f) {
  68. return this.edges.map(f);
  69. };
  70. /**
  71. * Similar to Array.prototype.some for the list of Edges in the EdgeRing.
  72. *
  73. * @memberof EdgeRing
  74. * @param {Function} f - The same function to be passed to Array.prototype.some
  75. * @returns {boolean} - True if an Edge check the condition
  76. */
  77. EdgeRing.prototype.some = function (f) {
  78. return this.edges.some(f);
  79. };
  80. /**
  81. * Check if the ring is valid in geomtry terms.
  82. *
  83. * A ring must have either 0 or 4 or more points. The first and the last must be
  84. * equal (in 2D)
  85. * geos::geom::LinearRing::validateConstruction
  86. *
  87. * @memberof EdgeRing
  88. * @returns {boolean} - Validity of the EdgeRing
  89. */
  90. EdgeRing.prototype.isValid = function () {
  91. // TODO: stub
  92. return true;
  93. };
  94. /**
  95. * Tests whether this ring is a hole.
  96. *
  97. * A ring is a hole if it is oriented counter-clockwise.
  98. * Similar implementation of geos::algorithm::CGAlgorithms::isCCW
  99. *
  100. * @memberof EdgeRing
  101. * @returns {boolean} - true: if it is a hole
  102. */
  103. EdgeRing.prototype.isHole = function () {
  104. var _this = this;
  105. // XXX: Assuming Ring is valid
  106. // Find highest point
  107. var hiIndex = this.edges.reduce(function (high, edge, i) {
  108. if (edge.from.coordinates[1] > _this.edges[high].from.coordinates[1])
  109. high = i;
  110. return high;
  111. }, 0), iPrev = (hiIndex === 0 ? this.length : hiIndex) - 1, iNext = (hiIndex + 1) % this.length, disc = orientationIndex(this.edges[iPrev].from.coordinates, this.edges[hiIndex].from.coordinates, this.edges[iNext].from.coordinates);
  112. if (disc === 0)
  113. return (this.edges[iPrev].from.coordinates[0] >
  114. this.edges[iNext].from.coordinates[0]);
  115. return disc > 0;
  116. };
  117. /**
  118. * Creates a MultiPoint representing the EdgeRing (discarts edges directions).
  119. *
  120. * @memberof EdgeRing
  121. * @returns {Feature<MultiPoint>} - Multipoint representation of the EdgeRing
  122. */
  123. EdgeRing.prototype.toMultiPoint = function () {
  124. return multiPoint(this.edges.map(function (edge) { return edge.from.coordinates; }));
  125. };
  126. /**
  127. * Creates a Polygon representing the EdgeRing.
  128. *
  129. * @memberof EdgeRing
  130. * @returns {Feature<Polygon>} - Polygon representation of the Edge Ring
  131. */
  132. EdgeRing.prototype.toPolygon = function () {
  133. if (this.polygon)
  134. return this.polygon;
  135. var coordinates = this.edges.map(function (edge) { return edge.from.coordinates; });
  136. coordinates.push(this.edges[0].from.coordinates);
  137. return (this.polygon = polygon([coordinates]));
  138. };
  139. /**
  140. * Calculates the envelope of the EdgeRing.
  141. *
  142. * @memberof EdgeRing
  143. * @returns {Feature<Polygon>} - envelope
  144. */
  145. EdgeRing.prototype.getEnvelope = function () {
  146. if (this.envelope)
  147. return this.envelope;
  148. return (this.envelope = envelope(this.toPolygon()));
  149. };
  150. /**
  151. * `geos::operation::polygonize::EdgeRing::findEdgeRingContaining`
  152. *
  153. * @param {EdgeRing} testEdgeRing - EdgeRing to look in the list
  154. * @param {EdgeRing[]} shellList - List of EdgeRing in which to search
  155. *
  156. * @returns {EdgeRing} - EdgeRing which contains the testEdgeRing
  157. */
  158. EdgeRing.findEdgeRingContaining = function (testEdgeRing, shellList) {
  159. var testEnvelope = testEdgeRing.getEnvelope();
  160. var minEnvelope, minShell;
  161. shellList.forEach(function (shell) {
  162. var tryEnvelope = shell.getEnvelope();
  163. if (minShell)
  164. minEnvelope = minShell.getEnvelope();
  165. // the hole envelope cannot equal the shell envelope
  166. if (envelopeIsEqual(tryEnvelope, testEnvelope))
  167. return;
  168. if (envelopeContains(tryEnvelope, testEnvelope)) {
  169. var testEdgeRingCoordinates = testEdgeRing.map(function (edge) { return edge.from.coordinates; });
  170. var testPoint = void 0;
  171. var _loop_1 = function (pt) {
  172. if (!shell.some(function (edge) { return coordinatesEqual(pt, edge.from.coordinates); })) {
  173. testPoint = pt;
  174. }
  175. };
  176. for (var _i = 0, testEdgeRingCoordinates_1 = testEdgeRingCoordinates; _i < testEdgeRingCoordinates_1.length; _i++) {
  177. var pt = testEdgeRingCoordinates_1[_i];
  178. _loop_1(pt);
  179. }
  180. if (testPoint && shell.inside(point(testPoint))) {
  181. if (!minShell || envelopeContains(minEnvelope, tryEnvelope))
  182. minShell = shell;
  183. }
  184. }
  185. });
  186. return minShell;
  187. };
  188. /**
  189. * Checks if the point is inside the edgeRing
  190. *
  191. * @param {Feature<Point>} pt - Point to check if it is inside the edgeRing
  192. * @returns {boolean} - True if it is inside, False otherwise
  193. */
  194. EdgeRing.prototype.inside = function (pt) {
  195. return booleanPointInPolygon(pt, this.toPolygon());
  196. };
  197. return EdgeRing;
  198. }());
  199. export default EdgeRing;