-
Notifications
You must be signed in to change notification settings - Fork 202
/
Copy pathhammerRetroazimuthal.js
109 lines (97 loc) · 3.1 KB
/
hammerRetroazimuthal.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import {geoProjectionMutator as projectionMutator, geoCircle} from "d3-geo";
import {abs, acos, asin, atan2, cos, degrees, epsilon, halfPi, radians, sqrt, sin} from "./math.js";
export function hammerRetroazimuthalRaw(phi0) {
var sinPhi0 = sin(phi0),
cosPhi0 = cos(phi0),
rotate = hammerRetroazimuthalRotation(phi0);
rotate.invert = hammerRetroazimuthalRotation(-phi0);
function forward(lambda, phi) {
var p = rotate(lambda, phi);
lambda = p[0], phi = p[1];
var sinPhi = sin(phi),
cosPhi = cos(phi),
cosLambda = cos(lambda),
z = acos(sinPhi0 * sinPhi + cosPhi0 * cosPhi * cosLambda),
sinz = sin(z),
K = abs(sinz) > epsilon ? z / sinz : 1;
return [
K * cosPhi0 * sin(lambda),
(abs(lambda) > halfPi ? K : -K) // rotate for back hemisphere
* (sinPhi0 * cosPhi - cosPhi0 * sinPhi * cosLambda)
];
}
forward.invert = function(x, y) {
var rho = sqrt(x * x + y * y),
sinz = -sin(rho),
cosz = cos(rho),
a = rho * cosz,
b = -y * sinz,
c = rho * sinPhi0,
d = sqrt(a * a + b * b - c * c),
phi = atan2(a * c + b * d, b * c - a * d),
lambda = (rho > halfPi ? -1 : 1) * atan2(x * sinz, rho * cos(phi) * cosz + y * sin(phi) * sinz);
return rotate.invert(lambda, phi);
};
return forward;
}
// Latitudinal rotation by phi0.
// Temporary hack until D3 supports arbitrary small-circle clipping origins.
function hammerRetroazimuthalRotation(phi0) {
var sinPhi0 = sin(phi0),
cosPhi0 = cos(phi0);
return function(lambda, phi) {
var cosPhi = cos(phi),
x = cos(lambda) * cosPhi,
y = sin(lambda) * cosPhi,
z = sin(phi);
return [
atan2(y, x * cosPhi0 - z * sinPhi0),
asin(z * cosPhi0 + x * sinPhi0)
];
};
}
export default function() {
var phi0 = 0,
m = projectionMutator(hammerRetroazimuthalRaw),
p = m(phi0),
rotate_ = p.rotate,
stream_ = p.stream,
circle = geoCircle();
p.parallel = function(_) {
if (!arguments.length) return phi0 * degrees;
var r = p.rotate();
return m(phi0 = _ * radians).rotate(r);
};
// Temporary hack; see hammerRetroazimuthalRotation.
p.rotate = function(_) {
if (!arguments.length) return (_ = rotate_.call(p), _[1] += phi0 * degrees, _);
rotate_.call(p, [_[0], _[1] - phi0 * degrees]);
circle.center([-_[0], -_[1]]);
return p;
};
p.stream = function(stream) {
stream = stream_(stream);
stream.sphere = function() {
stream.polygonStart();
var epsilon = 1e-2,
ring = circle.radius(90 - epsilon)().coordinates[0],
n = ring.length - 1,
i = -1,
p;
stream.lineStart();
while (++i < n) stream.point((p = ring[i])[0], p[1]);
stream.lineEnd();
ring = circle.radius(90 + epsilon)().coordinates[0];
n = ring.length - 1;
stream.lineStart();
while (--i >= 0) stream.point((p = ring[i])[0], p[1]);
stream.lineEnd();
stream.polygonEnd();
};
return stream;
};
return p
.scale(79.4187)
.parallel(45)
.clipAngle(180 - 1e-3);
}