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