index.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import explode from '@turf/explode';
  2. import centroid from '@turf/center';
  3. import nearestPoint from '@turf/nearest-point';
  4. import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
  5. import { featureCollection, point, feature } from '@turf/helpers';
  6. /**
  7. * Takes a Feature or FeatureCollection and returns a {@link Point} guaranteed to be on the surface of the feature.
  8. *
  9. * * Given a {@link Polygon}, the point will be in the area of the polygon
  10. * * Given a {@link LineString}, the point will be along the string
  11. * * Given a {@link Point}, the point will the same as the input
  12. *
  13. * @name pointOnFeature
  14. * @param {GeoJSON} geojson any Feature or FeatureCollection
  15. * @returns {Feature<Point>} a point on the surface of `input`
  16. * @example
  17. * var polygon = turf.polygon([[
  18. * [116, -36],
  19. * [131, -32],
  20. * [146, -43],
  21. * [155, -25],
  22. * [133, -9],
  23. * [111, -22],
  24. * [116, -36]
  25. * ]]);
  26. *
  27. * var pointOnPolygon = turf.pointOnFeature(polygon);
  28. *
  29. * //addToMap
  30. * var addToMap = [polygon, pointOnPolygon];
  31. */
  32. function pointOnFeature(geojson) {
  33. // normalize
  34. var fc = normalize(geojson);
  35. // get centroid
  36. var cent = centroid(fc);
  37. // check to see if centroid is on surface
  38. var onSurface = false;
  39. var i = 0;
  40. while (!onSurface && i < fc.features.length) {
  41. var geom = fc.features[i].geometry;
  42. var x, y, x1, y1, x2, y2, k;
  43. var onLine = false;
  44. if (geom.type === "Point") {
  45. if (
  46. cent.geometry.coordinates[0] === geom.coordinates[0] &&
  47. cent.geometry.coordinates[1] === geom.coordinates[1]
  48. ) {
  49. onSurface = true;
  50. }
  51. } else if (geom.type === "MultiPoint") {
  52. var onMultiPoint = false;
  53. k = 0;
  54. while (!onMultiPoint && k < geom.coordinates.length) {
  55. if (
  56. cent.geometry.coordinates[0] === geom.coordinates[k][0] &&
  57. cent.geometry.coordinates[1] === geom.coordinates[k][1]
  58. ) {
  59. onSurface = true;
  60. onMultiPoint = true;
  61. }
  62. k++;
  63. }
  64. } else if (geom.type === "LineString") {
  65. k = 0;
  66. while (!onLine && k < geom.coordinates.length - 1) {
  67. x = cent.geometry.coordinates[0];
  68. y = cent.geometry.coordinates[1];
  69. x1 = geom.coordinates[k][0];
  70. y1 = geom.coordinates[k][1];
  71. x2 = geom.coordinates[k + 1][0];
  72. y2 = geom.coordinates[k + 1][1];
  73. if (pointOnSegment(x, y, x1, y1, x2, y2)) {
  74. onLine = true;
  75. onSurface = true;
  76. }
  77. k++;
  78. }
  79. } else if (geom.type === "MultiLineString") {
  80. var j = 0;
  81. while (j < geom.coordinates.length) {
  82. onLine = false;
  83. k = 0;
  84. var line = geom.coordinates[j];
  85. while (!onLine && k < line.length - 1) {
  86. x = cent.geometry.coordinates[0];
  87. y = cent.geometry.coordinates[1];
  88. x1 = line[k][0];
  89. y1 = line[k][1];
  90. x2 = line[k + 1][0];
  91. y2 = line[k + 1][1];
  92. if (pointOnSegment(x, y, x1, y1, x2, y2)) {
  93. onLine = true;
  94. onSurface = true;
  95. }
  96. k++;
  97. }
  98. j++;
  99. }
  100. } else if (geom.type === "Polygon" || geom.type === "MultiPolygon") {
  101. if (booleanPointInPolygon(cent, geom)) {
  102. onSurface = true;
  103. }
  104. }
  105. i++;
  106. }
  107. if (onSurface) {
  108. return cent;
  109. } else {
  110. var vertices = featureCollection([]);
  111. for (i = 0; i < fc.features.length; i++) {
  112. vertices.features = vertices.features.concat(
  113. explode(fc.features[i]).features
  114. );
  115. }
  116. // Remove distanceToPoint properties from nearestPoint()
  117. return point(nearestPoint(cent, vertices).geometry.coordinates);
  118. }
  119. }
  120. /**
  121. * Normalizes any GeoJSON to a FeatureCollection
  122. *
  123. * @private
  124. * @name normalize
  125. * @param {GeoJSON} geojson Any GeoJSON
  126. * @returns {FeatureCollection} FeatureCollection
  127. */
  128. function normalize(geojson) {
  129. if (geojson.type !== "FeatureCollection") {
  130. if (geojson.type !== "Feature") {
  131. return featureCollection([feature(geojson)]);
  132. }
  133. return featureCollection([geojson]);
  134. }
  135. return geojson;
  136. }
  137. function pointOnSegment(x, y, x1, y1, x2, y2) {
  138. var ab = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
  139. var ap = Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
  140. var pb = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
  141. return ab === ap + pb;
  142. }
  143. export default pointOnFeature;