From 15dda93e3b0ce91fd294a09b0a194b07403a9fff Mon Sep 17 00:00:00 2001 From: Jason Davies Date: Mon, 12 Sep 2011 17:23:32 +0100 Subject: [PATCH] Reinstate d3.geo.greatCircle.polyline. For backwards compatibility. --- d3.geo.js | 52 +++++++++++++++---------------- d3.geo.min.js | 2 +- examples/azimuthal/azimuthal.html | 2 +- examples/azimuthal/azimuthal.js | 2 +- src/geo/clip.js | 4 +-- src/geo/greatCircle.js | 48 ++++++++++++++-------------- test/geo/greatCircle-test.js | 12 +++---- 7 files changed, 61 insertions(+), 61 deletions(-) diff --git a/d3.geo.js b/d3.geo.js index 5cb4b3bbfb839..e03cc67467e44 100644 --- a/d3.geo.js +++ b/d3.geo.js @@ -622,15 +622,22 @@ function d3_geo_boundsPolygon(o, f) { } // From http://williams.best.vwh.net/avform.htm#Intermediate d3.geo.greatCircle = function() { - var coordinates = Object, + var source = d3_geo_greatCircleSource, + target = d3_geo_greatCircleTarget, + coordinates = Object, // for use with polyline precision = 1, radius = d3_geo_earthRadius; // TODO: breakAtDateLine? function greatCircle(d, i) { - return d3_geo_greatCirclePath(coordinates.call(this, d, i), precision); + return d3_geo_greatCirclePath([ + source.call(this, d, i), target.call(this, d, i)], precision); } + greatCircle.polyline = function(d, i) { + return d3_geo_greatCirclePath(coordinates.call(this, d, i), precision); + }; + greatCircle.coordinates = function(x) { if (!arguments.length) return coordinates; coordinates = x; @@ -651,29 +658,16 @@ d3.geo.greatCircle = function() { // Haversine formula for great-circle distance. greatCircle.distance = function(d, i) { - d = coordinates.call(this, d, i); - if (d.length < 2) return NaN; - - var from = d[0], - to, + var from = source.call(this, d, i), + to = target.call(this, d, i), x0 = from[0] * d3_radians, y0 = from[1] * d3_radians, - n = d.length, - i = 0, - s = 0; - - while (++i < n) { - to = d[i]; - var x1 = to[0] * d3_radians, - y1 = to[1] * d3_radians, - sy = Math.sin((y1 - y0) / 2), - sx = Math.sin((x1 - x0) / 2), - a = sy * sy + Math.cos(y0) * Math.cos(y1) * sx * sx; - x0 = x1; - y0 = y1; - s += radius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - } - return s; + x1 = to[0] * d3_radians, + y1 = to[1] * d3_radians, + sy = Math.sin((y1 - y0) / 2), + sx = Math.sin((x1 - x0) / 2), + a = sy * sy + Math.cos(y0) * Math.cos(y1) * sx * sx; + return radius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); }; return greatCircle; @@ -727,6 +721,14 @@ function d3_geo_greatCirclePath(coordinates, precision) { return path; } + +function d3_geo_greatCircleSource(d) { + return d.source; +} + +function d3_geo_greatCircleTarget(d) { + return d.target; +} d3.geo.clip = function() { var origin = [0, 0], angle = 90, @@ -790,9 +792,7 @@ d3.geo.clip = function() { return clip; } -var d3_geo_clipGreatCircle = d3.geo.greatCircle().coordinates(function(d) { - return [d.source, d.target]; -}); +var d3_geo_clipGreatCircle = d3.geo.greatCircle(); function d3_geo_clipIntersect(from, to, f) { var x0 = from[0] * d3_radians, diff --git a/d3.geo.min.js b/d3.geo.min.js index 2b9062607f867..17aa763d926ca 100644 --- a/d3.geo.min.js +++ b/d3.geo.min.js @@ -1 +1 @@ -(function(){function q(b,c,d){var e=b[0]*a,f=b[1]*a,g=c[0]*a,h=c[1]*a,i=Math.cos(e),j=Math.sin(e),k=Math.cos(f),l=Math.sin(f),m=Math.cos(g),n=Math.sin(g),o=Math.cos(h),p=Math.sin(h),q=Math.acos(Math.max(-1,Math.min(1,l*p+k*o*Math.cos(g-e)))),r=d*q,s=Math.sin(q),t=Math.sin(q-r)/s,u=Math.sin(r)/s,v=t*k*i+u*o*m,w=t*k*j+u*o*n,x=t*l+u*p;return[Math.atan2(w,v)/a,Math.atan2(x,Math.sqrt(v*v+w*w))/a]}function o(b,c){var d=b.length;if(d<2)return b;var e=0,f=c*a,g=b[0],h,i=g[0]*a,j=g[1]*a,k=Math.cos(i),l=Math.sin(i),m=Math.cos(j),n=Math.sin(j),o=[g];while(++e50?b:f<-140?c:g<21?d:a)(e)}var a=d3.geo.albers(),b=d3.geo.albers().origin([-160,60]).parallels([55,65]),c=d3.geo.albers().origin([-160,20]).parallels([8,18]),d=d3.geo.albers().origin([-60,10]).parallels([8,18]);e.scale=function(f){if(!arguments.length)return a.scale();a.scale(f),b.scale(f*.6),c.scale(f),d.scale(f*1.5);return e.translate(a.translate())},e.translate=function(f){if(!arguments.length)return a.translate();var g=a.scale()/1e3,h=f[0],i=f[1];a.translate(f),b.translate([h-400*g,i+170*g]),c.translate([h-190*g,i+200*g]),d.translate([h+580*g,i+430*g]);return e};return e.scale(a.scale())},d3.geo.mercator=function(){function d(d){var e=d[0]/360,f=-(Math.log(Math.tan(Math.PI/4+d[1]*a/2))/a)/360;return[b*e+c[0],b*Math.max(-0.5,Math.min(.5,f))+c[1]]}var b=500,c=[480,250];d.invert=function(d){var e=(d[0]-c[0])/b,f=(d[1]-c[1])/b;return[360*e,2*Math.atan(Math.exp(-360*f*a))/a-90]},d.scale=function(a){if(!arguments.length)return b;b=+a;return d},d.translate=function(a){if(!arguments.length)return c;c=[+a[0],+a[1]];return d};return d},d3.geo.path=function(){function o(a){return Math.abs(d3.geom.polygon(a.map(f)).area())}function m(a){var b=d3.geom.polygon(a[0].map(f)),c=b.centroid(1),d=c[0],e=c[1],g=Math.abs(b.area()),h=0,i=a.length;while(++hd&&(d=a),fe&&(e=f)});return[[b,c],[d,e]]};var g={Feature:h,FeatureCollection:i,LineString:j,MultiLineString:k,MultiPoint:j,MultiPolygon:l,Point:m,Polygon:n};d3.geo.greatCircle=function(){function f(a,b){return o(c.call(this,a,b),d)}var c=Object,d=1,e=b;f.coordinates=function(a){if(!arguments.length)return c;c=a;return f},f.precision=function(a){if(!arguments.length)return d;d=+a;return f},f.radius=function(a){if(!arguments.length)return e;e=+a;return f},f.distance=function(b,d){b=c.call(this,b,d);if(b.length<2)return NaN;var f=b[0],g,h=f[0]*a,i=f[1]*a,j=b.length,d=0,k=0;while(++d50?b:f<-140?c:g<21?d:a)(e)}var a=d3.geo.albers(),b=d3.geo.albers().origin([-160,60]).parallels([55,65]),c=d3.geo.albers().origin([-160,20]).parallels([8,18]),d=d3.geo.albers().origin([-60,10]).parallels([8,18]);e.scale=function(f){if(!arguments.length)return a.scale();a.scale(f),b.scale(f*.6),c.scale(f),d.scale(f*1.5);return e.translate(a.translate())},e.translate=function(f){if(!arguments.length)return a.translate();var g=a.scale()/1e3,h=f[0],i=f[1];a.translate(f),b.translate([h-400*g,i+170*g]),c.translate([h-190*g,i+200*g]),d.translate([h+580*g,i+430*g]);return e};return e.scale(a.scale())},d3.geo.mercator=function(){function d(d){var e=d[0]/360,f=-(Math.log(Math.tan(Math.PI/4+d[1]*a/2))/a)/360;return[b*e+c[0],b*Math.max(-0.5,Math.min(.5,f))+c[1]]}var b=500,c=[480,250];d.invert=function(d){var e=(d[0]-c[0])/b,f=(d[1]-c[1])/b;return[360*e,2*Math.atan(Math.exp(-360*f*a))/a-90]},d.scale=function(a){if(!arguments.length)return b;b=+a;return d},d.translate=function(a){if(!arguments.length)return c;c=[+a[0],+a[1]];return d};return d},d3.geo.path=function(){function o(a){return Math.abs(d3.geom.polygon(a.map(f)).area())}function m(a){var b=d3.geom.polygon(a[0].map(f)),c=b.centroid(1),d=c[0],e=c[1],g=Math.abs(b.area()),h=0,i=a.length;while(++hd&&(d=a),fe&&(e=f)});return[[b,c],[d,e]]};var g={Feature:h,FeatureCollection:i,LineString:j,MultiLineString:k,MultiPoint:j,MultiPolygon:l,Point:m,Polygon:n};d3.geo.greatCircle=function(){function h(a,b){return o([c.call(this,a,b),d.call(this,a,b)],f)}var c=p,d=q,e=Object,f=1,g=b;h.polyline=function(a,b){return o(e.call(this,a,b),f)},h.coordinates=function(a){if(!arguments.length)return e;e=a;return h},h.precision=function(a){if(!arguments.length)return f;f=+a;return h},h.radius=function(a){if(!arguments.length)return g;g=+a;return h},h.distance=function(b,e){var f=c.call(this,b,e),h=d.call(this,b,e),i=f[0]*a,j=f[1]*a,k=h[0]*a,l=h[1]*a,m=Math.sin((l-j)/2),n=Math.sin((k-i)/2),o=m*m+Math.cos(j)*Math.cos(l)*n*n;return g*2*Math.atan2(Math.sqrt(o),Math.sqrt(1-o))};return h},d3.geo.clip=function(){function f(b,c){var b=e.call(this,b,c),f={source:a,target:null},g=b.length,c=-1,h,i=[],j=null,k=null,l,m;while(++cAzimuthal Projection $("#mode").change(function() { var mode = $(this).val(); xy.mode(mode); - path.clip(mode === "gnomonic" ? clip : circle); + path.clip(mode === "gnomonic" ? clip : circle.polyline); refresh(500); }); diff --git a/examples/azimuthal/azimuthal.js b/examples/azimuthal/azimuthal.js index 0221983eff873..b8013749284a2 100644 --- a/examples/azimuthal/azimuthal.js +++ b/examples/azimuthal/azimuthal.js @@ -1,7 +1,7 @@ var xy = d3.geo.azimuthal().scale(240).mode("stereographic"), clip = d3.geo.clip().angle(89), circle = d3.geo.greatCircle().precision(10).coordinates(clip), - path = d3.geo.path().projection(xy).clip(circle), + path = d3.geo.path().projection(xy).clip(circle.polyline), svg = d3.select("body").append("svg:svg"); d3.json("../data/world-countries.json", function(collection) { diff --git a/src/geo/clip.js b/src/geo/clip.js index dc932bbcc31c7..a2f96e7a65769 100644 --- a/src/geo/clip.js +++ b/src/geo/clip.js @@ -61,9 +61,7 @@ d3.geo.clip = function() { return clip; } -var d3_geo_clipGreatCircle = d3.geo.greatCircle().coordinates(function(d) { - return [d.source, d.target]; -}); +var d3_geo_clipGreatCircle = d3.geo.greatCircle(); function d3_geo_clipIntersect(from, to, f) { var x0 = from[0] * d3_radians, diff --git a/src/geo/greatCircle.js b/src/geo/greatCircle.js index 2423de91aefc1..4c5dffbd1bd6a 100644 --- a/src/geo/greatCircle.js +++ b/src/geo/greatCircle.js @@ -1,14 +1,21 @@ // From http://williams.best.vwh.net/avform.htm#Intermediate d3.geo.greatCircle = function() { - var coordinates = Object, + var source = d3_geo_greatCircleSource, + target = d3_geo_greatCircleTarget, + coordinates = Object, // for use with polyline precision = 1, radius = d3_geo_earthRadius; // TODO: breakAtDateLine? function greatCircle(d, i) { - return d3_geo_greatCirclePath(coordinates.call(this, d, i), precision); + return d3_geo_greatCirclePath([ + source.call(this, d, i), target.call(this, d, i)], precision); } + greatCircle.polyline = function(d, i) { + return d3_geo_greatCirclePath(coordinates.call(this, d, i), precision); + }; + greatCircle.coordinates = function(x) { if (!arguments.length) return coordinates; coordinates = x; @@ -29,29 +36,16 @@ d3.geo.greatCircle = function() { // Haversine formula for great-circle distance. greatCircle.distance = function(d, i) { - d = coordinates.call(this, d, i); - if (d.length < 2) return NaN; - - var from = d[0], - to, + var from = source.call(this, d, i), + to = target.call(this, d, i), x0 = from[0] * d3_radians, y0 = from[1] * d3_radians, - n = d.length, - i = 0, - s = 0; - - while (++i < n) { - to = d[i]; - var x1 = to[0] * d3_radians, - y1 = to[1] * d3_radians, - sy = Math.sin((y1 - y0) / 2), - sx = Math.sin((x1 - x0) / 2), - a = sy * sy + Math.cos(y0) * Math.cos(y1) * sx * sx; - x0 = x1; - y0 = y1; - s += radius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - } - return s; + x1 = to[0] * d3_radians, + y1 = to[1] * d3_radians, + sy = Math.sin((y1 - y0) / 2), + sx = Math.sin((x1 - x0) / 2), + a = sy * sy + Math.cos(y0) * Math.cos(y1) * sx * sx; + return radius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); }; return greatCircle; @@ -105,3 +99,11 @@ function d3_geo_greatCirclePath(coordinates, precision) { return path; } + +function d3_geo_greatCircleSource(d) { + return d.source; +} + +function d3_geo_greatCircleTarget(d) { + return d.target; +} diff --git a/test/geo/greatCircle-test.js b/test/geo/greatCircle-test.js index 9c0b084cb90ac..24c41f085bc55 100644 --- a/test/geo/greatCircle-test.js +++ b/test/geo/greatCircle-test.js @@ -13,14 +13,14 @@ suite.addBatch({ return d3.geo.greatCircle().precision(7.5); }, "distance": function(circle) { - assert.equal(circle.distance([[0, 0], [0, 0]]), 0); - assert.inDelta(circle.distance([ - [118 + 24 / 60, 33 + 57 / 60], - [ 73 + 47 / 60, 40 + 38 / 60] - ]), 3973, .5); + assert.equal(circle.distance({source: [0, 0], target: [0, 0]}), 0); + assert.inDelta(circle.distance({ + source: [118 + 24 / 60, 33 + 57 / 60], + target: [ 73 + 47 / 60, 40 + 38 / 60] + }), 3973, .5); }, "geodesic": function(circle) { - assert.inDelta(circle([[5, 52], [-120, 37]]), [ + assert.inDelta(circle.polyline([[5, 52], [-120, 37]]), [ [ 5, 52 ], [ -3.805036, 57.05083], [ -15.122869, 61.30118],