simplify.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. .pragma library
  2. /*
  3. (c) 2013, Vladimir Agafonkin
  4. Simplify.js, a high-performance JS polyline simplification library
  5. mourner.github.io/simplify-js
  6. */
  7. 'use strict';
  8. // to suit your point format, run search/replace for '.x' and '.y';
  9. // for 3D version, see 3d branch (configurability would draw significant performance overhead)
  10. // square distance between 2 points
  11. function getSqDist(p1, p2) {
  12. var dx = p1.x - p2.x,
  13. dy = p1.y - p2.y;
  14. return dx * dx + dy * dy;
  15. }
  16. // square distance from a point to a segment
  17. function getSqSegDist(p, p1, p2) {
  18. var x = p1.x,
  19. y = p1.y,
  20. dx = p2.x - x,
  21. dy = p2.y - y;
  22. if (dx !== 0 || dy !== 0) {
  23. var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
  24. if (t > 1) {
  25. x = p2.x;
  26. y = p2.y;
  27. } else if (t > 0) {
  28. x += dx * t;
  29. y += dy * t;
  30. }
  31. }
  32. dx = p.x - x;
  33. dy = p.y - y;
  34. return dx * dx + dy * dy;
  35. }
  36. // rest of the code doesn't care about point format
  37. // basic distance-based simplification
  38. function simplifyRadialDist(points, sqTolerance) {
  39. var prevPoint = points[0],
  40. newPoints = [prevPoint],
  41. point;
  42. for (var i = 1, len = points.length; i < len; i++) {
  43. point = points[i];
  44. if (getSqDist(point, prevPoint) > sqTolerance) {
  45. newPoints.push(point);
  46. prevPoint = point;
  47. }
  48. }
  49. if (prevPoint !== point) newPoints.push(point);
  50. return newPoints;
  51. }
  52. function simplifyDPStep(points, first, last, sqTolerance, simplified) {
  53. var maxSqDist = sqTolerance,
  54. index;
  55. for (var i = first + 1; i < last; i++) {
  56. var sqDist = getSqSegDist(points[i], points[first], points[last]);
  57. if (sqDist > maxSqDist) {
  58. index = i;
  59. maxSqDist = sqDist;
  60. }
  61. }
  62. if (maxSqDist > sqTolerance) {
  63. if (index - first > 1) simplifyDPStep(points, first, index, sqTolerance, simplified);
  64. simplified.push(points[index]);
  65. if (last - index > 1) simplifyDPStep(points, index, last, sqTolerance, simplified);
  66. }
  67. }
  68. // simplification using Ramer-Douglas-Peucker algorithm
  69. function simplifyDouglasPeucker(points, sqTolerance) {
  70. var last = points.length - 1;
  71. var simplified = [points[0]];
  72. simplifyDPStep(points, 0, last, sqTolerance, simplified);
  73. simplified.push(points[last]);
  74. return simplified;
  75. }
  76. // both algorithms combined for awesome performance
  77. function simplify(points, tolerance, highestQuality) {
  78. if (points.length <= 2) return points;
  79. var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;
  80. points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);
  81. points = simplifyDouglasPeucker(points, sqTolerance);
  82. return points;
  83. }
  84. /*
  85. // export as AMD module / Node module / browser or worker variable
  86. if (typeof define === 'function' && define.amd) define(function() { return simplify; });
  87. else if (typeof module !== 'undefined') module.exports = simplify;
  88. else if (typeof self !== 'undefined') self.simplify = simplify;
  89. else window.simplify = simplify;
  90. })();
  91. */