You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

92 lines
2.8 KiB

import clip from "./index";
import {abs, atan, cos, epsilon, halfPi, pi, sin} from "../math";
export default clip(
function() { return true; },
clipAntimeridianLine,
clipAntimeridianInterpolate,
[-pi, -halfPi]
);
// 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 clipAntimeridianLine(stream) {
var lambda0 = NaN,
phi0 = NaN,
sign0 = NaN,
clean; // no intersections
return {
lineStart: function() {
stream.lineStart();
clean = 1;
},
point: function(lambda1, phi1) {
var sign1 = lambda1 > 0 ? pi : -pi,
delta = abs(lambda1 - lambda0);
if (abs(delta - pi) < epsilon) { // line crosses a pole
stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
stream.point(sign0, phi0);
stream.lineEnd();
stream.lineStart();
stream.point(sign1, phi0);
stream.point(lambda1, phi0);
clean = 0;
} else if (sign0 !== sign1 && delta >= pi) { // line crosses antimeridian
if (abs(lambda0 - sign0) < epsilon) lambda0 -= sign0 * epsilon; // handle degeneracies
if (abs(lambda1 - sign1) < epsilon) lambda1 -= sign1 * epsilon;
phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
stream.point(sign0, phi0);
stream.lineEnd();
stream.lineStart();
stream.point(sign1, phi0);
clean = 0;
}
stream.point(lambda0 = lambda1, phi0 = phi1);
sign0 = sign1;
},
lineEnd: function() {
stream.lineEnd();
lambda0 = phi0 = NaN;
},
clean: function() {
return 2 - clean; // if intersections, rejoin first and last segments
}
};
}
function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
var cosPhi0,
cosPhi1,
sinLambda0Lambda1 = sin(lambda0 - lambda1);
return abs(sinLambda0Lambda1) > epsilon
? atan((sin(phi0) * (cosPhi1 = cos(phi1)) * sin(lambda1)
- sin(phi1) * (cosPhi0 = cos(phi0)) * sin(lambda0))
/ (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
: (phi0 + phi1) / 2;
}
function clipAntimeridianInterpolate(from, to, direction, stream) {
var phi;
if (from == null) {
phi = direction * halfPi;
stream.point(-pi, phi);
stream.point(0, phi);
stream.point(pi, phi);
stream.point(pi, 0);
stream.point(pi, -phi);
stream.point(0, -phi);
stream.point(-pi, -phi);
stream.point(-pi, 0);
stream.point(-pi, phi);
} else if (abs(from[0] - to[0]) > epsilon) {
var lambda = from[0] < to[0] ? pi : -pi;
phi = direction * lambda / 2;
stream.point(-lambda, phi);
stream.point(0, phi);
stream.point(lambda, phi);
} else {
stream.point(to[0], to[1]);
}
}