d3-jsnext
Version:
d3, but futuristic
97 lines (91 loc) • 3.09 kB
JavaScript
import { π, ε, halfπ } from '../math/trigonometry';
import { abs } from '../math/abs';
import { d3_true } from '../core/true';
import { d3_geo_clip } from './clip';
var d3_geo_clipAntimeridian = d3_geo_clip(
d3_true,
d3_geo_clipAntimeridianLine,
d3_geo_clipAntimeridianInterpolate,
[-π, -π / 2]);
// Takes a line and cuts into visible segments. Return values:
// 0: there were intersections or the line was empty.
// 1: no intersections.
// 2: there were intersections, and the first and last segments should be
// rejoined.
function d3_geo_clipAntimeridianLine(listener) {
var λ0 = NaN,
φ0 = NaN,
sλ0 = NaN,
clean; // no intersections
return {
lineStart: function() {
listener.lineStart();
clean = 1;
},
point: function(λ1, φ1) {
var sλ1 = λ1 > 0 ? π : -π,
dλ = abs(λ1 - λ0);
if (abs(dλ - π) < ε) { // line crosses a pole
listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
listener.point(sλ0, φ0);
listener.lineEnd();
listener.lineStart();
listener.point(sλ1, φ0);
listener.point(λ1, φ0);
clean = 0;
} else if (sλ0 !== sλ1 && dλ >= π) { // line crosses antimeridian
// handle degeneracies
if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
listener.point(sλ0, φ0);
listener.lineEnd();
listener.lineStart();
listener.point(sλ1, φ0);
clean = 0;
}
listener.point(λ0 = λ1, φ0 = φ1);
sλ0 = sλ1;
},
lineEnd: function() {
listener.lineEnd();
λ0 = φ0 = NaN;
},
// if there are intersections, we always rejoin the first and last segments.
clean: function() { return 2 - clean; }
};
}
function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
var cosφ0,
cosφ1,
sinλ0_λ1 = Math.sin(λ0 - λ1);
return abs(sinλ0_λ1) > ε
? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1)
- Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0))
/ (cosφ0 * cosφ1 * sinλ0_λ1))
: (φ0 + φ1) / 2;
}
function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
var φ;
if (from == null) {
φ = direction * halfπ;
listener.point(-π, φ);
listener.point( 0, φ);
listener.point( π, φ);
listener.point( π, 0);
listener.point( π, -φ);
listener.point( 0, -φ);
listener.point(-π, -φ);
listener.point(-π, 0);
listener.point(-π, φ);
} else if (abs(from[0] - to[0]) > ε) {
var s = from[0] < to[0] ? π : -π;
φ = direction * s / 2;
listener.point(-s, φ);
listener.point( 0, φ);
listener.point( s, φ);
} else {
listener.point(to[0], to[1]);
}
}
export { d3_geo_clipAntimeridianInterpolate, d3_geo_clipAntimeridianIntersect, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridian };