UNPKG

@cquiroz/aladin-lite

Version:
757 lines (642 loc) 22.5 kB
import Constants from './Constants'; import SpatialVector from './SpatialVector'; class LongRangeSetBuilder { constructor() { this.items = []; } appendRange(first, last) { for (var i = first; last >= i; i++) { i in this.items || this.items.push(i); } } } function bigAnd(v1, v2) { var hi = 0x80000000; var low = 0x7fffffff; var hi1 = ~~(v1 / hi); var hi2 = ~~(v2 / hi); var low1 = (v1 & low) >>> 0; var low2 = (v2 & low) >>> 0; var h = (hi1 & hi2) >>> 0; var l = (low1 & low2) >>> 0; return h * hi + l; } function bigOr(v1, v2) { var hi = 0x80000000; var low = 0x7fffffff; var hi1 = ~~(v1 / hi); var hi2 = ~~(v2 / hi); var low1 = (v1 & low) >>> 0; var low2 = (v2 & low) >>> 0; var h = (hi1 | hi2) >>> 0; var l = (low1 | low2) >>> 0; return h * hi + l; } var orAll = function orAll() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return args.reduce((prev, curr) => bigOr(prev, curr), 0); }; var powerOf2 = new Array(53).fill(0).map((val, idx) => 2 ** idx); var shiftRight = (v, bits) => Math.trunc(v / powerOf2[bits]); var shiftLeft = (v, bits) => Math.trunc(v * powerOf2[bits]); export var ORDER_MAX = 26; var NSIDELIST = new Array(ORDER_MAX).fill(0).map((val, idx) => 2 ** idx); var JPLL = [1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7]; var JRLL = [2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]; var NS_MAX = NSIDELIST[NSIDELIST.length - 1]; var Z0 = Constants.TWOTHIRD; var TAB_SIZE = 256; /* eslint-disable no-mixed-operators */ var CTAB = new Array(TAB_SIZE).fill(0).map((v, i) => 1 & i | (2 & i) << 7 | (4 & i) >>> 1 | (8 & i) << 6 | (16 & i) >>> 2 | (32 & i) << 5 | (64 & i) >>> 3 | (128 & i) << 4); var UTAB = new Array(TAB_SIZE).fill(0).map((v, i) => 1 & i | (2 & i) << 1 | (4 & i) << 2 | (8 & i) << 3 | (16 & i) << 4 | (32 & i) << 5 | (64 & i) << 6 | (128 & i) << 7); /* eslint-enable no-mixed-operators */ export class HealpixIndex { constructor(nside) { this.nside = nside; this.nl2 = 2 * nside; this.nl3 = 3 * nside; this.nl4 = 4 * nside; this.npface = nside * nside; this.ncap = 2 * nside * (nside - 1); this.npix = 12 * this.npface; this.fact2 = 4 / this.npix; this.fact1 = (nside << 1) * this.fact2; this.order = HealpixIndex.nside2order(nside); } static calculateNSide(pixsize) { var i = 0; var n = pixsize * pixsize; var a = 180 / Constants.PI; var e = 3600 * 3600 * 4 * Constants.PI * a * a; var h = parseInt(e / n); var r = h / 12; var o = Math.sqrt(r); var c = NS_MAX; var u = 0; for (var p = 0; NSIDELIST.length > p; p++) { if (c >= Math.abs(o - NSIDELIST[p])) { c = Math.abs(o - NSIDELIST[p]); i = NSIDELIST[p]; u = p; } if (o > i && NS_MAX > o) { i = NSIDELIST[u + 1]; } if (o > NS_MAX) { console.log('nside cannot be bigger than ' + NS_MAX); return NS_MAX; } } return i; } static nside2order(nside) { return (nside & nside - 1) > 0 ? -1 : parseInt(Math.log2(nside)); } ang2pix_nest(theta, phi) { var tp, o, c, jp, jm, ntt, face_num, ix, iy; phi >= Constants.TWOPI && (phi -= Constants.TWOPI); 0 > phi && (phi += Constants.TWOPI); if (theta > Constants.PI || 0 > theta) { throw new Error({ name: 'Illegal argument', message: 'theta must be between 0 and ' + Constants.PI }); } if (0 > phi) { throw new Error({ name: 'Illegal argument', message: 'phi must be between 0 and ' + Constants.TWOPI }); } var z = Math.cos(theta); var za = Math.abs(z); var tt = phi / Constants.PIOVER2; if (Z0 >= za) { //Equatorial region var M = this.nside * (.5 + tt); var y = this.nside * .75 * z; var u = M - y; var p = M + y; // o = u >>> this.order; // c = p >>> this.order; o = shiftRight(u, this.order); c = shiftRight(p, this.order); face_num = o === c ? 4 === o ? 4 : o + 4 : c > o ? o : c + 8; ix = parseInt(p & this.nside - 1); iy = parseInt(this.nside - (u & this.nside - 1) - 1); } else { // polar region, za > 2/3 ntt = parseInt(tt); if (ntt >= 4) ntt = 3; tp = tt - ntt; var tmp = this.nside * Math.sqrt(3 * (1 - za)); // (the index of edge lines increase when distance from the closest pole goes up) jp = parseInt(tp * tmp); jm = parseInt((1 - tp) * tmp); jp = Math.min(NS_MAX - 1, jp); jm = Math.min(NS_MAX - 1, jm); // finds the face and pixel's (x,y) if (z >= 0) { face_num = ntt; // in {0,3} ix = parseInt(this.nside - jm - 1); iy = parseInt(this.nside - jp - 1); } else { face_num = ntt + 8; // in {8,11} ix = jp; iy = jm; } } return this.xyf2nest(ix, iy, face_num); } xyf2nest(ix, iy, face_num) { // const nest= (face_num << 2 * this.order) + // (this.utab[255 & ix] | // this.utab[255 & ix >>> 8] * Math.pow(2,16) | // this.utab[255 & ix >>> 16] * Math.pow(2,32)| // this.utab[255 & ix >>> 24] * Math.pow(2,48)| // this.utab[255 & iy] << 1 | // this.utab[255 & iy >>> 8] * Math.pow(2,17) | // this.utab[255 & iy >>> 16] * Math.pow(2,33) | // this.utab[255 & iy >>> 24] * Math.pow(2,49)); var nest = shiftLeft(face_num, 2 * this.order) + orAll(UTAB[255 & ix], shiftLeft(UTAB[bigAnd(255, shiftRight(ix, 8))], 16), shiftLeft(UTAB[bigAnd(255, shiftRight(ix, 16))], 32), shiftLeft(UTAB[bigAnd(255, shiftRight(ix, 24))], 48), shiftLeft(UTAB[bigAnd(255, iy)], 1), shiftLeft(UTAB[bigAnd(255, shiftRight(iy, 8))], 17), shiftLeft(UTAB[bigAnd(255, shiftRight(iy, 16))], 33), shiftLeft(UTAB[bigAnd(255, shiftRight(iy, 24))], 49)); // if (nest>0x7FFFFFF) { // console.log('xyf2nest: nest greater'); // } return nest; } nest2xyf(ipix) { // if (ipix>0x7FFFFFF) { // console.log('nest2xyf: ipix greater'); // } var s = {}; s.face_num = shiftRight(ipix, 2 * this.order); var i = bigAnd(ipix, this.npface - 1); // n = (93823560581120 & i) >>> 16 | (614882086624428e4 & i) >>> 31 | 21845 & i | (1431633920 & i) >>> 15; var n = orAll(shiftRight(bigAnd(0x555500000000, i), 16), shiftRight(bigAnd(0x5555000000000000, i), 31), bigAnd(0x5555, i), shiftRight(bigAnd(0x55550000, i), 15)); // s.ix = this.ctab[255 & n] | this.ctab[255 & n >>> 8] << 4 | this.ctab[255 & n >>> 16] << 16 | this.ctab[255 & n >>> 24] << 20; s.ix = orAll(CTAB[bigAnd(255, n)], shiftLeft(CTAB[255 & shiftRight(n, 8)], 4), shiftLeft(CTAB[255 & shiftRight(n, 16)], 16), shiftLeft(CTAB[255 & shiftRight(n, 24)], 20)); i = shiftRight(i, 1); // n = (93823560581120 & i) >>> 16 | (614882086624428e4 & i) >>> 31 | 21845 & i | (1431633920 & i) >>> 15; n = orAll(shiftRight(bigAnd(0x555500000000, i), 16), shiftRight(bigAnd(0x5555000000000000, i), 31), bigAnd(0x5555, i), shiftRight(bigAnd(0x55550000, i), 15)); // s.iy = this.ctab[255 & n] | this.ctab[255 & n >>> 8] << 4 | this.ctab[255 & n >>> 16] << 16 | this.ctab[255 & n >>> 24] << 20; s.iy = orAll(CTAB[bigAnd(255, n)], shiftLeft(CTAB[255 & shiftRight(n, 8)], 4), shiftLeft(CTAB[255 & shiftRight(n, 16)], 16), shiftLeft(CTAB[255 & shiftRight(n, 24)], 20)); return s; } pix2ang_nest(ipix) { if (0 > ipix || ipix > this.npix - 1) { throw new Error({ name: 'Illegal argument', message: 'ipix out of range' }); } var nr, z, kshift; var e = this.nest2xyf(ipix); var h = e.ix; var r = e.iy; var o = e.face_num; var jr = (JRLL[o] << this.order) - h - r - 1; if (this.nside > jr) { nr = jr; z = 1 - nr * nr * this.fact2; kshift = 0; } else if (jr > this.nl3) { nr = this.nl4 - jr; z = nr * nr * this.fact2 - 1; kshift = 0; } else { nr = this.nside; z = (this.nl2 - jr) * this.fact1; kshift = 1 & jr - this.nside; } var theta = Math.acos(z); var jp = (JPLL[o] * nr + h - r + 1 + kshift) / 2; jp > this.nl4 && (jp -= this.nl4); 1 > jp && (jp += this.nl4); var phi = (jp - .5 * (kshift + 1)) * (Constants.PIOVER2 / nr); return { theta, phi }; } static nside2Npix(nside) { if (0 > nside || (nside & -nside) !== nside || nside > NS_MAX) { throw new Error({ name: 'Illegal argument', message: 'nside should be >0, power of 2, <' + NS_MAX }); } var i = 12 * nside * nside; return i; } xyf2ring(ix, iy, face_num) { var nr, kshift, startpix; var r = JRLL[face_num] * this.nside - ix - iy - 1; if (this.nside > r) { nr = r; startpix = 2 * nr * (nr - 1); kshift = 0; } else if (r > 3 * this.nside) { nr = this.nl4 - r; startpix = this.npix - 2 * (nr + 1) * nr; kshift = 0; } else { nr = this.nside; startpix = this.ncap + (r - this.nside) * this.nl4; kshift = 1 & r - this.nside; } var jp = (JPLL[face_num] * nr + ix - iy + 1 + kshift) / 2; if (jp > this.nl4) { jp -= this.nl4; } else if (1 > jp) { jp += this.nl4; } return startpix + jp - 1; } nest2ring(ipnest) { var s = this.nest2xyf(ipnest); var i = this.xyf2ring(s.ix, s.iy, s.face_num); return i; } corners_nest(ipix, step) { var i = this.nest2ring(ipix); return this.corners_ring(i, step); } pix2ang_ring(ipix) { var theta, phi, iring, iphi, ip, fodd, hip, fihip; if (0 > ipix || ipix > this.npix - 1) { throw new Error({ name: 'Illegal argument', message: 'ipix out of range' }); } var ipix1 = ipix + 1; // in {1, npix} if (this.ncap >= ipix1) { hip = ipix1 / 2; fihip = parseInt(hip); iring = parseInt(Math.sqrt(hip - Math.sqrt(fihip))) + 1; iphi = ipix1 - 2 * iring * (iring - 1); theta = Math.acos(1 - iring * iring * this.fact2); phi = (iphi - .5) * Constants.PI / (2 * iring); } else { if (this.npix - this.ncap > ipix) { ip = ipix - this.ncap; iring = ip / this.nl4 + this.nside; iphi = ip % this.nl4 + 1; fodd = bigAnd(1, iring + this.nside) > 0 ? 1 : .5; theta = Math.acos((this.nl2 - iring) * this.fact1); phi = (iphi - fodd) * Constants.PI / this.nl2; } else { ip = this.npix - ipix; iring = parseInt(.5 * (1 + Math.sqrt(2 * ip - 1))); iphi = 4 * iring + 1 - (ip - 2 * iring * (iring - 1)); theta = Math.acos(-1 + Math.pow(iring, 2) * this.fact2); phi = (iphi - .5) * Constants.PI / (2 * iring); } } return [theta, phi]; } ring(ipix) { var s, i, n = 0; var a = ipix + 1; var e = 0; if (this.ncap >= a) { i = a / 2; e = parseInt(i); n = parseInt(Math.sqrt(i - Math.sqrt(e))) + 1; } else if (this.nl2 * (5 * this.nside + 1) >= a) { s = parseInt(a - this.ncap - 1); n = parseInt(s / this.nl4 + this.nside); } else { s = this.npix - a + 1; i = s / 2; e = parseInt(i); n = parseInt(Math.sqrt(i - Math.sqrt(e))) + 1; n = this.nl4 - n; } return n; } integration_limits_in_costh(i_th) { var s, i, n; var a = 1 * this.nside; if (this.nside >= i_th) { i = 1 - Math.pow(i_th, 2) / 3 / this.npface; n = 1 - Math.pow(i_th - 1, 2) / 3 / this.npface; s = i_th === this.nside ? 2 * (this.nside - 1) / 3 / a : 1 - Math.pow(i_th + 1, 2) / 3 / this.npface; } else if (this.nl3 > i_th) { i = 2 * (2 * this.nside - i_th) / 3 / a; n = 2 * (2 * this.nside - i_th + 1) / 3 / a; s = 2 * (2 * this.nside - i_th - 1) / 3 / a; } else { n = i_th === this.nl3 ? 2 * (-this.nside + 1) / 3 / a : -1 + Math.pow(4 * this.nside - i_th + 1, 2) / 3 / this.npface; s = -1 + Math.pow(this.nl4 - i_th - 1, 2) / 3 / this.npface; i = -1 + Math.pow(this.nl4 - i_th, 2) / 3 / this.npface; } return [n, i, s]; } pixel_boundaries(i_th, i_phi, i_zone, cos_theta) { var sq3th, factor, jd, ju, ku, kd, phi_l, phi_r; var r_n_nside = 1 * this.nside; if (Math.abs(cos_theta) >= 1 - 1 / 3 / this.npface) { phi_l = i_zone * Constants.PIOVER2; phi_r = (i_zone + 1) * Constants.PIOVER2; return [phi_l, phi_r]; } if (1.5 * cos_theta >= 1) { sq3th = Math.sqrt(3 * (1 - cos_theta)); factor = 1 / r_n_nside / sq3th; jd = i_phi; ju = jd - 1; ku = i_th - i_phi; kd = ku + 1; phi_l = Constants.PIOVER2 * (Math.max(ju * factor, 1 - kd * factor) + i_zone); phi_r = Constants.PIOVER2 * (Math.min(1 - ku * factor, jd * factor) + i_zone); } else if (1.5 * cos_theta > -1) { var cth34 = .5 * (1 - 1.5 * cos_theta); var cth34_1 = cth34 + 1; var modfactor = this.nside + i_th % 2; jd = i_phi - (modfactor - i_th) / 2; ju = jd - 1; ku = (modfactor + i_th) / 2 - i_phi; kd = ku + 1; phi_l = Constants.PIOVER2 * (Math.max(cth34_1 - kd / r_n_nside, -cth34 + ju / r_n_nside) + i_zone); phi_r = Constants.PIOVER2 * (Math.min(cth34_1 - ku / r_n_nside, -cth34 + jd / r_n_nside) + i_zone); } else { sq3th = Math.sqrt(3 * (1 + cos_theta)); factor = 1 / r_n_nside / sq3th; var M = 2 * this.nside; jd = i_th - M + i_phi; ju = jd - 1; ku = M - i_phi; kd = ku + 1; phi_l = Constants.PIOVER2 * (Math.max(1 - (M - ju) * factor, (M - kd) * factor) + i_zone); phi_r = Constants.PIOVER2 * (Math.min(1 - (M - jd) * factor, (M - ku) * factor) + i_zone); } return [phi_l, phi_r]; } static vector(theta, phi) { var x = Math.sin(theta) * Math.cos(phi); var y = Math.sin(theta) * Math.sin(phi); var z = Math.cos(theta); return new SpatialVector(x, y, z); } corners_ring(pix, step) { var n = 2 * step + 2; var res = Array(n); var e = this.pix2ang_ring(pix); var h = Math.cos(e[0]); var r = e[0]; var o = e[1]; var c = parseInt(o / Constants.PIOVER2); var u = this.ring(pix); var p = Math.min(u, Math.min(this.nside, this.nl4 - u)); var d = Constants.PIOVER2 / p; var l = u >= this.nside && this.nl3 >= u ? parseInt(o / d + u % 2 / 2) + 1 : parseInt(o / d) + 1; l -= c * p; var f = n / 2; var I = this.integration_limits_in_costh(u); var M = Math.acos(I[0]); var y = Math.acos(I[2]); var g = this.pixel_boundaries(u, l, c, I[0]); res[0] = l > p / 2 ? HealpixIndex.vector(M, g[1]) : HealpixIndex.vector(M, g[0]); g = this.pixel_boundaries(u, l, c, I[2]); res[f] = l > p / 2 ? HealpixIndex.vector(y, g[1]) : HealpixIndex.vector(y, g[0]); if (1 === step) { var P = Math.acos(I[1]); g = this.pixel_boundaries(u, l, c, I[1]); res[1] = HealpixIndex.vector(P, g[0]); res[3] = HealpixIndex.vector(P, g[1]); } else { var x = I[2] - I[0]; var C = x / (step + 1); for (var v = 1; step >= v; v++) { h = I[0] + C * v; r = Math.acos(h); g = this.pixel_boundaries(u, l, c, h); res[v] = HealpixIndex.vector(r, g[0]); res[n - v] = HealpixIndex.vector(r, g[1]); } } return res; } static vec2Ang(spatialVector) { var s = spatialVector.z / spatialVector.length(); var i = Math.acos(s); var n = 0; if (0 !== spatialVector.x || 0 !== spatialVector.y) { n = Math.atan2(spatialVector.y, spatialVector.x); } if (0 > n) { n += 2 * Math.PI; } return [i, n]; } /** * Returns a range set of pixels whose centers lie within a given disk. <p> * This method is more efficient in the RING scheme. * @param {SpatialVector} spatialVector the angular coordinates of the disk center * @param {number} radius the radius (in radians) of the disk * @param {boolean} nest true if nest, false if ring * @param {boolean} inclusive * @return {Array.<number> }the requested set of pixel number ranges */ queryDisc(spatialVector, radius, nest, inclusive) { if (0 > radius || radius > Constants.PI) { throw new Error({ name: 'Illegal argument', message: 'angular radius is in RADIAN and should be in [0,pi]' }); } var d, f, y, v; var pixset = new LongRangeSetBuilder(); var rsmall = inclusive ? radius + Constants.PI / this.nl4 : radius; var [theta, phi] = HealpixIndex.vec2Ang(spatialVector); var z0 = Math.cos(theta); var xa = 1 / Math.sqrt((1 - z0) * (1 + z0)); var rlat1 = theta - rsmall; var rlat2 = theta + rsmall; var cosrsmall = Math.cos(rsmall); var zmax = Math.cos(rlat1); var irmin = this.ringAbove(zmax) + 1; var zmin = Math.cos(rlat2); var h = this.ringAbove(zmin); if (irmin > h && 0 === h) h = irmin; if (0 >= rlat1) { for (var m = 1; irmin > m; ++m) { this.inRing(m, 0, Math.PI, pixset); } } for (var iz = irmin; h >= iz; ++iz) { v = this.nside > iz ? 1 - iz * iz * this.fact2 : this.nl3 >= iz ? (this.nl2 - iz) * this.fact1 : -1 + (this.nl4 - iz) * (this.nl4 - iz) * this.fact2; d = (cosrsmall - v * z0) * xa; f = 1 - v * v - d * d; y = Math.atan2(Math.sqrt(f), d); if (isNaN(y)) y = rsmall; this.inRing(iz, phi, y, pixset); } if (rlat2 >= Math.PI) { for (var _m = h + 1; this.nl4 > _m; ++_m) { this.inRing(_m, 0, Math.PI, pixset, false); } } if (nest) { var nestPixset = []; for (var i = 0; pixset.items.length > i; i++) { var nestPix = this.ring2nest(pixset.items[i]); nestPixset.indexOf(nestPix) >= 0 || nestPixset.push(nestPix); } // console.log(retPixAry); return nestPixset; } else { return pixset.items; } } inRing(iz, phi0, dphi, nest, conservative) { var e, h, r, o, c = false, d = 0, f = 0, I = 0, u; var p = 1e-12; var M = (phi0 - dphi) % Constants.TWOPI - p; var y = phi0 + dphi + p; var g = (phi0 + dphi) % Constants.TWOPI + p; if (p > Math.abs(dphi - Constants.PI)) c = true; if (iz >= this.nside && this.nl3 >= iz) { d = iz - this.nside + 1; r = this.ncap + this.nl4 * (d - 1); o = r + this.nl4 - 1; e = d % 2; h = this.nl4; } else { if (this.nside > iz) { d = iz; r = 2 * d * (d - 1); o = r + 4 * d - 1; } else { d = 4 * this.nside - iz; r = this.npix - 2 * d * (d + 1); o = r + 4 * d - 1; } h = 4 * d; e = 1; } if (c) { nest.appendRange(r, o); return; } var l = e / 2; if (conservative) { f = Math.round(h * M / Constants.TWOPI - l); I = Math.round(h * y / Constants.TWOPI - l); f %= h; I > h && (I %= h); } else { f = Math.ceil(h * M / Constants.TWOPI - l); I = parseInt(h * g / Constants.TWOPI - l); f > I && 1 === iz && (I = parseInt(h * y / Constants.TWOPI - l)); f === I + 1 && (f = I); if (1 === f - I && Constants.PI > dphi * h) { console.log('the interval is too small and away from center'); return undefined; } f = Math.min(f, h - 1); I = Math.max(I, 0); } f > I && (u = true); if (u) { f += r; I += r; nest.appendRange(r, I); nest.appendRange(f, o); } else { if (0 > f) { f = Math.abs(f); nest.appendRange(r, r + I); nest.appendRange(o - f + 1, o); return; } f += r; I += r; nest.appendRange(f, I); } } ringAbove(z) { var az = Math.abs(z); if (az > Constants.TWOTHIRD) { var iring = parseInt(this.nside * Math.sqrt(3 * (1 - az))); return z > 0 ? iring : 4 * this.nside - iring - 1; } return parseInt(this.nside * (2 - 1.5 * z)); } ring2nest(ipRing) { var xyf = this.ring2xyf(ipRing); var nest = this.xyf2nest(xyf.ix, xyf.iy, xyf.face_num); return nest; } ring2xyf(pix) { var iring, iphi, kshift, nr; var ret = {}; // Xyf if (this.ncap > pix) { // North Polar cap iring = parseInt(.5 * (1 + Math.sqrt(1 + 2 * pix))); iphi = pix + 1 - 2 * iring * (iring - 1); kshift = 0; nr = iring; ret.face_num = 0; var r = iphi - 1; if (r >= 2 * iring) { ret.face_num = 2; r -= 2 * iring; } r >= iring && ++ret.face_num; } else if (this.npix - this.ncap > pix) { // Equatorial region var ip = pix - this.ncap; if (this.order >= 0) { iring = shiftRight(ip, this.order + 2) + this.nside; // iphi = (ip & this.nl4 - 1) + 1; iphi = bigAnd(ip, this.nl4 - 1) + 1; } else { iring = ip / this.nl4 + this.nside; iphi = ip % this.nl4 + 1; } kshift = bigAnd(1, iring + this.nside); nr = this.nside; var c, u; var ire = iring - this.nside + 1; var irm = this.nl2 + 2 - ire; if (this.order >= 0) { c = shiftRight(iphi - parseInt(ire / 2) + this.nside - 1, this.order); u = shiftRight(iphi - parseInt(irm / 2) + this.nside - 1, this.order); } else { c = (iphi - parseInt(ire / 2) + this.nside - 1) / this.nside; u = (iphi - parseInt(irm / 2) + this.nside - 1) / this.nside; } if (u === c) { ret.face_num = 4 === u ? 4 : parseInt(u) + 4; } else { ret.face_num = c > u ? parseInt(u) : parseInt(c) + 8; } } else { // South Polar cap var _ip = this.npix - pix; iring = parseInt(.5 * (1 + Math.sqrt(2 * _ip - 1))); iphi = 4 * iring + 1 - (_ip - 2 * iring * (iring - 1)); kshift = 0; nr = iring; iring = 2 * this.nl2 - iring; ret.face_num = 8; var _r = iphi - 1; if (_r >= 2 * nr) { ret.face_num = 10; _r -= 2 * nr; } _r >= nr && ++ret.face_num; } var d = iring - JRLL[ret.face_num] * this.nside + 1; var f = 2 * iphi - JPLL[ret.face_num] * nr - kshift - 1; f >= this.nl2 && (f -= 8 * this.nside); // ret.ix = f - d >>> 1; // ret.iy = -(f + d) >>> 1; ret.ix = shiftRight(f - d, 1); ret.iy = shiftRight(-(f + d), 1); return ret; } }