Skip to content

Commit 6b06c45

Browse files
committed
Deprecate d3.geo.greatArc; add d3.geo.distance.
Now that D3 supports great-arc interpolation automatically for projections, there is no need for a great arc feature generator, as a simple LineString geometry object is equivalent. For the same reason, d3.geo.graticule does not need to use supersampling on meridians, since meridians are great arcs. This commit also adds d3.geo.distance(a, b) for computing the length of the great arc between points a and b in radians, as a replacement for the deprecated d3.geo.greatArc method, and a faster alternative to constructing a d3.geo.interpolate solely to measure distance. Fixes d3#1021 d3#1024.
1 parent 2145cc6 commit 6b06c45

12 files changed

Lines changed: 73 additions & 75 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ d3.geo.js: \
183183
src/geo/stream.js \
184184
src/geo/spherical.js \
185185
src/geo/cartesian.js \
186+
src/geo/distance.js \
186187
src/geo/resample.js \
187188
src/geo/albers-usa.js \
188189
src/geo/albers.js \

d3.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
function d3_source(d) {
2222
return d.source;
2323
}
24+
function d3_acos(x) {
25+
return Math.acos(Math.max(-1, Math.min(1, x)));
26+
}
2427
function d3_class(ctor, properties) {
2528
try {
2629
for (var key in properties) {
@@ -5418,6 +5421,10 @@
54185421
d[1] /= l;
54195422
d[2] /= l;
54205423
}
5424+
d3.geo.distance = function(a, b) {
5425+
var λ0 = a[0] * d3_radians, φ0 = a[1] * d3_radians, λ1 = b[0] * d3_radians, φ1 = b[1] * d3_radians;
5426+
return d3_acos(Math.sin(φ0) * Math.sin(φ1) + Math.cos(φ0) * Math.cos(φ1) * Math.cos(λ1 - λ0));
5427+
};
54215428
function d3_geo_resample(project) {
54225429
var δ2 = .5, maxDepth = 16;
54235430
function resample(stream) {
@@ -5715,7 +5722,7 @@
57155722
var a = d3_geo_cartesian(point);
57165723
a[0] -= cr;
57175724
d3_geo_cartesianNormalize(a);
5718-
var angle = Math.acos(Math.max(-1, Math.min(1, -a[1])));
5725+
var angle = d3_acos(-a[1]);
57195726
return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
57205727
}
57215728
function d3_geo_clip(pointVisible, clipLine, interpolate) {
@@ -6149,9 +6156,9 @@
61496156
graticule.precision = function(_) {
61506157
if (!arguments.length) return precision;
61516158
precision = +_;
6152-
x = d3_geo_graticuleX(y0, y1, precision);
6159+
x = d3_geo_graticuleX(y0, y1, 90);
61536160
y = d3_geo_graticuleY(x0, x1, precision);
6154-
X = d3_geo_graticuleX(Y0, Y1, precision);
6161+
X = d3_geo_graticuleX(Y0, Y1, 90);
61556162
Y = d3_geo_graticuleY(X0, X1, precision);
61566163
return graticule;
61576164
};
@@ -6177,7 +6184,7 @@
61776184
return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);
61786185
};
61796186
function d3_geo_interpolate(x0, y0, x1, y1) {
6180-
var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))), k = 1 / Math.sin(d);
6187+
var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = d3_acos(sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)), k = 1 / Math.sin(d);
61816188
function interpolate(t) {
61826189
var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;
61836190
return [ Math.atan2(y, x) / d3_radians, Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_radians ];
@@ -6186,35 +6193,28 @@
61866193
return interpolate;
61876194
}
61886195
d3.geo.greatArc = function() {
6189-
var source = d3_source, source_, target = d3_target, target_, precision = 6 * d3_radians, interpolate;
6196+
var source = d3_source, source_, target = d3_target, target_;
61906197
function greatArc() {
6191-
var p0 = source_ || source.apply(this, arguments), p1 = target_ || target.apply(this, arguments), i = interpolate || d3.geo.interpolate(p0, p1), t = 0, dt = precision / i.distance, coordinates = [ p0 ];
6192-
while ((t += dt) < 1) coordinates.push(i(t));
6193-
coordinates.push(p1);
61946198
return {
61956199
type: "LineString",
6196-
coordinates: coordinates
6200+
coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ]
61976201
};
61986202
}
61996203
greatArc.distance = function() {
6200-
return (interpolate || d3.geo.interpolate(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments))).distance;
6204+
return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments));
62016205
};
62026206
greatArc.source = function(_) {
62036207
if (!arguments.length) return source;
62046208
source = _, source_ = typeof _ === "function" ? null : _;
6205-
interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
62066209
return greatArc;
62076210
};
62086211
greatArc.target = function(_) {
62096212
if (!arguments.length) return target;
62106213
target = _, target_ = typeof _ === "function" ? null : _;
6211-
interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
62126214
return greatArc;
62136215
};
6214-
greatArc.precision = function(_) {
6215-
if (!arguments.length) return precision / d3_radians;
6216-
precision = _ * d3_radians;
6217-
return greatArc;
6216+
greatArc.precision = function() {
6217+
return arguments.length ? greatArc : 0;
62186218
};
62196219
return greatArc;
62206220
};

