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
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]); |
|
} |
|
}
|
|
|