toolkit/javascript/d3/src/geo/greatArc.js
changeset 47 c0b4a8b5a012
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolkit/javascript/d3/src/geo/greatArc.js	Thu Apr 10 14:20:23 2014 +0200
@@ -0,0 +1,80 @@
+d3.geo.greatArc = function() {
+  var source = d3_geo_greatArcSource,
+      target = d3_geo_greatArcTarget,
+      precision = 6 * d3_geo_radians;
+
+  function greatArc() {
+    var a = typeof source === "function" ? source.apply(this, arguments) : source,
+        b = typeof target === "function" ? target.apply(this, arguments) : target,
+        i = d3_geo_greatArcInterpolate(a, b),
+        dt = precision / i.d,
+        t = 0,
+        coordinates = [a];
+    while ((t += dt) < 1) coordinates.push(i(t));
+    coordinates.push(b);
+    return {
+      type: "LineString",
+      coordinates: coordinates
+    };
+  }
+
+  // Length returned in radians; multiply by radius for distance.
+  greatArc.distance = function() {
+    var a = typeof source === "function" ? source.apply(this, arguments) : source,
+        b = typeof target === "function" ? target.apply(this, arguments) : target;
+     return d3_geo_greatArcInterpolate(a, b).d;
+  };
+
+  greatArc.source = function(x) {
+    if (!arguments.length) return source;
+    source = x;
+    return greatArc;
+  };
+
+  greatArc.target = function(x) {
+    if (!arguments.length) return target;
+    target = x;
+    return greatArc;
+  };
+
+  // Precision is specified in degrees.
+  greatArc.precision = function(x) {
+    if (!arguments.length) return precision / d3_geo_radians;
+    precision = x * d3_geo_radians;
+    return greatArc;
+  };
+
+  return greatArc;
+};
+
+function d3_geo_greatArcSource(d) {
+  return d.source;
+}
+
+function d3_geo_greatArcTarget(d) {
+  return d.target;
+}
+
+function d3_geo_greatArcInterpolate(a, b) {
+  var x0 = a[0] * d3_geo_radians, cx0 = Math.cos(x0), sx0 = Math.sin(x0),
+      y0 = a[1] * d3_geo_radians, cy0 = Math.cos(y0), sy0 = Math.sin(y0),
+      x1 = b[0] * d3_geo_radians, cx1 = Math.cos(x1), sx1 = Math.sin(x1),
+      y1 = b[1] * d3_geo_radians, cy1 = Math.cos(y1), sy1 = Math.sin(y1),
+      d = interpolate.d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))),
+      sd = Math.sin(d);
+
+  // From http://williams.best.vwh.net/avform.htm#Intermediate
+  function interpolate(t) {
+    var A = Math.sin(d - (t *= d)) / sd,
+        B = Math.sin(t) / sd,
+        x = A * cy0 * cx0 + B * cy1 * cx1,
+        y = A * cy0 * sx0 + B * cy1 * sx1,
+        z = A * sy0       + B * sy1;
+    return [
+      Math.atan2(y, x) / d3_geo_radians,
+      Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_geo_radians
+    ];
+  }
+
+  return interpolate;
+}