d3.min.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/core.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ function d3_target(d) {
1212
function d3_source(d) {
1313
return d.source;
1414
}
15+
16+
function d3_acos(x) {
17+
return Math.acos(Math.max(-1, Math.min(1, x)));
18+
}

src/geo/circle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,6 @@ function d3_geo_circleAngle(cr, point) {
7070
var a = d3_geo_cartesian(point);
7171
a[0] -= cr;
7272
d3_geo_cartesianNormalize(a);
73-
var angle = Math.acos(Math.max(-1, Math.min(1, -a[1])));
73+
var angle = d3_acos(-a[1]);
7474
return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
7575
}

src/geo/distance.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Length returned in radians; multiply by radius for distance.
2+
d3.geo.distance = function(a, b) {
3+
var λ0 = a[0] * d3_radians, φ0 = a[1] * d3_radians,
4+
λ1 = b[0] * d3_radians, φ1 = b[1] * d3_radians;
5+
return d3_acos(Math.sin(φ0) * Math.sin(φ1) + Math.cos(φ0) * Math.cos(φ1) * Math.cos(λ1 - λ0));
6+
};

src/geo/graticule.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ d3.geo.graticule = function() {
7575
graticule.precision = function(_) {
7676
if (!arguments.length) return precision;
7777
precision = +_;
78-
x = d3_geo_graticuleX(y0, y1, precision);
78+
x = d3_geo_graticuleX(y0, y1, 90);
7979
y = d3_geo_graticuleY(x0, x1, precision);
80-
X = d3_geo_graticuleX(Y0, Y1, precision);
80+
X = d3_geo_graticuleX(Y0, Y1, 90);
8181
Y = d3_geo_graticuleY(X0, X1, precision);
8282
return graticule;
8383
};

src/geo/greatArc.js

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,36 @@
1+
// @deprecated use {type: "LineString"} or d3.geo.distance instead.
12
d3.geo.greatArc = function() {
23
var source = d3_source, source_,
3-
target = d3_target, target_,
4-
precision = 6 * d3_radians,
5-
interpolate;
4+
target = d3_target, target_;
65

76
function greatArc() {
8-
var p0 = source_ || source.apply(this, arguments),
9-
p1 = target_ || target.apply(this, arguments),
10-
i = interpolate || d3.geo.interpolate(p0, p1),
11-
t = 0,
12-
dt = precision / i.distance,
13-
coordinates = [p0];
14-
while ((t += dt) < 1) coordinates.push(i(t));
15-
coordinates.push(p1);
16-
return {type: "LineString", coordinates: coordinates};
7+
return {type: "LineString", coordinates: [
8+
source_ || source.apply(this, arguments),
9+
target_ || target.apply(this, arguments)
10+
]};
1711
}
1812

19-
// Length returned in radians; multiply by radius for distance.
2013
greatArc.distance = function() {
21-
return (interpolate || d3.geo.interpolate(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments))).distance;
14+
return d3.geo.distance(
15+
source_ || source.apply(this, arguments),
16+
target_ || target.apply(this, arguments)
17+
);
2218
};
2319

2420
greatArc.source = function(_) {
2521
if (!arguments.length) return source;
2622
source = _, source_ = typeof _ === "function" ? null : _;
27-
interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
2823
return greatArc;
2924
};
3025

3126
greatArc.target = function(_) {
3227
if (!arguments.length) return target;
3328
target = _, target_ = typeof _ === "function" ? null : _;
34-
interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
3529
return greatArc;
3630
};
3731

38-
// Precision is specified in degrees.
39-
greatArc.precision = function(_) {
40-
if (!arguments.length) return precision / d3_radians;
41-
precision = _ * d3_radians;
42-
return greatArc;
32+
greatArc.precision = function() {
33+
return arguments.length ? greatArc : 0;
4334
};
4435

4536
return greatArc;

src/geo/interpolate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function d3_geo_interpolate(x0, y0, x1, y1) {
1414
ky0 = cy0 * Math.sin(x0),
1515
kx1 = cy1 * Math.cos(x1),
1616
ky1 = cy1 * Math.sin(x1),
17-
d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))),
17+
d = d3_acos(sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)),
1818
k = 1 / Math.sin(d);
1919

2020
function interpolate(t) {

test/geo/distance-test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require("../env");
2+
3+
var vows = require("vows"),
4+
assert = require("assert");
5+
6+
var suite = vows.describe("d3.geo.distance");
7+
8+
suite.addBatch({
9+
"distance": {
10+
"computes the great-arc distance": function() {
11+
assert.equal(d3.geo.distance([0, 0], [0, 0]), 0);
12+
assert.inDelta(d3.geo.distance([118 + 24 / 60, 33 + 57 / 60], [ 73 + 47 / 60, 40 + 38 / 60]), 3973 / 6371, .5);
13+
}
14+
}
15+
});
16+
17+
suite.export(module);

0 commit comments

Comments
 (0)