|
1 d3.geo.greatArc = function() { |
|
2 var source = d3_geo_greatArcSource, |
|
3 target = d3_geo_greatArcTarget, |
|
4 precision = 6 * d3_geo_radians; |
|
5 |
|
6 function greatArc() { |
|
7 var a = typeof source === "function" ? source.apply(this, arguments) : source, |
|
8 b = typeof target === "function" ? target.apply(this, arguments) : target, |
|
9 i = d3_geo_greatArcInterpolate(a, b), |
|
10 dt = precision / i.d, |
|
11 t = 0, |
|
12 coordinates = [a]; |
|
13 while ((t += dt) < 1) coordinates.push(i(t)); |
|
14 coordinates.push(b); |
|
15 return { |
|
16 type: "LineString", |
|
17 coordinates: coordinates |
|
18 }; |
|
19 } |
|
20 |
|
21 // Length returned in radians; multiply by radius for distance. |
|
22 greatArc.distance = function() { |
|
23 var a = typeof source === "function" ? source.apply(this, arguments) : source, |
|
24 b = typeof target === "function" ? target.apply(this, arguments) : target; |
|
25 return d3_geo_greatArcInterpolate(a, b).d; |
|
26 }; |
|
27 |
|
28 greatArc.source = function(x) { |
|
29 if (!arguments.length) return source; |
|
30 source = x; |
|
31 return greatArc; |
|
32 }; |
|
33 |
|
34 greatArc.target = function(x) { |
|
35 if (!arguments.length) return target; |
|
36 target = x; |
|
37 return greatArc; |
|
38 }; |
|
39 |
|
40 // Precision is specified in degrees. |
|
41 greatArc.precision = function(x) { |
|
42 if (!arguments.length) return precision / d3_geo_radians; |
|
43 precision = x * d3_geo_radians; |
|
44 return greatArc; |
|
45 }; |
|
46 |
|
47 return greatArc; |
|
48 }; |
|
49 |
|
50 function d3_geo_greatArcSource(d) { |
|
51 return d.source; |
|
52 } |
|
53 |
|
54 function d3_geo_greatArcTarget(d) { |
|
55 return d.target; |
|
56 } |
|
57 |
|
58 function d3_geo_greatArcInterpolate(a, b) { |
|
59 var x0 = a[0] * d3_geo_radians, cx0 = Math.cos(x0), sx0 = Math.sin(x0), |
|
60 y0 = a[1] * d3_geo_radians, cy0 = Math.cos(y0), sy0 = Math.sin(y0), |
|
61 x1 = b[0] * d3_geo_radians, cx1 = Math.cos(x1), sx1 = Math.sin(x1), |
|
62 y1 = b[1] * d3_geo_radians, cy1 = Math.cos(y1), sy1 = Math.sin(y1), |
|
63 d = interpolate.d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))), |
|
64 sd = Math.sin(d); |
|
65 |
|
66 // From http://williams.best.vwh.net/avform.htm#Intermediate |
|
67 function interpolate(t) { |
|
68 var A = Math.sin(d - (t *= d)) / sd, |
|
69 B = Math.sin(t) / sd, |
|
70 x = A * cy0 * cx0 + B * cy1 * cx1, |
|
71 y = A * cy0 * sx0 + B * cy1 * sx1, |
|
72 z = A * sy0 + B * sy1; |
|
73 return [ |
|
74 Math.atan2(y, x) / d3_geo_radians, |
|
75 Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_geo_radians |
|
76 ]; |
|
77 } |
|
78 |
|
79 return interpolate; |
|
80 } |