LCOV - code coverage report
Current view: top level - libs/healpix_base - healpix_base.cc (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 112 734 15.3 %
Date: 2024-04-29 14:43:01 Functions: 10 91 11.0 %

          Line data    Source code
       1             : /*
       2             :  *  This file is part of Healpix_cxx.
       3             :  *
       4             :  *  Healpix_cxx is free software; you can redistribute it and/or modify
       5             :  *  it under the terms of the GNU General Public License as published by
       6             :  *  the Free Software Foundation; either version 2 of the License, or
       7             :  *  (at your option) any later version.
       8             :  *
       9             :  *  Healpix_cxx is distributed in the hope that it will be useful,
      10             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  *  GNU General Public License for more details.
      13             :  *
      14             :  *  You should have received a copy of the GNU General Public License
      15             :  *  along with Healpix_cxx; if not, write to the Free Software
      16             :  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             :  *
      18             :  *  For more information about HEALPix, see http://healpix.sourceforge.net
      19             :  */
      20             : 
      21             : /*
      22             :  *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
      23             :  *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
      24             :  *  (DLR).
      25             :  */
      26             : 
      27             : /*
      28             :  *  Copyright (C) 2003-2012 Max-Planck-Society
      29             :  *  Author: Martin Reinecke
      30             :  */
      31             : 
      32             : #include "healpix_base/healpix_base.h"
      33             : #include "healpix_base/geom_utils.h"
      34             : #include "healpix_base/lsconstants.h"
      35             : 
      36             : namespace healpix{
      37             : 
      38             : using namespace std;
      39             : 
      40             : template<> const int T_Healpix_Base<int  >::order_max=13;
      41             : template<> const int T_Healpix_Base<int64>::order_max=29;
      42             : 
      43           0 : template<typename I> int T_Healpix_Base<I>::nside2order (I nside)
      44             :   {
      45           0 :   planck_assert (nside>I(0), "invalid value for Nside");
      46           0 :   return ((nside)&(nside-1)) ? -1 : ilog2(nside);
      47             :   }
      48           0 : template<typename I> I T_Healpix_Base<I>::npix2nside (I npix)
      49             :   {
      50           0 :   I res=isqrt(npix/I(12));
      51           0 :   planck_assert (npix==res*res*I(12), "invalid value for npix");
      52           0 :   return res;
      53             :   }
      54             : 
      55           0 : template<typename I> I T_Healpix_Base<I>::ring_above (double z) const
      56             :   {
      57             :   double az=abs(z);
      58           0 :   if (az<=twothird) // equatorial region
      59           0 :     return I(nside_*(2-1.5*z));
      60           0 :   I iring = I(nside_*sqrt(3*(1-az)));
      61           0 :   return (z>0) ? iring : 4*nside_-iring-1;
      62             :   }
      63             : 
      64             : namespace {
      65             : 
      66             : /* Short note on the "zone":
      67             :    zone = 0: pixel lies completely outside the queried shape
      68             :           1: pixel may overlap with the shape, pixel center is outside
      69             :           2: pixel center is inside the shape, but maybe not the complete pixel
      70             :           3: pixel lies completely inside the shape */
      71             : 
      72           0 : template<typename I, typename I2> inline void check_pixel (int o, int order_,
      73             :   int omax, int zone, rangeset<I2> &pixset, I pix, vector<pair<I,int> > &stk,
      74             :   bool inclusive, int &stacktop)
      75             :   {
      76           0 :   if (zone==0) return;
      77             : 
      78           0 :   if (o<order_)
      79             :     {
      80           0 :     if (zone>=3)
      81             :       {
      82           0 :       int sdist=2*(order_-o); // the "bit-shift distance" between map orders
      83           0 :       pixset.append(pix<<sdist,(pix+1)<<sdist); // output all subpixels
      84             :       }
      85             :     else // (zone>=1)
      86           0 :       for (int i=0; i<4; ++i)
      87           0 :         stk.push_back(make_pair(4*pix+3-i,o+1)); // add children
      88             :     }
      89           0 :   else if (o>order_) // this implies that inclusive==true
      90             :     {
      91           0 :     if (zone>=2) // pixel center in shape
      92             :       {
      93           0 :       pixset.append(pix>>(2*(o-order_))); // output the parent pixel at order_
      94           0 :       stk.resize(stacktop); // unwind the stack
      95             :       }
      96             :     else // (zone>=1): pixel center in safety range
      97             :       {
      98           0 :       if (o<omax) // check sublevels
      99           0 :         for (int i=0; i<4; ++i) // add children in reverse order
     100           0 :           stk.push_back(make_pair(4*pix+3-i,o+1));
     101             :       else // at resolution limit
     102             :         {
     103           0 :         pixset.append(pix>>(2*(o-order_))); // output the parent pixel at order_
     104           0 :         stk.resize(stacktop); // unwind the stack
     105             :         }
     106             :       }
     107             :     }
     108             :   else // o==order_
     109             :     {
     110           0 :     if (zone>=2)
     111           0 :       pixset.append(pix);
     112           0 :     else if (inclusive) // and (zone>=1)
     113             :       {
     114           0 :       if (order_<omax) // check sublevels
     115             :         {
     116           0 :         stacktop=stk.size(); // remember current stack position
     117           0 :         for (int i=0; i<4; ++i) // add children in reverse order
     118           0 :           stk.push_back(make_pair(4*pix+3-i,o+1));
     119             :         }
     120             :       else // at resolution limit
     121           0 :         pixset.append(pix); // output the pixel
     122             :       }
     123             :     }
     124             :   }
     125             : 
     126           0 : template<typename I> bool check_pixel_ring (const T_Healpix_Base<I> &b1,
     127             :   const T_Healpix_Base<I> &b2, I pix, I nr, I ipix1, int fct,
     128             :   double cz, double cphi, double cosrp2, I cpix)
     129             :   {
     130           0 :   if (pix>=nr) pix-=nr;
     131           0 :   if (pix<0) pix+=nr;
     132           0 :   pix+=ipix1;
     133           0 :   if (pix==cpix) return false; // disk center in pixel => overlap
     134             :   int px,py,pf;
     135           0 :   b1.pix2xyf(pix,px,py,pf);
     136           0 :   for (int i=0; i<fct-1; ++i) // go along the 4 edges
     137             :     {
     138           0 :     I ox=fct*px, oy=fct*py;
     139             :     double pz,pphi;
     140           0 :     b2.pix2zphi(b2.xyf2pix(ox+i,oy,pf),pz,pphi);
     141           0 :     if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap
     142           0 :       return false;
     143           0 :     b2.pix2zphi(b2.xyf2pix(ox+fct-1,oy+i,pf),pz,pphi);
     144           0 :     if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap
     145             :       return false;
     146           0 :     b2.pix2zphi(b2.xyf2pix(ox+fct-1-i,oy+fct-1,pf),pz,pphi);
     147           0 :     if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap
     148             :       return false;
     149           0 :     b2.pix2zphi(b2.xyf2pix(ox,oy+fct-1-i,pf),pz,pphi);
     150           0 :     if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap
     151             :       return false;
     152             :     }
     153             :   return true;
     154             :   }
     155             : 
     156             : } // unnamed namespace
     157             : 
     158             : template<typename I> template<typename I2>
     159           0 :   void T_Healpix_Base<I>::query_disc_internal
     160             :   (pointing ptg, double radius, int fact, rangeset<I2> &pixset) const
     161             :   {
     162           0 :   bool inclusive = (fact!=0);
     163             :   pixset.clear();
     164           0 :   ptg.normalize();
     165             : 
     166           0 :   if (scheme_==RING)
     167             :     {
     168             :     I fct=1;
     169           0 :     if (inclusive)
     170             :       {
     171           0 :       planck_assert (((I(1)<<order_max)/nside_)>=fact,
     172             :         "invalid oversampling factor");
     173             :       fct = fact;
     174             :       }
     175           0 :     T_Healpix_Base b2;
     176             :     double rsmall, rbig;
     177           0 :     if (fct>1)
     178             :       {
     179           0 :       b2.SetNside(fct*nside_,RING);
     180           0 :       rsmall = radius+b2.max_pixrad();
     181           0 :       rbig = radius+max_pixrad();
     182             :       }
     183             :     else
     184           0 :       rsmall = rbig = inclusive ? radius+max_pixrad() : radius;
     185             : 
     186           0 :     if (rsmall>=pi)
     187           0 :       { pixset.append(0,npix_); return; }
     188             : 
     189           0 :     rbig = min(pi,rbig);
     190             : 
     191           0 :     double cosrsmall = cos(rsmall);
     192           0 :     double cosrbig = cos(rbig);
     193             : 
     194           0 :     double z0 = cos(ptg.theta);
     195           0 :     double xa = 1./sqrt((1-z0)*(1+z0));
     196             : 
     197           0 :     I cpix=zphi2pix(z0,ptg.phi);
     198             : 
     199           0 :     double rlat1 = ptg.theta - rsmall;
     200           0 :     double zmax = cos(rlat1);
     201           0 :     I irmin = ring_above (zmax)+1;
     202             : 
     203           0 :     if ((rlat1<=0) && (irmin>1)) // north pole in the disk
     204             :       {
     205             :       I sp,rp; bool dummy;
     206           0 :       get_ring_info_small(irmin-1,sp,rp,dummy);
     207           0 :       pixset.append(0,sp+rp);
     208             :       }
     209             : 
     210           0 :     if ((fct>1) && (rlat1>0)) irmin=max(I(1),irmin-1);
     211             : 
     212           0 :     double rlat2 = ptg.theta + rsmall;
     213           0 :     double zmin = cos(rlat2);
     214           0 :     I irmax = ring_above (zmin);
     215             : 
     216           0 :     if ((fct>1) && (rlat2<pi)) irmax=min(4*nside_-1,irmax+1);
     217             : 
     218           0 :     for (I iz=irmin; iz<=irmax; ++iz)
     219             :       {
     220           0 :       double z=ring2z(iz);
     221           0 :       double x = (cosrbig-z*z0)*xa;
     222           0 :       double ysq = 1-z*z-x*x;
     223           0 :       double dphi = (ysq<=0) ? pi-1e-15 : atan2(sqrt(ysq),x);
     224             :       I nr, ipix1;
     225             :       bool shifted;
     226           0 :       get_ring_info_small(iz,ipix1,nr,shifted);
     227           0 :       double shift = shifted ? 0.5 : 0.;
     228             : 
     229           0 :       I ipix2 = ipix1 + nr - 1; // highest pixel number in the ring
     230             : 
     231           0 :       I ip_lo = ifloor<I>(nr*inv_twopi*(ptg.phi-dphi) - shift)+1;
     232           0 :       I ip_hi = ifloor<I>(nr*inv_twopi*(ptg.phi+dphi) - shift);
     233             : 
     234           0 :       if (fct>1)
     235             :         {
     236           0 :         while ((ip_lo<=ip_hi) && check_pixel_ring
     237           0 :                (*this,b2,ip_lo,nr,ipix1,fct,z0,ptg.phi,cosrsmall,cpix))
     238           0 :           ++ip_lo;
     239           0 :         while ((ip_hi>ip_lo) && check_pixel_ring
     240           0 :                (*this,b2,ip_hi,nr,ipix1,fct,z0,ptg.phi,cosrsmall,cpix))
     241           0 :           --ip_hi;
     242             :         }
     243             : 
     244           0 :       if (ip_lo<=ip_hi)
     245             :         {
     246           0 :         if (ip_hi>=nr)
     247           0 :           { ip_lo-=nr; ip_hi-=nr; }
     248           0 :         if (ip_lo<0)
     249             :           {
     250           0 :           pixset.append(ipix1,ipix1+ip_hi+1);
     251           0 :           pixset.append(ipix1+ip_lo+nr,ipix2+1);
     252             :           }
     253             :         else
     254           0 :           pixset.append(ipix1+ip_lo,ipix1+ip_hi+1);
     255             :         }
     256             :       }
     257           0 :     if ((rlat2>=pi) && (irmax+1<4*nside_)) // south pole in the disk
     258             :       {
     259             :       I sp,rp; bool dummy;
     260           0 :       get_ring_info_small(irmax+1,sp,rp,dummy);
     261           0 :       pixset.append(sp,npix_);
     262             :       }
     263             :     }
     264             :   else // scheme_==NEST
     265             :     {
     266           0 :     if (radius>=pi) // disk covers the whole sphere
     267           0 :       { pixset.append(0,npix_); return; }
     268             : 
     269             :     int oplus = 0;
     270           0 :     if (inclusive)
     271             :       {
     272           0 :       planck_assert ((I(1)<<(order_max-order_))>=fact,
     273             :         "invalid oversampling factor");
     274           0 :       planck_assert ((fact&(fact-1))==0,
     275             :         "oversampling factor must be a power of 2");
     276           0 :       oplus=ilog2(fact);
     277             :       }
     278           0 :     int omax=order_+oplus; // the order up to which we test
     279             : 
     280             :     vec3 vptg(ptg);
     281           0 :     arr<T_Healpix_Base<I> > base(omax+1);
     282             :     arr<double> crpdr(omax+1), crmdr(omax+1);
     283           0 :     double cosrad=cos(radius);
     284           0 :     for (int o=0; o<=omax; ++o) // prepare data at the required orders
     285             :       {
     286           0 :       base[o].Set(o,NEST);
     287           0 :       double dr=base[o].max_pixrad(); // safety distance
     288           0 :       crpdr[o] = (radius+dr>pi) ? -1. : cos(radius+dr);
     289           0 :       crmdr[o] = (radius-dr<0.) ?  1. : cos(radius-dr);
     290             :       }
     291             :     vector<pair<I,int> > stk; // stack for pixel numbers and their orders
     292           0 :     stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation
     293           0 :     for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order
     294           0 :       stk.push_back(make_pair(I(11-i),0));
     295             : 
     296           0 :     int stacktop=0; // a place to save a stack position
     297             : 
     298           0 :     while (!stk.empty()) // as long as there are pixels on the stack
     299             :       {
     300             :       // pop current pixel number and order from the stack
     301           0 :       I pix=stk.back().first;
     302           0 :       int o=stk.back().second;
     303             :       stk.pop_back();
     304             : 
     305             :       double z,phi;
     306             :       base[o].pix2zphi(pix,z,phi);
     307             :       // cosine of angular distance between pixel center and disk center
     308           0 :       double cangdist=cosdist_zphi(vptg.z,ptg.phi,z,phi);
     309             : 
     310           0 :       if (cangdist>crpdr[o])
     311             :         {
     312           0 :         int zone = (cangdist<cosrad) ? 1 : ((cangdist<=crmdr[o]) ? 2 : 3);
     313             : 
     314           0 :         check_pixel (o, order_, omax, zone, pixset, pix, stk, inclusive,
     315             :           stacktop);
     316             :         }
     317             :       }
     318             :     }
     319             :   }
     320             : 
     321           0 : template<typename I> void T_Healpix_Base<I>::query_disc
     322             :   (pointing ptg, double radius, rangeset<I> &pixset) const
     323             :   {
     324           0 :   query_disc_internal (ptg, radius, 0, pixset);
     325           0 :   }
     326             : 
     327           0 : template<typename I> void T_Healpix_Base<I>::query_disc_inclusive
     328             :   (pointing ptg, double radius, rangeset<I> &pixset, int fact) const
     329             :   {
     330           0 :   planck_assert(fact>0,"fact must be a positive integer");
     331           0 :   if ((sizeof(I)<8) && (((I(1)<<order_max)/nside_)<fact))
     332             :     {
     333           0 :     T_Healpix_Base<int64> base2(nside_,scheme_,SET_NSIDE);
     334           0 :     base2.query_disc_internal(ptg,radius,fact,pixset);
     335             :     return;
     336             :     }
     337           0 :   query_disc_internal (ptg, radius, fact, pixset);
     338             :   }
     339             : 
     340             : template<typename I> template<typename I2>
     341           0 :   void T_Healpix_Base<I>::query_multidisc (const arr<vec3> &norm,
     342             :   const arr<double> &rad, int fact, rangeset<I2> &pixset) const
     343             :   {
     344           0 :   bool inclusive = (fact!=0);
     345             :   tsize nv=norm.size();
     346           0 :   planck_assert(nv==rad.size(),"inconsistent input arrays");
     347             :   pixset.clear();
     348             : 
     349           0 :   if (scheme_==RING)
     350             :     {
     351             :     I fct=1;
     352           0 :     if (inclusive)
     353             :       {
     354           0 :       planck_assert (((I(1)<<order_max)/nside_)>=fact,
     355             :         "invalid oversampling factor");
     356             :       fct = fact;
     357             :       }
     358           0 :     T_Healpix_Base b2;
     359             :     double rpsmall, rpbig;
     360           0 :     if (fct>1)
     361             :       {
     362           0 :       b2.SetNside(fct*nside_,RING);
     363           0 :       rpsmall = b2.max_pixrad();
     364           0 :       rpbig = max_pixrad();
     365             :       }
     366             :     else
     367           0 :       rpsmall = rpbig = inclusive ? max_pixrad() : 0;
     368             : 
     369           0 :     I irmin=1, irmax=4*nside_-1;
     370             :     vector<double> z0,xa,cosrsmall,cosrbig;
     371             :     vector<pointing> ptg;
     372             :     vector<I> cpix;
     373           0 :     for (tsize i=0; i<nv; ++i)
     374             :       {
     375           0 :       double rsmall=rad[i]+rpsmall;
     376           0 :       if (rsmall<pi)
     377             :         {
     378           0 :         double rbig=min(pi,rad[i]+rpbig);
     379             :         pointing pnt=pointing(norm[i]);
     380           0 :         cosrsmall.push_back(cos(rsmall));
     381           0 :         cosrbig.push_back(cos(rbig));
     382           0 :         double cth=cos(pnt.theta);
     383           0 :         z0.push_back(cth);
     384           0 :         if (fct>1) cpix.push_back(zphi2pix(cth,pnt.phi));
     385           0 :         xa.push_back(1./sqrt((1-cth)*(1+cth)));
     386           0 :         ptg.push_back(pnt);
     387             : 
     388           0 :         double rlat1 = pnt.theta - rsmall;
     389           0 :         double zmax = cos(rlat1);
     390           0 :         I irmin_t = (rlat1<=0) ? 1 : ring_above (zmax)+1;
     391             : 
     392           0 :         if ((fct>1) && (rlat1>0)) irmin_t=max(I(1),irmin_t-1);
     393             : 
     394           0 :         double rlat2 = pnt.theta + rsmall;
     395           0 :         double zmin = cos(rlat2);
     396           0 :         I irmax_t = (rlat2>=pi) ? 4*nside_-1 : ring_above (zmin);
     397             : 
     398           0 :         if ((fct>1) && (rlat2<pi)) irmax_t=min(4*nside_-1,irmax_t+1);
     399             : 
     400             :         if (irmax_t < irmax) irmax=irmax_t;
     401             :         if (irmin_t > irmin) irmin=irmin_t;
     402             :         }
     403             :       }
     404             : 
     405           0 :     for (I iz=irmin; iz<=irmax; ++iz)
     406             :       {
     407           0 :       double z=ring2z(iz);
     408             :       I ipix1,nr;
     409             :       bool shifted;
     410           0 :       get_ring_info_small(iz,ipix1,nr,shifted);
     411           0 :       double shift = shifted ? 0.5 : 0.;
     412             :       rangeset<I2> tr;
     413           0 :       tr.append(ipix1,ipix1+nr);
     414           0 :       for (tsize j=0; j<z0.size(); ++j)
     415             :         {
     416           0 :         double x = (cosrbig[j]-z*z0[j])*xa[j];
     417           0 :         double ysq = 1.-z*z-x*x;
     418           0 :         double dphi = (ysq<=0) ? pi-1e-15 : atan2(sqrt(ysq),x);
     419           0 :         I ip_lo = ifloor<I>(nr*inv_twopi*(ptg[j].phi-dphi) - shift)+1;
     420           0 :         I ip_hi = ifloor<I>(nr*inv_twopi*(ptg[j].phi+dphi) - shift);
     421           0 :         if (fct>1)
     422             :           {
     423           0 :           while ((ip_lo<=ip_hi) && check_pixel_ring
     424           0 :             (*this,b2,ip_lo,nr,ipix1,fct,z0[j],ptg[j].phi,cosrsmall[j],cpix[j]))
     425           0 :             ++ip_lo;
     426           0 :           while ((ip_hi>ip_lo) && check_pixel_ring
     427           0 :             (*this,b2,ip_hi,nr,ipix1,fct,z0[j],ptg[j].phi,cosrsmall[j],cpix[j]))
     428           0 :             --ip_hi;
     429             :           }
     430           0 :         if (ip_hi>=nr)
     431           0 :           { ip_lo-=nr; ip_hi-=nr;}
     432           0 :         if (ip_lo<0)
     433           0 :           tr.remove(ipix1+ip_hi+1,ipix1+ip_lo+nr);
     434             :         else
     435           0 :           tr.intersect(ipix1+ip_lo,ipix1+ip_hi+1);
     436             :         }
     437           0 :       pixset.append(tr);
     438             :       }
     439             :     }
     440             :   else // scheme_ == NEST
     441             :     {
     442             :     int oplus = 0;
     443           0 :     if (inclusive)
     444             :       {
     445           0 :       planck_assert ((I(1)<<(order_max-order_))>=fact,
     446             :         "invalid oversampling factor");
     447           0 :       planck_assert ((fact&(fact-1))==0,
     448             :         "oversampling factor must be a power of 2");
     449           0 :       oplus=ilog2(fact);
     450             :       }
     451           0 :     int omax=order_+oplus; // the order up to which we test
     452             : 
     453             :     // TODO: ignore all disks with radius>=pi
     454             : 
     455           0 :     arr<T_Healpix_Base<I> > base(omax+1);
     456             :     arr3<double> crlimit(omax+1,nv,3);
     457           0 :     for (int o=0; o<=omax; ++o) // prepare data at the required orders
     458             :       {
     459           0 :       base[o].Set(o,NEST);
     460           0 :       double dr=base[o].max_pixrad(); // safety distance
     461           0 :       for (tsize i=0; i<nv; ++i)
     462             :         {
     463           0 :         crlimit(o,i,0) = (rad[i]+dr>pi) ? -1. : cos(rad[i]+dr);
     464           0 :         crlimit(o,i,1) = (o==0) ? cos(rad[i]) : crlimit(0,i,1);
     465           0 :         crlimit(o,i,2) = (rad[i]-dr<0.) ?  1. : cos(rad[i]-dr);
     466             :         }
     467             :       }
     468             : 
     469             :     vector<pair<I,int> > stk; // stack for pixel numbers and their orders
     470           0 :     stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation
     471           0 :     for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order
     472           0 :       stk.push_back(make_pair(I(11-i),0));
     473             : 
     474           0 :     int stacktop=0; // a place to save a stack position
     475             : 
     476           0 :     while (!stk.empty()) // as long as there are pixels on the stack
     477             :       {
     478             :       // pop current pixel number and order from the stack
     479           0 :       I pix=stk.back().first;
     480           0 :       int o=stk.back().second;
     481             :       stk.pop_back();
     482             : 
     483           0 :       vec3 pv(base[o].pix2vec(pix));
     484             : 
     485             :       tsize zone=3;
     486           0 :       for (tsize i=0; i<nv; ++i)
     487             :         {
     488             :         double crad=dotprod(pv,norm[i]);
     489           0 :         for (tsize iz=0; iz<zone; ++iz)
     490           0 :           if (crad<crlimit(o,i,iz))
     491           0 :             if ((zone=iz)==0) goto bailout;
     492             :         }
     493             : 
     494           0 :       check_pixel (o, order_, omax, zone, pixset, pix, stk, inclusive,
     495             :         stacktop);
     496           0 :       bailout:;
     497             :       }
     498             :     }
     499           0 :   }
     500             : 
     501           0 : template<typename I> void T_Healpix_Base<I>::query_multidisc_general
     502             :   (const arr<vec3> &norm, const arr<double> &rad, bool inclusive,
     503             :   const vector<int> &cmds, rangeset<I> &pixset) const
     504             :   {
     505             :   tsize nv=norm.size();
     506           0 :   planck_assert(nv==rad.size(),"inconsistent input arrays");
     507             :   pixset.clear();
     508             : 
     509           0 :   if (scheme_==RING)
     510             :     {
     511           0 :     planck_fail ("not yet implemented");
     512             :     }
     513             :   else // scheme_ == NEST
     514             :     {
     515           0 :     int oplus=inclusive ? 2 : 0;
     516           0 :     int omax=min(order_max,order_+oplus); // the order up to which we test
     517             : 
     518             :     // TODO: ignore all disks with radius>=pi
     519             : 
     520           0 :     arr<T_Healpix_Base<I> > base(omax+1);
     521             :     arr3<double> crlimit(omax+1,nv,3);
     522           0 :     for (int o=0; o<=omax; ++o) // prepare data at the required orders
     523             :       {
     524           0 :       base[o].Set(o,NEST);
     525           0 :       double dr=base[o].max_pixrad(); // safety distance
     526           0 :       for (tsize i=0; i<nv; ++i)
     527             :         {
     528           0 :         crlimit(o,i,0) = (rad[i]+dr>pi) ? -1. : cos(rad[i]+dr);
     529           0 :         crlimit(o,i,1) = (o==0) ? cos(rad[i]) : crlimit(0,i,1);
     530           0 :         crlimit(o,i,2) = (rad[i]-dr<0.) ?  1. : cos(rad[i]-dr);
     531             :         }
     532             :       }
     533             : 
     534             :     vector<pair<I,int> > stk; // stack for pixel numbers and their orders
     535           0 :     stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation
     536           0 :     for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order
     537           0 :       stk.push_back(make_pair(I(11-i),0));
     538             : 
     539           0 :     int stacktop=0; // a place to save a stack position
     540             :     arr<tsize> zone(nv);
     541             : 
     542           0 :     vector<tsize> zstk; zstk.reserve(cmds.size());
     543             : 
     544           0 :     while (!stk.empty()) // as long as there are pixels on the stack
     545             :       {
     546             :       // pop current pixel number and order from the stack
     547           0 :       I pix=stk.back().first;
     548           0 :       int o=stk.back().second;
     549             :       stk.pop_back();
     550             : 
     551           0 :       vec3 pv(base[o].pix2vec(pix));
     552             : 
     553           0 :       for (tsize i=0; i<nv; ++i)
     554             :         {
     555           0 :         zone[i]=3;
     556             :         double crad=dotprod(pv,norm[i]);
     557           0 :         for (tsize iz=0; iz<zone[i]; ++iz)
     558           0 :           if (crad<crlimit(o,i,iz))
     559           0 :             zone[i]=iz;
     560             :         }
     561             : 
     562           0 :       for (tsize i=0; i<cmds.size(); ++i)
     563             :         {
     564             :         tsize tmp;
     565           0 :         switch (cmds[i])
     566             :           {
     567             :           case -1: // union
     568           0 :             tmp=zstk.back(); zstk.pop_back();
     569           0 :             zstk.back() = max(zstk.back(),tmp);
     570           0 :             break;
     571             :           case -2: // intersection
     572           0 :             tmp=zstk.back(); zstk.pop_back();
     573           0 :             zstk.back() = min(zstk.back(),tmp);
     574           0 :             break;
     575             :           default: // add value
     576           0 :             zstk.push_back(zone[cmds[i]]);
     577             :           }
     578             :         }
     579           0 :       planck_assert(zstk.size()==1,"inconsistent commands");
     580           0 :       tsize zn=zstk[0]; zstk.pop_back();
     581             : 
     582           0 :       check_pixel (o, order_, omax, zn, pixset, pix, stk, inclusive,
     583             :         stacktop);
     584             :       }
     585             :     }
     586           0 :   }
     587             : 
     588             : template<> inline int T_Healpix_Base<int>::spread_bits (int v) const
     589         421 :   { return utab[v&0xff] | (utab[(v>>8)&0xff]<<16); }
     590           0 : template<> inline int64 T_Healpix_Base<int64>::spread_bits (int v) const
     591             :   {
     592           0 :   return  int64(utab[ v     &0xff])      | (int64(utab[(v>> 8)&0xff])<<16)
     593           0 :        | (int64(utab[(v>>16)&0xff])<<32) | (int64(utab[(v>>24)&0xff])<<48);
     594             :   }
     595             : 
     596             : template<> inline int T_Healpix_Base<int>::compress_bits (int v) const
     597             :   {
     598           0 :   int raw = (v&0x5555) | ((v&0x55550000)>>15);
     599           0 :   return ctab[raw&0xff] | (ctab[raw>>8]<<4);
     600             :   }
     601         842 : template<> inline int T_Healpix_Base<int64>::compress_bits (int64 v) const
     602             :   {
     603         842 :   int64 raw = v&0x5555555555555555ull;
     604         842 :   raw|=raw>>15;
     605         842 :   return ctab[ raw     &0xff]      | (ctab[(raw>> 8)&0xff]<< 4)
     606         842 :       | (ctab[(raw>>32)&0xff]<<16) | (ctab[(raw>>40)&0xff]<<20);
     607             :   }
     608             : 
     609         421 : template<typename I> inline void T_Healpix_Base<I>::nest2xyf (I pix, int &ix,
     610             :   int &iy, int &face_num) const
     611             :   {
     612         421 :   face_num = pix>>(2*order_);
     613         421 :   pix &= (npface_-1);
     614         421 :   ix = compress_bits(pix);
     615         421 :   iy = compress_bits(pix>>1);
     616         421 :   }
     617             : 
     618         421 : template<typename I> inline I T_Healpix_Base<I>::xyf2nest (int ix, int iy,
     619             :   int face_num) const
     620         421 :   { return (I(face_num)<<(2*order_)) + spread_bits(ix) + (spread_bits(iy)<<1); }
     621             : 
     622         421 : template<typename I> void T_Healpix_Base<I>::ring2xyf (I pix, int &ix, int &iy,
     623             :   int &face_num) const
     624             :   {
     625             :   I iring, iphi, kshift, nr;
     626         421 :   I nl2 = 2*nside_;
     627             : 
     628         421 :   if (pix<ncap_) // North Polar cap
     629             :     {
     630           0 :     iring = (1+isqrt(1+2*pix))>>1; //counted from North pole
     631           0 :     iphi  = (pix+1) - 2*iring*(iring-1);
     632             :     kshift = 0;
     633             :     nr = iring;
     634           0 :     face_num=(iphi-1)/nr;
     635             :     }
     636         421 :   else if (pix<(npix_-ncap_)) // Equatorial region
     637             :     {
     638         421 :     I ip = pix - ncap_;
     639         421 :     I tmp = (order_>=0) ? ip>>(order_+2) : ip/(4*nside_);
     640         421 :     iring = tmp+nside_;
     641         421 :     iphi = ip-tmp*4*nside_ + 1;
     642         421 :     kshift = (iring+nside_)&1;
     643             :     nr = nside_;
     644         421 :     I ire = iring-nside_+1,
     645         421 :       irm = nl2+2-ire;
     646         421 :     I ifm = iphi - ire/2 + nside_ -1,
     647         421 :       ifp = iphi - irm/2 + nside_ -1;
     648         421 :     if (order_>=0)
     649         421 :       { ifm >>= order_; ifp >>= order_; }
     650             :     else
     651           0 :       { ifm /= nside_; ifp /= nside_; }
     652         421 :     face_num = (ifp==ifm) ? (ifp|4) : ((ifp<ifm) ? ifp : (ifm+8));
     653             :     }
     654             :   else // South Polar cap
     655             :     {
     656           0 :     I ip = npix_ - pix;
     657           0 :     iring = (1+isqrt(2*ip-1))>>1; //counted from South pole
     658           0 :     iphi  = 4*iring + 1 - (ip - 2*iring*(iring-1));
     659             :     kshift = 0;
     660             :     nr = iring;
     661           0 :     iring = 2*nl2-iring;
     662           0 :     face_num = 8 + (iphi-1)/nr;
     663             :     }
     664             : 
     665         421 :   I irt = iring - (jrll[face_num]*nside_) + 1;
     666         421 :   I ipt = 2*iphi- jpll[face_num]*nr - kshift -1;
     667         421 :   if (ipt>=nl2) ipt-=8*nside_;
     668             : 
     669         421 :   ix =  (ipt-irt) >>1;
     670         421 :   iy = (-ipt-irt) >>1;
     671         421 :   }
     672             : 
     673           0 : template<typename I> I T_Healpix_Base<I>::xyf2ring (int ix, int iy,
     674             :   int face_num) const
     675             :   {
     676           0 :   I nl4 = 4*nside_;
     677           0 :   I jr = (jrll[face_num]*nside_) - ix - iy  - 1;
     678             : 
     679             :   I nr, kshift, n_before;
     680             : 
     681             :   bool shifted;
     682           0 :   get_ring_info_small(jr,n_before,nr,shifted);
     683           0 :   nr>>=2;
     684           0 :   kshift=1-shifted;
     685           0 :   I jp = (jpll[face_num]*nr + ix - iy + 1 + kshift) / 2;
     686           0 :   planck_assert(jp<=4*nr,"must not happen");
     687           0 :   if (jp<1) jp+=nl4; // assumption: if this triggers, then nl4==4*nr
     688             : 
     689           0 :   return n_before + jp - 1;
     690             :   }
     691             : 
     692           0 : template<typename I> T_Healpix_Base<I>::T_Healpix_Base ()
     693           0 :   : order_(-1), nside_(0), npface_(0), ncap_(0), npix_(0),
     694           0 :     fact1_(0), fact2_(0), scheme_(RING) {}
     695             : 
     696          29 : template<typename I> void T_Healpix_Base<I>::Set (int order,
     697             :   Healpix_Ordering_Scheme scheme)
     698             :   {
     699          29 :   planck_assert ((order>=0)&&(order<=order_max), "bad order");
     700          29 :   order_  = order;
     701          29 :   nside_  = I(1)<<order;
     702          29 :   npface_ = nside_<<order_;
     703          29 :   ncap_   = (npface_-nside_)<<1;
     704          29 :   npix_   = 12*npface_;
     705          29 :   fact2_  = 4./npix_;
     706          29 :   fact1_  = (nside_<<1)*fact2_;
     707          29 :   scheme_ = scheme;
     708          29 :   }
     709           0 : template<typename I> void T_Healpix_Base<I>::SetNside (I nside,
     710             :   Healpix_Ordering_Scheme scheme)
     711             :   {
     712           0 :   order_  = nside2order(nside);
     713           0 :   planck_assert ((scheme!=NEST) || (order_>=0),
     714             :     "SetNside: nside must be power of 2 for nested maps");
     715           0 :   nside_  = nside;
     716           0 :   npface_ = nside_*nside_;
     717           0 :   ncap_   = (npface_-nside_)<<1;
     718           0 :   npix_   = 12*npface_;
     719           0 :   fact2_  = 4./npix_;
     720           0 :   fact1_  = (nside_<<1)*fact2_;
     721           0 :   scheme_ = scheme;
     722           0 :   }
     723             : 
     724           0 : template<typename I> double T_Healpix_Base<I>::ring2z (I ring) const
     725             :   {
     726           0 :   if (ring<nside_)
     727           0 :     return 1 - ring*ring*fact2_;
     728           0 :   if (ring <=3*nside_)
     729           0 :     return (2*nside_-ring)*fact1_;
     730           0 :   ring=4*nside_ - ring;
     731           0 :   return ring*ring*fact2_ - 1;
     732             :   }
     733             : 
     734           0 : template<typename I> I T_Healpix_Base<I>::pix2ring (I pix) const
     735             :   {
     736           0 :   if (scheme_==RING)
     737             :     {
     738           0 :     if (pix<ncap_) // North Polar cap
     739           0 :       return (1+I(isqrt(1+2*pix)))>>1; // counted from North pole
     740           0 :     else if (pix<(npix_-ncap_)) // Equatorial region
     741           0 :       return (pix-ncap_)/(4*nside_) + nside_; // counted from North pole
     742             :     else // South Polar cap
     743           0 :       return 4*nside_-((1+I(isqrt(2*(npix_-pix)-1)))>>1);
     744             :     }
     745             :   else
     746             :     {
     747             :     int face_num, ix, iy;
     748           0 :     nest2xyf(pix,ix,iy,face_num);
     749           0 :     return (I(jrll[face_num])<<order_) - ix - iy - 1;
     750             :     }
     751             :   }
     752             : 
     753           0 : template<typename I> I T_Healpix_Base<I>::nest2ring (I pix) const
     754             :   {
     755           0 :   planck_assert(order_>=0, "hierarchical map required");
     756             :   int ix, iy, face_num;
     757           0 :   nest2xyf (pix, ix, iy, face_num);
     758           0 :   return xyf2ring (ix, iy, face_num);
     759             :   }
     760             : 
     761         421 : template<typename I> I T_Healpix_Base<I>::ring2nest (I pix) const
     762             :   {
     763         421 :   planck_assert(order_>=0, "hierarchical map required");
     764             :   int ix, iy, face_num;
     765         421 :   ring2xyf (pix, ix, iy, face_num);
     766         421 :   return xyf2nest (ix, iy, face_num);
     767             :   }
     768             : 
     769           0 : template<typename I> inline I T_Healpix_Base<I>::nest_peano_helper
     770             :   (I pix, int dir) const
     771             :   {
     772           0 :   int face = pix>>(2*order_);
     773             :   I result = 0;
     774           0 :   uint8 path = peano_face2path[dir][face];
     775             : 
     776           0 :   for (int shift=2*order_-2; shift>=0; shift-=2)
     777             :     {
     778           0 :     uint8 spix = uint8((pix>>shift) & 0x3);
     779           0 :     result <<= 2;
     780           0 :     result |= peano_subpix[dir][path][spix];
     781           0 :     path=peano_subpath[dir][path][spix];
     782             :     }
     783             : 
     784           0 :   return result + (I(peano_face2face[dir][face])<<(2*order_));
     785             :   }
     786             : 
     787           0 : template<typename I> I T_Healpix_Base<I>::nest2peano (I pix) const
     788           0 :   { return nest_peano_helper(pix,0); }
     789             : 
     790           0 : template<typename I> I T_Healpix_Base<I>::peano2nest (I pix) const
     791           0 :   { return nest_peano_helper(pix,1); }
     792             : 
     793       24585 : template<typename I> I T_Healpix_Base<I>::loc2pix (double z, double phi,
     794             :   double sth, bool have_sth) const
     795             :   {
     796             :   double za = abs(z);
     797       24585 :   double tt = fmodulo(phi*inv_halfpi,4.0); // in [0,4)
     798             : 
     799       24585 :   if (scheme_==RING)
     800             :     {
     801       24585 :     if (za<=twothird) // Equatorial region
     802             :       {
     803       16535 :       I nl4 = 4*nside_;
     804       16535 :       double temp1 = nside_*(0.5+tt);
     805       16535 :       double temp2 = nside_*z*0.75;
     806       16535 :       I jp = I(temp1-temp2); // index of  ascending edge line
     807       16535 :       I jm = I(temp1+temp2); // index of descending edge line
     808             : 
     809             :       // ring number counted from z=2/3
     810       16535 :       I ir = nside_ + 1 + jp - jm; // in {1,2n+1}
     811       16535 :       I kshift = 1-(ir&1); // kshift=1 if ir even, 0 otherwise
     812             : 
     813       16535 :       I t1 = jp+jm-nside_+kshift+1+nl4+nl4;
     814       16535 :       I ip = (order_>0) ?
     815       16535 :         (t1>>1)&(nl4-1) : ((t1>>1)%nl4); // in {0,4n-1}
     816             : 
     817       16535 :       return ncap_ + (ir-1)*nl4 + ip;
     818             :       }
     819             :     else  // North & South polar caps
     820             :       {
     821        8050 :       double tp = tt-I(tt);
     822        8050 :       double tmp = ((za<0.99)||(!have_sth)) ?
     823        7809 :                    nside_*sqrt(3*(1-za)) :
     824         241 :                    nside_*sth/sqrt((1.+za)/3.);
     825             : 
     826        8050 :       I jp = I(tp*tmp); // increasing edge line index
     827        8050 :       I jm = I((1.0-tp)*tmp); // decreasing edge line index
     828             : 
     829        8050 :       I ir = jp+jm+1; // ring number counted from the closest pole
     830        8050 :       I ip = I(tt*ir); // in {0,4*ir-1}
     831        8050 :       planck_assert((ip>=0)&&(ip<4*ir),"must not happen");
     832             :       //ip %= 4*ir;
     833             : 
     834        8050 :       return (z>0)  ?  2*ir*(ir-1) + ip  :  npix_ - 2*ir*(ir+1) + ip;
     835             :       }
     836             :     }
     837             :   else // scheme_ == NEST
     838             :     {
     839           0 :     if (za<=twothird) // Equatorial region
     840             :       {
     841           0 :       double temp1 = nside_*(0.5+tt);
     842           0 :       double temp2 = nside_*(z*0.75);
     843           0 :       I jp = I(temp1-temp2); // index of  ascending edge line
     844           0 :       I jm = I(temp1+temp2); // index of descending edge line
     845           0 :       I ifp = jp >> order_;  // in {0,4}
     846           0 :       I ifm = jm >> order_;
     847           0 :       int face_num = (ifp==ifm) ? (ifp|4) : ((ifp<ifm) ? ifp : (ifm+8));
     848             : 
     849           0 :       int ix = jm & (nside_-1),
     850           0 :           iy = nside_ - (jp & (nside_-1)) - 1;
     851           0 :       return xyf2nest(ix,iy,face_num);
     852             :       }
     853             :     else // polar region, za > 2/3
     854             :       {
     855           0 :       int ntt = min(3,int(tt));
     856           0 :       double tp = tt-ntt;
     857           0 :       double tmp = ((za<0.99)||(!have_sth)) ?
     858           0 :                    nside_*sqrt(3*(1-za)) :
     859           0 :                    nside_*sth/sqrt((1.+za)/3.);
     860             : 
     861           0 :       I jp = I(tp*tmp); // increasing edge line index
     862           0 :       I jm = I((1.0-tp)*tmp); // decreasing edge line index
     863           0 :       jp=min(jp,nside_-1); // for points too close to the boundary
     864           0 :       jm=min(jm,nside_-1);
     865           0 :       return (z>=0) ?
     866           0 :         xyf2nest(nside_-jm -1,nside_-jp-1,ntt) : xyf2nest(jp,jm,ntt+8);
     867             :       }
     868             :     }
     869             :   }
     870             : 
     871      135593 : template<typename I> void T_Healpix_Base<I>::pix2loc (I pix, double &z,
     872             :   double &phi, double &sth, bool &have_sth) const
     873             :   {
     874      135593 :   have_sth=false;
     875      135593 :   if (scheme_==RING)
     876             :     {
     877      135172 :     if (pix<ncap_) // North Polar cap
     878             :       {
     879       22080 :       I iring = (1+I(isqrt(1+2*pix)))>>1; // counted from North pole
     880       22080 :       I iphi  = (pix+1) - 2*iring*(iring-1);
     881             : 
     882       22080 :       double tmp=(iring*iring)*fact2_;
     883       22080 :       z = 1.0 - tmp;
     884       22080 :       if (z>0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; }
     885       22080 :       phi = (iphi-0.5) * halfpi/iring;
     886             :       }
     887      113092 :     else if (pix<(npix_-ncap_)) // Equatorial region
     888             :       {
     889       91010 :       I nl4 = 4*nside_;
     890       91010 :       I ip  = pix - ncap_;
     891       91010 :       I tmp = (order_>=0) ? ip>>(order_+2) : ip/nl4;
     892       91010 :       I iring = tmp + nside_,
     893       91010 :         iphi = ip-nl4*tmp+1;
     894             :       // 1 if iring+nside is odd, 1/2 otherwise
     895       91010 :       double fodd = ((iring+nside_)&1) ? 1 : 0.5;
     896             : 
     897       91010 :       z = (2*nside_-iring)*fact1_;
     898       91010 :       phi = (iphi-fodd) * pi*0.75*fact1_;
     899             :       }
     900             :     else // South Polar cap
     901             :       {
     902       22082 :       I ip = npix_ - pix;
     903       22082 :       I iring = (1+I(isqrt(2*ip-1)))>>1; // counted from South pole
     904       22082 :       I iphi  = 4*iring + 1 - (ip - 2*iring*(iring-1));
     905             : 
     906       22082 :       double tmp=(iring*iring)*fact2_;
     907       22082 :       z = tmp - 1.0;
     908       22082 :       if (z<-0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; }
     909       22082 :       phi = (iphi-0.5) * halfpi/iring;
     910             :       }
     911             :     }
     912             :   else
     913             :     {
     914             :     int face_num, ix, iy;
     915         421 :     nest2xyf(pix,ix,iy,face_num);
     916             : 
     917         421 :     I jr = (I(jrll[face_num])<<order_) - ix - iy - 1;
     918             : 
     919             :     I nr;
     920         421 :     if (jr<nside_)
     921             :       {
     922             :       nr = jr;
     923           0 :       double tmp=(nr*nr)*fact2_;
     924           0 :       z = 1 - tmp;
     925           0 :       if (z>0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; }
     926             :       }
     927         421 :     else if (jr > 3*nside_)
     928             :       {
     929           0 :       nr = nside_*4-jr;
     930           0 :       double tmp=(nr*nr)*fact2_;
     931           0 :       z = tmp - 1;
     932           0 :       if (z<-0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; }
     933             :       }
     934             :     else
     935             :       {
     936             :       nr = nside_;
     937         421 :       z = (2*nside_-jr)*fact1_;
     938             :       }
     939             : 
     940         421 :     I tmp=I(jpll[face_num])*nr+ix-iy;
     941         421 :     planck_assert(tmp<8*nr,"must not happen");
     942         421 :     if (tmp<0) tmp+=8*nr;
     943         421 :     phi = (nr==nside_) ? 0.75*halfpi*tmp*fact1_ :
     944           0 :                          (0.5*halfpi*tmp)/nr;
     945             :     }
     946      135593 :   }
     947             : 
     948             : template<typename I> template<typename I2>
     949           0 :   void T_Healpix_Base<I>::query_polygon_internal
     950             :   (const vector<pointing> &vertex, int fact, rangeset<I2> &pixset) const
     951             :   {
     952             :   bool inclusive = (fact!=0);
     953             :   tsize nv=vertex.size();
     954           0 :   tsize ncirc = inclusive ? nv+1 : nv;
     955           0 :   planck_assert(nv>=3,"not enough vertices in polygon");
     956             :   arr<vec3> vv(nv);
     957           0 :   for (tsize i=0; i<nv; ++i)
     958           0 :     vv[i]=vertex[i].to_vec3();
     959             :   arr<vec3> normal(ncirc);
     960             :   int flip=0;
     961           0 :   for (tsize i=0; i<nv; ++i)
     962             :     {
     963           0 :     normal[i]=crossprod(vv[i],vv[(i+1)%nv]);
     964           0 :     double hnd=dotprod(normal[i],vv[(i+2)%nv]);
     965           0 :     planck_assert(abs(hnd)>1e-10,"degenerate corner");
     966           0 :     if (i==0)
     967           0 :       flip = (hnd<0.) ? -1 : 1;
     968             :     else
     969           0 :       planck_assert(flip*hnd>0,"polygon is not convex");
     970           0 :     normal[i]*=flip/normal[i].Length();
     971             :     }
     972             :   arr<double> rad(ncirc,halfpi);
     973           0 :   if (inclusive)
     974             :     {
     975             :     double cosrad;
     976           0 :     find_enclosing_circle (vv, normal[nv], cosrad);
     977           0 :     rad[nv]=acos(cosrad);
     978             :     }
     979           0 :   query_multidisc(normal,rad,fact,pixset);
     980           0 :   }
     981             : 
     982           0 : template<typename I> void T_Healpix_Base<I>::query_polygon
     983             :   (const vector<pointing> &vertex, rangeset<I> &pixset) const
     984             :   {
     985           0 :   query_polygon_internal(vertex, 0, pixset);
     986           0 :   }
     987             : 
     988           0 : template<typename I> void T_Healpix_Base<I>::query_polygon_inclusive
     989             :   (const vector<pointing> &vertex, rangeset<I> &pixset, int fact) const
     990             :   {
     991           0 :   planck_assert(fact>0,"fact must be a positive integer");
     992           0 :   if ((sizeof(I)<8) && (((I(1)<<order_max)/nside_)<fact))
     993             :     {
     994           0 :     T_Healpix_Base<int64> base2(nside_,scheme_,SET_NSIDE);
     995           0 :     base2.query_polygon_internal(vertex,fact,pixset);
     996             :     return;
     997             :     }
     998           0 :   query_polygon_internal(vertex, fact, pixset);
     999             :   }
    1000             : 
    1001           0 : template<typename I> void T_Healpix_Base<I>::query_strip_internal
    1002             :   (double theta1, double theta2, bool inclusive, rangeset<I> &pixset) const
    1003             :   {
    1004           0 :   if (scheme_==RING)
    1005             :     {
    1006           0 :     I ring1 = max(I(1),1+ring_above(cos(theta1))),
    1007           0 :       ring2 = min(4*nside_-1,ring_above(cos(theta2)));
    1008           0 :     if (inclusive)
    1009             :       {
    1010           0 :       ring1 = max(I(1),ring1-1);
    1011           0 :       ring2 = min(4*nside_-1,ring2+1);
    1012             :       }
    1013             : 
    1014             :     I sp1,rp1,sp2,rp2;
    1015             :     bool dummy;
    1016           0 :     get_ring_info_small(ring1,sp1,rp1,dummy);
    1017           0 :     get_ring_info_small(ring2,sp2,rp2,dummy);
    1018           0 :     I pix1 = sp1,
    1019           0 :       pix2 = sp2+rp2;
    1020           0 :     if (pix1<=pix2) pixset.append(pix1,pix2);
    1021             :     }
    1022             :   else
    1023           0 :     planck_fail("query_strip not yet implemented for NESTED");
    1024           0 :   }
    1025             : 
    1026           0 : template<typename I> void T_Healpix_Base<I>::query_strip (double theta1,
    1027             :   double theta2, bool inclusive, rangeset<I> &pixset) const
    1028             :   {
    1029             :   pixset.clear();
    1030             : 
    1031           0 :   if (theta1<theta2)
    1032           0 :     query_strip_internal(theta1,theta2,inclusive,pixset);
    1033             :   else
    1034             :     {
    1035           0 :     query_strip_internal(0.,theta2,inclusive,pixset);
    1036             :     rangeset<I> ps2;
    1037           0 :     query_strip_internal(theta1,pi,inclusive,ps2);
    1038           0 :     pixset.append(ps2);
    1039             :     }
    1040           0 :   }
    1041             : 
    1042           0 : template<typename I> inline void T_Healpix_Base<I>::get_ring_info_small
    1043             :   (I ring, I &startpix, I &ringpix, bool &shifted) const
    1044             :   {
    1045           0 :   if (ring < nside_)
    1046             :     {
    1047           0 :     shifted = true;
    1048           0 :     ringpix = 4*ring;
    1049           0 :     startpix = 2*ring*(ring-1);
    1050             :     }
    1051           0 :   else if (ring < 3*nside_)
    1052             :     {
    1053           0 :     shifted = ((ring-nside_) & 1) == 0;
    1054           0 :     ringpix = 4*nside_;
    1055           0 :     startpix = ncap_ + (ring-nside_)*ringpix;
    1056             :     }
    1057             :   else
    1058             :     {
    1059           0 :     shifted = true;
    1060           0 :     I nr= 4*nside_-ring;
    1061           0 :     ringpix = 4*nr;
    1062           0 :     startpix = npix_-2*nr*(nr+1);
    1063             :     }
    1064           0 :   }
    1065             : 
    1066           0 : template<typename I> void T_Healpix_Base<I>::get_ring_info (I ring, I &startpix,
    1067             :   I &ringpix, double &costheta, double &sintheta, bool &shifted) const
    1068             :   {
    1069           0 :   I northring = (ring>2*nside_) ? 4*nside_-ring : ring;
    1070           0 :   if (northring < nside_)
    1071             :     {
    1072           0 :     double tmp = northring*northring*fact2_;
    1073           0 :     costheta = 1 - tmp;
    1074           0 :     sintheta = sqrt(tmp*(2-tmp));
    1075           0 :     ringpix = 4*northring;
    1076           0 :     shifted = true;
    1077           0 :     startpix = 2*northring*(northring-1);
    1078             :     }
    1079             :   else
    1080             :     {
    1081           0 :     costheta = (2*nside_-northring)*fact1_;
    1082           0 :     sintheta = sqrt((1+costheta)*(1-costheta));
    1083           0 :     ringpix = 4*nside_;
    1084           0 :     shifted = ((northring-nside_) & 1) == 0;
    1085           0 :     startpix = ncap_ + (northring-nside_)*ringpix;
    1086             :     }
    1087           0 :   if (northring != ring) // southern hemisphere
    1088             :     {
    1089           0 :     costheta = -costheta;
    1090           0 :     startpix = npix_ - startpix - ringpix;
    1091             :     }
    1092           0 :   }
    1093           0 : template<typename I> void T_Healpix_Base<I>::get_ring_info2 (I ring,
    1094             :   I &startpix, I &ringpix, double &theta, bool &shifted) const
    1095             :   {
    1096           0 :   I northring = (ring>2*nside_) ? 4*nside_-ring : ring;
    1097           0 :   if (northring < nside_)
    1098             :     {
    1099           0 :     double tmp = northring*northring*fact2_;
    1100           0 :     double costheta = 1 - tmp;
    1101           0 :     double sintheta = sqrt(tmp*(2-tmp));
    1102           0 :     theta = atan2(sintheta,costheta);
    1103           0 :     ringpix = 4*northring;
    1104           0 :     shifted = true;
    1105           0 :     startpix = 2*northring*(northring-1);
    1106             :     }
    1107             :   else
    1108             :     {
    1109           0 :     theta = acos((2*nside_-northring)*fact1_);
    1110           0 :     ringpix = 4*nside_;
    1111           0 :     shifted = ((northring-nside_) & 1) == 0;
    1112           0 :     startpix = ncap_ + (northring-nside_)*ringpix;
    1113             :     }
    1114           0 :   if (northring != ring) // southern hemisphere
    1115             :     {
    1116           0 :     theta = pi-theta;
    1117           0 :     startpix = npix_ - startpix - ringpix;
    1118             :     }
    1119           0 :   }
    1120             : 
    1121           0 : template<typename I> void T_Healpix_Base<I>::neighbors (I pix,
    1122             :   fix_arr<I,8> &result) const
    1123             :   {
    1124             :   int ix, iy, face_num;
    1125           0 :   (scheme_==RING) ?
    1126           0 :     ring2xyf(pix,ix,iy,face_num) : nest2xyf(pix,ix,iy,face_num);
    1127             : 
    1128           0 :   const I nsm1 = nside_-1;
    1129           0 :   if ((ix>0)&&(ix<nsm1)&&(iy>0)&&(iy<nsm1))
    1130             :     {
    1131           0 :     if (scheme_==RING)
    1132           0 :       for (int m=0; m<8; ++m)
    1133           0 :         result[m] = xyf2ring(ix+nb_xoffset[m],iy+nb_yoffset[m],face_num);
    1134             :     else
    1135             :       {
    1136           0 :       I fpix = I(face_num)<<(2*order_),
    1137           0 :         px0=spread_bits(ix  ), py0=spread_bits(iy  )<<1,
    1138           0 :         pxp=spread_bits(ix+1), pyp=spread_bits(iy+1)<<1,
    1139           0 :         pxm=spread_bits(ix-1), pym=spread_bits(iy-1)<<1;
    1140             : 
    1141           0 :       result[0] = fpix+pxm+py0; result[1] = fpix+pxm+pyp;
    1142           0 :       result[2] = fpix+px0+pyp; result[3] = fpix+pxp+pyp;
    1143           0 :       result[4] = fpix+pxp+py0; result[5] = fpix+pxp+pym;
    1144           0 :       result[6] = fpix+px0+pym; result[7] = fpix+pxm+pym;
    1145             :       }
    1146             :     }
    1147             :   else
    1148             :     {
    1149           0 :     for (int i=0; i<8; ++i)
    1150             :       {
    1151           0 :       int x=ix+nb_xoffset[i], y=iy+nb_yoffset[i];
    1152             :       int nbnum=4;
    1153           0 :       if (x<0)
    1154           0 :         { x+=nside_; nbnum-=1; }
    1155           0 :       else if (x>=nside_)
    1156           0 :         { x-=nside_; nbnum+=1; }
    1157           0 :       if (y<0)
    1158           0 :         { y+=nside_; nbnum-=3; }
    1159           0 :       else if (y>=nside_)
    1160           0 :         { y-=nside_; nbnum+=3; }
    1161             : 
    1162           0 :       int f = nb_facearray[nbnum][face_num];
    1163           0 :       if (f>=0)
    1164             :         {
    1165           0 :         int bits = nb_swaparray[nbnum][face_num>>2];
    1166           0 :         if (bits&1) x=nside_-x-1;
    1167           0 :         if (bits&2) y=nside_-y-1;
    1168           0 :         if (bits&4) std::swap(x,y);
    1169           0 :         result[i] = (scheme_==RING) ? xyf2ring(x,y,f) : xyf2nest(x,y,f);
    1170             :         }
    1171             :       else
    1172           0 :         result[i] = -1;
    1173             :       }
    1174             :     }
    1175           0 :   }
    1176             : 
    1177           0 : template<typename I> void T_Healpix_Base<I>::get_interpol (const pointing &ptg,
    1178             :   fix_arr<I,4> &pix, fix_arr<double,4> &wgt) const
    1179             :   {
    1180           0 :   planck_assert((ptg.theta>=0)&&(ptg.theta<=pi),"invalid theta value");
    1181           0 :   double z = cos (ptg.theta);
    1182           0 :   I ir1 = ring_above(z);
    1183           0 :   I ir2 = ir1+1;
    1184             :   double theta1, theta2, w1, tmp, dphi;
    1185             :   I sp,nr;
    1186             :   bool shift;
    1187             :   I i1,i2;
    1188           0 :   if (ir1>0)
    1189             :     {
    1190           0 :     get_ring_info2 (ir1, sp, nr, theta1, shift);
    1191           0 :     dphi = twopi/nr;
    1192           0 :     tmp = (ptg.phi/dphi - .5*shift);
    1193           0 :     i1 = (tmp<0) ? I(tmp)-1 : I(tmp);
    1194           0 :     w1 = (ptg.phi-(i1+.5*shift)*dphi)/dphi;
    1195           0 :     i2 = i1+1;
    1196           0 :     if (i1<0) i1 +=nr;
    1197           0 :     if (i2>=nr) i2 -=nr;
    1198           0 :     pix[0] = sp+i1; pix[1] = sp+i2;
    1199           0 :     wgt[0] = 1-w1; wgt[1] = w1;
    1200             :     }
    1201           0 :   if (ir2<(4*nside_))
    1202             :     {
    1203           0 :     get_ring_info2 (ir2, sp, nr, theta2, shift);
    1204           0 :     dphi = twopi/nr;
    1205           0 :     tmp = (ptg.phi/dphi - .5*shift);
    1206           0 :     i1 = (tmp<0) ? I(tmp)-1 : I(tmp);
    1207           0 :     w1 = (ptg.phi-(i1+.5*shift)*dphi)/dphi;
    1208           0 :     i2 = i1+1;
    1209           0 :     if (i1<0) i1 +=nr;
    1210           0 :     if (i2>=nr) i2 -=nr;
    1211           0 :     pix[2] = sp+i1; pix[3] = sp+i2;
    1212           0 :     wgt[2] = 1-w1; wgt[3] = w1;
    1213             :     }
    1214             : 
    1215           0 :   if (ir1==0)
    1216             :     {
    1217           0 :     double wtheta = ptg.theta/theta2;
    1218           0 :     wgt[2] *= wtheta; wgt[3] *= wtheta;
    1219           0 :     double fac = (1-wtheta)*0.25;
    1220           0 :     wgt[0] = fac; wgt[1] = fac; wgt[2] += fac; wgt[3] +=fac;
    1221           0 :     pix[0] = (pix[2]+2)&3;
    1222           0 :     pix[1] = (pix[3]+2)&3;
    1223             :     }
    1224           0 :   else if (ir2==4*nside_)
    1225             :     {
    1226           0 :     double wtheta = (ptg.theta-theta1)/(pi-theta1);
    1227           0 :     wgt[0] *= (1-wtheta); wgt[1] *= (1-wtheta);
    1228           0 :     double fac = wtheta*0.25;
    1229           0 :     wgt[0] += fac; wgt[1] += fac; wgt[2] = fac; wgt[3] =fac;
    1230           0 :     pix[2] = ((pix[0]+2)&3)+npix_-4;
    1231           0 :     pix[3] = ((pix[1]+2)&3)+npix_-4;
    1232             :     }
    1233             :   else
    1234             :     {
    1235           0 :     double wtheta = (ptg.theta-theta1)/(theta2-theta1);
    1236           0 :     wgt[0] *= (1-wtheta); wgt[1] *= (1-wtheta);
    1237           0 :     wgt[2] *= wtheta; wgt[3] *= wtheta;
    1238             :     }
    1239             : 
    1240           0 :   if (scheme_==NEST)
    1241           0 :     for (tsize m=0; m<pix.size(); ++m)
    1242           0 :       pix[m] = ring2nest(pix[m]);
    1243           0 :   }
    1244             : 
    1245           0 : template<typename I> void T_Healpix_Base<I>::swap (T_Healpix_Base &other)
    1246             :   {
    1247             :   std::swap(order_,other.order_);
    1248             :   std::swap(nside_,other.nside_);
    1249             :   std::swap(npface_,other.npface_);
    1250             :   std::swap(ncap_,other.ncap_);
    1251             :   std::swap(npix_,other.npix_);
    1252             :   std::swap(fact1_,other.fact1_);
    1253             :   std::swap(fact2_,other.fact2_);
    1254             :   std::swap(scheme_,other.scheme_);
    1255           0 :   }
    1256             : 
    1257           0 : template<typename I> double T_Healpix_Base<I>::max_pixrad() const
    1258             :   {
    1259             :   vec3 va,vb;
    1260           0 :   va.set_z_phi (2./3., pi/(4*nside_));
    1261           0 :   double t1 = 1.-1./nside_;
    1262           0 :   t1*=t1;
    1263           0 :   vb.set_z_phi (1-t1/3, 0);
    1264           0 :   return v_angle(va,vb);
    1265             :   }
    1266             : 
    1267           0 : template<typename I> double T_Healpix_Base<I>::max_pixrad(I ring) const
    1268             :   {
    1269           0 :   if (ring>=2*nside_) ring=4*nside_-ring;
    1270           0 :   double z=ring2z(ring), z_up=(ring>1) ? ring2z(ring-1) : 1.;
    1271             :   vec3 mypos, uppos;
    1272           0 :   uppos.set_z_phi(z_up,0);
    1273           0 :   if (ring<=nside_)
    1274             :     {
    1275           0 :     mypos.set_z_phi(z,pi/(4*ring));
    1276           0 :     return v_angle(mypos,uppos);
    1277             :     }
    1278           0 :   mypos.set_z_phi(z,0);
    1279           0 :   double vdist=v_angle(mypos,uppos);
    1280           0 :   double hdist=sqrt(1.-z*z)*pi/(4*nside_);
    1281           0 :   return max(hdist,vdist);
    1282             :   }
    1283             : 
    1284           0 : template<typename I> void T_Healpix_Base<I>::xyf2loc (double x, double y,
    1285             :   int face, double &z, double &phi, double &sth, bool &have_sth) const
    1286             :   {
    1287           0 :   have_sth = false;
    1288           0 :   double jr = jrll[face] - x - y;
    1289             :   double nr;
    1290           0 :   if (jr<1)
    1291             :     {
    1292             :     nr = jr;
    1293           0 :     double tmp = nr*nr/3.;
    1294           0 :     z = 1 - tmp;
    1295           0 :     if (z > 0.99)
    1296             :       {
    1297           0 :       sth = std::sqrt(tmp*(2.0-tmp));
    1298           0 :       have_sth = true;
    1299             :       }
    1300             :     }
    1301           0 :   else if (jr>3)
    1302             :     {
    1303           0 :     nr = 4-jr;
    1304           0 :     double tmp = nr*nr/3.;
    1305           0 :     z = tmp - 1;
    1306           0 :     if (z<-0.99)
    1307             :       {
    1308           0 :       sth = std::sqrt(tmp*(2.-tmp));
    1309           0 :       have_sth = true;
    1310             :       }
    1311             :     }
    1312             :   else
    1313             :     {
    1314             :     nr = 1;
    1315           0 :     z = (2-jr)*2./3.;
    1316             :     }
    1317             : 
    1318           0 :   double tmp=jpll[face]*nr+x-y;
    1319           0 :   if (tmp<0) tmp+=8;
    1320           0 :   if (tmp>=8) tmp-=8;
    1321           0 :   phi = (nr<1e-15) ? 0 : (0.5*halfpi*tmp)/nr;
    1322           0 :   }
    1323             : 
    1324             : namespace {
    1325             : 
    1326           0 : vec3 locToVec3 (double z, double phi, double sth, bool have_sth)
    1327             :   {
    1328           0 :   if (have_sth)
    1329           0 :     return vec3(sth*cos(phi),sth*sin(phi),z);
    1330             :   else
    1331             :     {
    1332             :     vec3 res;
    1333           0 :     res.set_z_phi (z, phi);
    1334           0 :     return res;
    1335             :     }
    1336             :   }
    1337             : 
    1338             : } // unnamed namespace
    1339             : 
    1340           0 : template<typename I> void T_Healpix_Base<I>::boundaries(I pix, tsize step,
    1341             :   vector<vec3> &out) const
    1342             :   {
    1343           0 :   out.resize(4*step);
    1344             :   int ix, iy, face;
    1345           0 :   pix2xyf(pix, ix, iy, face);
    1346           0 :   double dc = 0.5 / nside_;
    1347           0 :   double xc = (ix + 0.5)/nside_, yc = (iy + 0.5)/nside_;
    1348           0 :   double d = 1.0/(step*nside_);
    1349           0 :   for (tsize i=0; i<step; ++i)
    1350             :     {
    1351             :     double z, phi, sth;
    1352             :     bool have_sth;
    1353           0 :     xyf2loc(xc+dc-i*d, yc+dc, face, z, phi, sth, have_sth);
    1354           0 :     out[i] = locToVec3(z, phi, sth, have_sth);
    1355           0 :     xyf2loc(xc-dc, yc+dc-i*d, face, z, phi, sth, have_sth);
    1356           0 :     out[i+step] = locToVec3(z, phi, sth, have_sth);
    1357           0 :     xyf2loc(xc-dc+i*d, yc-dc, face, z, phi, sth, have_sth);
    1358           0 :     out[i+2*step] = locToVec3(z, phi, sth, have_sth);
    1359           0 :     xyf2loc(xc+dc, yc-dc+i*d, face, z, phi, sth, have_sth);
    1360           0 :     out[i+3*step] = locToVec3(z, phi, sth, have_sth);
    1361             :     }
    1362           0 :   }
    1363             : 
    1364           0 : template<typename I> arr<int> T_Healpix_Base<I>::swap_cycles() const
    1365             :   {
    1366           0 :   planck_assert(order_>=0, "need hierarchical map");
    1367           0 :   planck_assert(order_<=13, "map too large");
    1368           0 :   arr<int> result(swap_clen[order_]);
    1369             :   tsize ofs=0;
    1370           0 :   for (int m=0; m<order_;++m) ofs+=swap_clen[m];
    1371           0 :   for (tsize m=0; m<result.size();++m) result[m]=swap_cycle[m+ofs];
    1372           0 :   return result;
    1373             :   }
    1374             : 
    1375             : template class T_Healpix_Base<int>;
    1376             : template class T_Healpix_Base<int64>;
    1377             : } // namespace healpix
    1378             : 

Generated by: LCOV version 1.14