moc_query.cc

Go to the documentation of this file.
00001 /*
00002  *  This file is part of Healpix_cxx.
00003  *
00004  *  Healpix_cxx is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  Healpix_cxx is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with Healpix_cxx; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00017  *
00018  *  For more information about HEALPix, see http://healpix.sourceforge.net
00019  */
00020 
00021 /*
00022  *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
00023  *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
00024  *  (DLR).
00025  */
00026 
00027 /*! \file moc_query.cc
00028  *  Copyright (C) 2014-2015 Max-Planck-Society
00029  *  \author Martin Reinecke
00030  */
00031 
00032 #include "moc_query.h"
00033 #include "geom_utils.h"
00034 #include "lsconstants.h"
00035 
00036 using namespace std;
00037 
00038 namespace {
00039 
00040 template<typename I> class queryHelper
00041   {
00042   private:
00043     int order, omax;
00044     bool inclusive;
00045     vector<MocQueryComponent> comp;
00046     vector<T_Healpix_Base<I> > base;
00047     vector<int> shortcut;
00048     arr<double> cr;
00049     arr2<double> crmin;
00050     arr2<double> crmax;
00051 
00052     vector<pair<I,int> > stk; // stack for pixel numbers and their orders
00053     I pix;
00054     int o;
00055     int stacktop; // a place to save a stack position
00056     vec3 pv;
00057 
00058     void check_pixel (int zone, Moc<I> &pixset)
00059       {
00060       if (zone==0) return;
00061       if (o<order)
00062         {
00063         if (zone>=3)
00064           pixset.appendPixel(o,pix); // output all subpixels
00065         else // (zone>=1)
00066           for (int i=0; i<4; ++i)
00067             stk.push_back(make_pair(4*pix+3-i,o+1)); // add children
00068         }
00069       else if (o>order) // this implies that inclusive==true
00070         {
00071         if (zone>=2) // pixel center in shape
00072           {
00073           pixset.appendPixel(order,pix>>(2*(o-order))); // output parent pixel
00074           stk.resize(stacktop); // unwind the stack
00075           }
00076         else // (zone>=1): pixel center in safety range
00077           {
00078           if (o<omax) // check sublevels
00079             for (int i=0; i<4; ++i) // add children in reverse order
00080               stk.push_back(make_pair(4*pix+3-i,o+1));
00081           else // at resolution limit
00082             {
00083             pixset.appendPixel(order,pix>>(2*(o-order))); // output parent pixel
00084             stk.resize(stacktop); // unwind the stack
00085             }
00086           }
00087         }
00088       else // o==order
00089         {
00090         if (zone>=2)
00091           pixset.appendPixel(order,pix);
00092         else if (inclusive) // and (zone>=1)
00093           {
00094           if (order<omax) // check sublevels
00095             {
00096             stacktop=stk.size(); // remember current stack position
00097             for (int i=0; i<4; ++i) // add children in reverse order
00098               stk.push_back(make_pair(4*pix+3-i,o+1));
00099             }
00100           else // at resolution limit
00101             pixset.appendPixel(order,pix); // output the pixel
00102           }
00103         }
00104       }
00105 
00106     void correctLoc(int &loc) const
00107       {
00108       int myloc=loc--;
00109       planck_assert((myloc>=0)&&(myloc<int(comp.size())),"inconsistency");
00110       for (int i=0; i<comp[myloc].nops; ++i)
00111         correctLoc(loc);
00112       }
00113 
00114     int getZone (int &loc, int zmin, int zmax) const
00115       {
00116       if (zmin==zmax) { loc=shortcut[loc]; return zmin; } // short-circuit
00117       int myloc=loc--;
00118 //      planck_assert((myloc>=0)&&(myloc<int(comp.size())),"inconsistency");
00119       switch (comp[myloc].op)
00120         {
00121         case AND:
00122           {
00123           int z1=zmax;
00124           for (int i=0; i<comp[myloc].nops; ++i)
00125             z1 = getZone(loc,zmin,z1);
00126           return z1;
00127           }
00128         case OR:
00129           {
00130           int z1=zmin;
00131           for (int i=0; i<comp[myloc].nops; ++i)
00132             z1 = getZone(loc,z1,zmax);
00133           return z1;
00134           }
00135         case XOR:
00136           {
00137           int z1=getZone(loc,0,3);
00138           int z2=getZone(loc,0,3);
00139           return max(zmin,min(zmax,max(min(z1,3-z2),min(3-z1,z2))));
00140           }
00141         case NOT:
00142           return 3-getZone(loc,3-zmax,3-zmin);
00143         case NONE:
00144           {
00145           int res=zmax;
00146           double crad=dotprod(pv,comp[myloc].center);
00147           if (crad<=crmax(o,myloc)) res=0;
00148           else if (crad<=cr[myloc]) res=1;
00149           else if (crad<=crmin(o,myloc)) res=2;
00150           return max(zmin,min(zmax,res));
00151           }
00152         }
00153       planck_fail("must not get here");
00154       }
00155 
00156   public:
00157     queryHelper (int order_, int omax_, bool inclusive_,
00158       const vector<MocQueryComponent> &comp_)
00159       : order(order_), omax(omax_), inclusive(inclusive_), comp(comp_),
00160         base(omax+1), shortcut(comp.size()), cr(comp.size()),
00161         crmin(omax+1,comp.size()), crmax(omax+1,comp.size())
00162       {
00163       planck_assert(comp.size()>=1,"bad query component vector");
00164       planck_assert(order<=omax,"order>omax");
00165       if (!inclusive) planck_assert(order==omax,"inconsistency");
00166       planck_assert(omax<=T_Healpix_Base<I>::order_max,"omax too high");
00167 
00168       for (tsize i=0; i<comp.size(); ++i)
00169         if (comp[i].op==NONE) // it's a cap
00170           cr[i]=cos(comp[i].radius);
00171       for (o=0; o<=omax; ++o) // prepare data at the required orders
00172         {
00173         base[o].Set(o,NEST);
00174         double dr=base[o].max_pixrad(); // safety distance
00175         for (tsize i=0; i<comp.size(); ++i)
00176           if (comp[i].op==NONE) // it's a cap
00177             {
00178             crmax(o,i) = (comp[i].radius+dr>=pi) ? -1.01:cos(comp[i].radius+dr);
00179             crmin(o,i) = (comp[i].radius-dr<=0.) ?  1.01:cos(comp[i].radius-dr);
00180             }
00181         }
00182 
00183       for (tsize i=0; i<comp.size(); ++i)
00184         {
00185         int loc=int(i);
00186         correctLoc(loc);
00187         shortcut[i]=loc;
00188         }
00189       }
00190     Moc<I> result()
00191       {
00192       Moc<I> pixset;
00193       stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation
00194       for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order
00195         stk.push_back(make_pair(I(11-i),0));
00196 
00197       stacktop=0; // a place to save a stack position
00198 
00199       while (!stk.empty()) // as long as there are pixels on the stack
00200         {
00201         // pop current pixel number and order from the stack
00202         pix=stk.back().first;
00203         o=stk.back().second;
00204         stk.pop_back();
00205         pv = base[o].pix2vec(pix);
00206 
00207         int loc=comp.size()-1;
00208         tsize zone=getZone(loc,0,3);
00209         check_pixel (zone, pixset);
00210         planck_assert(loc==-1,"stack not used up");
00211         }
00212       return pixset;
00213       }
00214   };
00215 
00216 double isLeft (const vec3 &a, const vec3 &b, const vec3 &c)
00217   { return dotprod(crossprod(a,b),c); }
00218 
00219 // adapted from code available at http://geomalgorithms.com/a12-_hull-3.html
00220 // Original copyright notice follows:
00221 // Copyright 2001 softSurfer, 2012 Dan Sunday
00222 // This code may be freely used and modified for any purpose
00223 // providing that this copyright notice is included with it.
00224 // SoftSurfer makes no warranty for this code, and cannot be held
00225 // liable for any real or imagined damage resulting from its use.
00226 // Users of this code must verify correctness for their application.
00227 vector<int> getHull (const vector<vec3> &vert, const vector<int> &P)
00228   {
00229   // initialize a deque D[] from bottom to top so that the
00230   // 1st three vertices of P[] are a ccw triangle
00231   int n = P.size();
00232   arr<int> D(2*n+1);
00233   int bot = n-2, top = bot+3;    // initial bottom and top deque indices
00234   D[bot] = D[top] = P[2];      // 3rd vertex is at both bot and top
00235   if (isLeft(vert[P[0]], vert[P[1]], vert[P[2]]) > 0)
00236     {
00237     D[bot+1] = P[0];
00238     D[bot+2] = P[1];           // ccw vertices are: 2,0,1,2
00239     }
00240   else
00241     {
00242     D[bot+1] = P[1];
00243     D[bot+2] = P[0];           // ccw vertices are: 2,1,0,2
00244     }
00245 
00246   // compute the hull on the deque D[]
00247   for (int i=3; i<n; i++)
00248     {   // process the rest of vertices
00249     // test if next vertex is inside the deque hull
00250     if ((isLeft(vert[D[bot]], vert[D[bot+1]], vert[P[i]]) > 0) &&
00251         (isLeft(vert[D[top-1]], vert[D[top]], vert[P[i]]) > 0) )
00252       continue;         // skip an interior vertex
00253 
00254     // incrementally add an exterior vertex to the deque hull
00255     // get the rightmost tangent at the deque bot
00256     while (isLeft(vert[D[bot]], vert[D[bot+1]], vert[P[i]]) <= 0)
00257       ++bot;                 // remove bot of deque
00258     D[--bot] = P[i];         // insert P[i] at bot of deque
00259 
00260     // get the leftmost tangent at the deque top
00261     while (isLeft(vert[D[top-1]], vert[D[top]], vert[P[i]]) <= 0)
00262       --top;                 // pop top of deque
00263     D[++top] = P[i];         // push P[i] onto top of deque
00264     }
00265 
00266   // transcribe deque D[] to the output hull array H[]
00267   int nout = top-bot;
00268   vector<int> res(nout);
00269   for (int h=0; h<nout; h++)
00270     res[h] = D[bot + h +1];
00271 
00272   return res;
00273   }
00274 
00275 void prepPolyHelper (const vector<vec3> &vv, const vector<int> &P,
00276   vector<MocQueryComponent> &comp, bool doLast)
00277   {
00278   vector<int> hull=getHull(vv,P);
00279   vector<bool> addHull(hull.size());
00280 
00281   // sync both sequences at the first point of the convex hull
00282   int ihull=0, ipoly=0, nhull=hull.size(), npoly=P.size();
00283   while (hull[ihull]!=P[ipoly]) ++ipoly;
00284 
00285   // iterate over the pockets between the polygon and its convex hull
00286   int npockets=0;
00287   if (P.size()==3) // really P.size(), not vv.size()?
00288     for (int i=0; i<3; i++) addHull[i]=true;
00289   else
00290     {
00291     do
00292       {
00293       int ihull_next = (ihull+1)%nhull,
00294           ipoly_next = (ipoly+1)%npoly;
00295       if (hull[ihull_next]==P[ipoly_next]) // no pocket found
00296         { addHull[ihull]=true; ihull=ihull_next; ipoly=ipoly_next; }
00297       else // query pocket
00298         {
00299         int nvpocket=2; // number of vertices for this pocket
00300         while (P[ipoly_next]!=hull[ihull_next])
00301           {
00302           ipoly_next = (ipoly_next+1)%npoly;
00303           ++nvpocket;
00304           }
00305         vector<int> ppocket(nvpocket);
00306         int idx=0;
00307         int ipoly_bw=ipoly_next;
00308         while (P[ipoly_bw]!=hull[ihull])
00309           {
00310           ppocket[idx++]=P[ipoly_bw];
00311           ipoly_bw=(ipoly_bw+npoly-1)%npoly;
00312           }
00313         ppocket[idx]=hull[ihull];
00314         // process pocket recursively
00315         ++npockets;
00316         prepPolyHelper (vv, ppocket, comp, false);
00317         ihull=ihull_next;
00318         ipoly=ipoly_next;
00319         }
00320       } while (ihull!=0);
00321     }
00322   if (npockets>1) 
00323     comp.push_back(MocQueryComponent(OR,npockets));
00324   if (npockets>0) 
00325     comp.push_back(MocQueryComponent(NOT));
00326 
00327   if (!doLast)
00328     addHull.back()=false;
00329 
00330   // add convex hull
00331   for (tsize i=0; i<hull.size(); ++i)
00332     if (addHull[i])
00333       comp.push_back(MocQueryComponent
00334         (crossprod(vv[hull[i]],vv[hull[(i+1)%hull.size()]]).Norm(),0.5*pi));
00335 
00336   int num_and = 0;
00337   for (tsize i=0; i<hull.size(); ++i)
00338     if (addHull[i]) ++num_and;
00339   if (npockets>0) ++num_and;
00340   if (num_and>1) 
00341     comp.push_back(MocQueryComponent(AND,num_and));
00342   }
00343 
00344 } // unnamed namespace
00345 
00346 template<typename I> Moc<I> mocQuery (int order,
00347   const vector<MocQueryComponent> &comp)
00348   { return queryHelper<I>(order,order,false,comp).result(); }
00349 template Moc<int> mocQuery (int order, const vector<MocQueryComponent> &comp);
00350 template Moc<int64> mocQuery (int order, const vector<MocQueryComponent> &comp);
00351 
00352 template<typename I> Moc<I> mocQueryInclusive (int order, int omax,
00353   const vector<MocQueryComponent> &comp)
00354   { return queryHelper<I>(order,omax,true,comp).result(); }
00355 template Moc<int> mocQueryInclusive (int order, int omax,
00356   const vector<MocQueryComponent> &comp);
00357 template Moc<int64> mocQueryInclusive (int order, int omax,
00358   const vector<MocQueryComponent> &comp);
00359 
00360 vector<MocQueryComponent> prepPolygon (const vector<vec3> &vertex)
00361   {
00362   planck_assert(vertex.size()>=3,"not enough vertices in polygon");
00363   vector<vec3> vv(vertex.size());
00364   for (tsize i=0; i<vertex.size(); ++i)
00365     vv[i]=vertex[i].Norm();
00366 
00367   vector<int> P(vv.size());
00368   for (tsize i=0; i<P.size(); ++i)
00369     P[i]=i;
00370   vector<MocQueryComponent> comp;
00371   prepPolyHelper(vv,P,comp,true);
00372   return comp;
00373   }

Generated on Thu Oct 8 14:48:52 2015 for Healpix C++