resample.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import {cartesian} from "../cartesian";
  2. import {abs, asin, atan2, cos, epsilon, radians, sqrt} from "../math";
  3. import {transformer} from "../transform";
  4. var maxDepth = 16, // maximum depth of subdivision
  5. cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
  6. export default function(project, delta2) {
  7. return +delta2 ? resample(project, delta2) : resampleNone(project);
  8. }
  9. function resampleNone(project) {
  10. return transformer({
  11. point: function(x, y) {
  12. x = project(x, y);
  13. this.stream.point(x[0], x[1]);
  14. }
  15. });
  16. }
  17. function resample(project, delta2) {
  18. function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
  19. var dx = x1 - x0,
  20. dy = y1 - y0,
  21. d2 = dx * dx + dy * dy;
  22. if (d2 > 4 * delta2 && depth--) {
  23. var a = a0 + a1,
  24. b = b0 + b1,
  25. c = c0 + c1,
  26. m = sqrt(a * a + b * b + c * c),
  27. phi2 = asin(c /= m),
  28. lambda2 = abs(abs(c) - 1) < epsilon || abs(lambda0 - lambda1) < epsilon ? (lambda0 + lambda1) / 2 : atan2(b, a),
  29. p = project(lambda2, phi2),
  30. x2 = p[0],
  31. y2 = p[1],
  32. dx2 = x2 - x0,
  33. dy2 = y2 - y0,
  34. dz = dy * dx2 - dx * dy2;
  35. if (dz * dz / d2 > delta2 // perpendicular projected distance
  36. || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
  37. || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
  38. resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
  39. stream.point(x2, y2);
  40. resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
  41. }
  42. }
  43. }
  44. return function(stream) {
  45. var lambda00, x00, y00, a00, b00, c00, // first point
  46. lambda0, x0, y0, a0, b0, c0; // previous point
  47. var resampleStream = {
  48. point: point,
  49. lineStart: lineStart,
  50. lineEnd: lineEnd,
  51. polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
  52. polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
  53. };
  54. function point(x, y) {
  55. x = project(x, y);
  56. stream.point(x[0], x[1]);
  57. }
  58. function lineStart() {
  59. x0 = NaN;
  60. resampleStream.point = linePoint;
  61. stream.lineStart();
  62. }
  63. function linePoint(lambda, phi) {
  64. var c = cartesian([lambda, phi]), p = project(lambda, phi);
  65. resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
  66. stream.point(x0, y0);
  67. }
  68. function lineEnd() {
  69. resampleStream.point = point;
  70. stream.lineEnd();
  71. }
  72. function ringStart() {
  73. lineStart();
  74. resampleStream.point = ringPoint;
  75. resampleStream.lineEnd = ringEnd;
  76. }
  77. function ringPoint(lambda, phi) {
  78. linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
  79. resampleStream.point = linePoint;
  80. }
  81. function ringEnd() {
  82. resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
  83. resampleStream.lineEnd = lineEnd;
  84. lineEnd();
  85. }
  86. return resampleStream;
  87. };
  88. }