| import {cartesian, cartesianAddInPlace, cartesianCross, cartesianDot, cartesianScale, spherical} from "../cartesian.js"; |
| import {circleStream} from "../circle.js"; |
| import {abs, cos, epsilon, pi, radians, sqrt} from "../math.js"; |
| import pointEqual from "../pointEqual.js"; |
| import clip from "./index.js"; |
|
|
| export default function(radius) { |
| var cr = cos(radius), |
| delta = 2 * radians, |
| smallRadius = cr > 0, |
| notHemisphere = abs(cr) > epsilon; |
|
|
| function interpolate(from, to, direction, stream) { |
| circleStream(stream, radius, delta, direction, from, to); |
| } |
|
|
| function visible(lambda, phi) { |
| return cos(lambda) * cos(phi) > cr; |
| } |
|
|
| |
| |
| |
| |
| function clipLine(stream) { |
| var point0, |
| c0, |
| v0, |
| v00, |
| clean; |
| return { |
| lineStart: function() { |
| v00 = v0 = false; |
| clean = 1; |
| }, |
| point: function(lambda, phi) { |
| var point1 = [lambda, phi], |
| point2, |
| v = visible(lambda, phi), |
| c = smallRadius |
| ? v ? 0 : code(lambda, phi) |
| : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0; |
| if (!point0 && (v00 = v0 = v)) stream.lineStart(); |
| if (v !== v0) { |
| point2 = intersect(point0, point1); |
| if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) |
| point1[2] = 1; |
| } |
| if (v !== v0) { |
| clean = 0; |
| if (v) { |
| |
| stream.lineStart(); |
| point2 = intersect(point1, point0); |
| stream.point(point2[0], point2[1]); |
| } else { |
| |
| point2 = intersect(point0, point1); |
| stream.point(point2[0], point2[1], 2); |
| stream.lineEnd(); |
| } |
| point0 = point2; |
| } else if (notHemisphere && point0 && smallRadius ^ v) { |
| var t; |
| |
| |
| if (!(c & c0) && (t = intersect(point1, point0, true))) { |
| clean = 0; |
| if (smallRadius) { |
| stream.lineStart(); |
| stream.point(t[0][0], t[0][1]); |
| stream.point(t[1][0], t[1][1]); |
| stream.lineEnd(); |
| } else { |
| stream.point(t[1][0], t[1][1]); |
| stream.lineEnd(); |
| stream.lineStart(); |
| stream.point(t[0][0], t[0][1], 3); |
| } |
| } |
| } |
| if (v && (!point0 || !pointEqual(point0, point1))) { |
| stream.point(point1[0], point1[1]); |
| } |
| point0 = point1, v0 = v, c0 = c; |
| }, |
| lineEnd: function() { |
| if (v0) stream.lineEnd(); |
| point0 = null; |
| }, |
| |
| |
| clean: function() { |
| return clean | ((v00 && v0) << 1); |
| } |
| }; |
| } |
|
|
| |
| function intersect(a, b, two) { |
| var pa = cartesian(a), |
| pb = cartesian(b); |
|
|
| |
| |
| var n1 = [1, 0, 0], |
| n2 = cartesianCross(pa, pb), |
| n2n2 = cartesianDot(n2, n2), |
| n1n2 = n2[0], |
| determinant = n2n2 - n1n2 * n1n2; |
|
|
| |
| if (!determinant) return !two && a; |
|
|
| var c1 = cr * n2n2 / determinant, |
| c2 = -cr * n1n2 / determinant, |
| n1xn2 = cartesianCross(n1, n2), |
| A = cartesianScale(n1, c1), |
| B = cartesianScale(n2, c2); |
| cartesianAddInPlace(A, B); |
|
|
| |
| var u = n1xn2, |
| w = cartesianDot(A, u), |
| uu = cartesianDot(u, u), |
| t2 = w * w - uu * (cartesianDot(A, A) - 1); |
|
|
| if (t2 < 0) return; |
|
|
| var t = sqrt(t2), |
| q = cartesianScale(u, (-w - t) / uu); |
| cartesianAddInPlace(q, A); |
| q = spherical(q); |
|
|
| if (!two) return q; |
|
|
| |
| var lambda0 = a[0], |
| lambda1 = b[0], |
| phi0 = a[1], |
| phi1 = b[1], |
| z; |
|
|
| if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z; |
|
|
| var delta = lambda1 - lambda0, |
| polar = abs(delta - pi) < epsilon, |
| meridian = polar || delta < epsilon; |
|
|
| if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; |
|
|
| |
| if (meridian |
| ? polar |
| ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon ? phi0 : phi1) |
| : phi0 <= q[1] && q[1] <= phi1 |
| : delta > pi ^ (lambda0 <= q[0] && q[0] <= lambda1)) { |
| var q1 = cartesianScale(u, (-w + t) / uu); |
| cartesianAddInPlace(q1, A); |
| return [q, spherical(q1)]; |
| } |
| } |
|
|
| |
| |
| function code(lambda, phi) { |
| var r = smallRadius ? radius : pi - radius, |
| code = 0; |
| if (lambda < -r) code |= 1; |
| else if (lambda > r) code |= 2; |
| if (phi < -r) code |= 4; |
| else if (phi > r) code |= 8; |
| return code; |
| } |
|
|
| return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]); |
| } |
|
|