UNPKG

@visx/vendor

Version:

vendored packages for visx

173 lines (163 loc) 6.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = _default; var _cartesian = require("../cartesian.js"); var _circle = require("../circle.js"); var _math = require("../math.js"); var _pointEqual = _interopRequireDefault(require("../pointEqual.js")); var _index = _interopRequireDefault(require("./index.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _default(radius) { var cr = (0, _math.cos)(radius), delta = 6 * _math.radians, smallRadius = cr > 0, notHemisphere = (0, _math.abs)(cr) > _math.epsilon; // TODO optimise for this common case function interpolate(from, to, direction, stream) { (0, _circle.circleStream)(stream, radius, delta, direction, from, to); } function visible(lambda, phi) { return (0, _math.cos)(lambda) * (0, _math.cos)(phi) > cr; } // Takes a line and cuts into visible segments. Return values used for polygon // clipping: 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 clipLine(stream) { var point0, // previous point c0, // code for previous point v0, // visibility of previous point v00, // visibility of first point clean; // no intersections 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 ? _math.pi : -_math.pi), phi) : 0; if (!point0 && (v00 = v0 = v)) stream.lineStart(); if (v !== v0) { point2 = intersect(point0, point1); if (!point2 || (0, _pointEqual.default)(point0, point2) || (0, _pointEqual.default)(point1, point2)) point1[2] = 1; } if (v !== v0) { clean = 0; if (v) { // outside going in stream.lineStart(); point2 = intersect(point1, point0); stream.point(point2[0], point2[1]); } else { // inside going out point2 = intersect(point0, point1); stream.point(point2[0], point2[1], 2); stream.lineEnd(); } point0 = point2; } else if (notHemisphere && point0 && smallRadius ^ v) { var t; // If the codes for two points are different, or are both zero, // and there this segment intersects with the small circle. 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 || !(0, _pointEqual.default)(point0, point1))) { stream.point(point1[0], point1[1]); } point0 = point1, v0 = v, c0 = c; }, lineEnd: function () { if (v0) stream.lineEnd(); point0 = null; }, // Rejoin first and last segments if there were intersections and the first // and last points were visible. clean: function () { return clean | (v00 && v0) << 1; } }; } // Intersects the great circle between a and b with the clip circle. function intersect(a, b, two) { var pa = (0, _cartesian.cartesian)(a), pb = (0, _cartesian.cartesian)(b); // We have two planes, n1.p = d1 and n2.p = d2. // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2). var n1 = [1, 0, 0], // normal n2 = (0, _cartesian.cartesianCross)(pa, pb), n2n2 = (0, _cartesian.cartesianDot)(n2, n2), n1n2 = n2[0], // cartesianDot(n1, n2), determinant = n2n2 - n1n2 * n1n2; // Two polar points. if (!determinant) return !two && a; var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = (0, _cartesian.cartesianCross)(n1, n2), A = (0, _cartesian.cartesianScale)(n1, c1), B = (0, _cartesian.cartesianScale)(n2, c2); (0, _cartesian.cartesianAddInPlace)(A, B); // Solve |p(t)|^2 = 1. var u = n1xn2, w = (0, _cartesian.cartesianDot)(A, u), uu = (0, _cartesian.cartesianDot)(u, u), t2 = w * w - uu * ((0, _cartesian.cartesianDot)(A, A) - 1); if (t2 < 0) return; var t = (0, _math.sqrt)(t2), q = (0, _cartesian.cartesianScale)(u, (-w - t) / uu); (0, _cartesian.cartesianAddInPlace)(q, A); q = (0, _cartesian.spherical)(q); if (!two) return q; // Two intersection points. 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 = (0, _math.abs)(delta - _math.pi) < _math.epsilon, meridian = polar || delta < _math.epsilon; if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; // Check that the first point is between a and b. if (meridian ? polar ? phi0 + phi1 > 0 ^ q[1] < ((0, _math.abs)(q[0] - lambda0) < _math.epsilon ? phi0 : phi1) : phi0 <= q[1] && q[1] <= phi1 : delta > _math.pi ^ (lambda0 <= q[0] && q[0] <= lambda1)) { var q1 = (0, _cartesian.cartesianScale)(u, (-w + t) / uu); (0, _cartesian.cartesianAddInPlace)(q1, A); return [q, (0, _cartesian.spherical)(q1)]; } } // Generates a 4-bit vector representing the location of a point relative to // the small circle's bounding box. function code(lambda, phi) { var r = smallRadius ? radius : _math.pi - radius, code = 0; if (lambda < -r) code |= 1; // left else if (lambda > r) code |= 2; // right if (phi < -r) code |= 4; // below else if (phi > r) code |= 8; // above return code; } return (0, _index.default)(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-_math.pi, radius - _math.pi]); }