智慧水务管理系统 - 精河县供水工程综合管理平台

PolyUtil.js 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import * as LineUtil from './LineUtil';
  2. import {toLatLng} from '../geo/LatLng';
  3. import {toPoint} from './Point';
  4. import {toLatLngBounds} from '../geo/LatLngBounds';
  5. /*
  6. * @namespace PolyUtil
  7. * Various utility functions for polygon geometries.
  8. */
  9. /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
  10. * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
  11. * Used by Leaflet to only show polygon points that are on the screen or near, increasing
  12. * performance. Note that polygon points needs different algorithm for clipping
  13. * than polyline, so there's a separate method for it.
  14. */
  15. export function clipPolygon(points, bounds, round) {
  16. var clippedPoints,
  17. edges = [1, 4, 2, 8],
  18. i, j, k,
  19. a, b,
  20. len, edge, p;
  21. for (i = 0, len = points.length; i < len; i++) {
  22. points[i]._code = LineUtil._getBitCode(points[i], bounds);
  23. }
  24. // for each edge (left, bottom, right, top)
  25. for (k = 0; k < 4; k++) {
  26. edge = edges[k];
  27. clippedPoints = [];
  28. for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
  29. a = points[i];
  30. b = points[j];
  31. // if a is inside the clip window
  32. if (!(a._code & edge)) {
  33. // if b is outside the clip window (a->b goes out of screen)
  34. if (b._code & edge) {
  35. p = LineUtil._getEdgeIntersection(b, a, edge, bounds, round);
  36. p._code = LineUtil._getBitCode(p, bounds);
  37. clippedPoints.push(p);
  38. }
  39. clippedPoints.push(a);
  40. // else if b is inside the clip window (a->b enters the screen)
  41. } else if (!(b._code & edge)) {
  42. p = LineUtil._getEdgeIntersection(b, a, edge, bounds, round);
  43. p._code = LineUtil._getBitCode(p, bounds);
  44. clippedPoints.push(p);
  45. }
  46. }
  47. points = clippedPoints;
  48. }
  49. return points;
  50. }
  51. /* @function polygonCenter(latlngs: LatLng[], crs: CRS): LatLng
  52. * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polygon.
  53. */
  54. export function polygonCenter(latlngs, crs) {
  55. var i, j, p1, p2, f, area, x, y, center;
  56. if (!latlngs || latlngs.length === 0) {
  57. throw new Error('latlngs not passed');
  58. }
  59. if (!LineUtil.isFlat(latlngs)) {
  60. console.warn('latlngs are not flat! Only the first ring will be used');
  61. latlngs = latlngs[0];
  62. }
  63. var centroidLatLng = toLatLng([0, 0]);
  64. var bounds = toLatLngBounds(latlngs);
  65. var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest());
  66. // tests showed that below 1700 rounding errors are happening
  67. if (areaBounds < 1700) {
  68. // getting a inexact center, to move the latlngs near to [0, 0] to prevent rounding errors
  69. centroidLatLng = centroid(latlngs);
  70. }
  71. var len = latlngs.length;
  72. var points = [];
  73. for (i = 0; i < len; i++) {
  74. var latlng = toLatLng(latlngs[i]);
  75. points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng])));
  76. }
  77. area = x = y = 0;
  78. // polygon centroid algorithm;
  79. for (i = 0, j = len - 1; i < len; j = i++) {
  80. p1 = points[i];
  81. p2 = points[j];
  82. f = p1.y * p2.x - p2.y * p1.x;
  83. x += (p1.x + p2.x) * f;
  84. y += (p1.y + p2.y) * f;
  85. area += f * 3;
  86. }
  87. if (area === 0) {
  88. // Polygon is so small that all points are on same pixel.
  89. center = points[0];
  90. } else {
  91. center = [x / area, y / area];
  92. }
  93. var latlngCenter = crs.unproject(toPoint(center));
  94. return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]);
  95. }
  96. /* @function centroid(latlngs: LatLng[]): LatLng
  97. * Returns the 'center of mass' of the passed LatLngs.
  98. */
  99. export function centroid(coords) {
  100. var latSum = 0;
  101. var lngSum = 0;
  102. var len = 0;
  103. for (var i = 0; i < coords.length; i++) {
  104. var latlng = toLatLng(coords[i]);
  105. latSum += latlng.lat;
  106. lngSum += latlng.lng;
  107. len++;
  108. }
  109. return toLatLng([latSum / len, lngSum / len]);
  110. }