00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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;
00053 I pix;
00054 int o;
00055 int stacktop;
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);
00065 else
00066 for (int i=0; i<4; ++i)
00067 stk.push_back(make_pair(4*pix+3-i,o+1));
00068 }
00069 else if (o>order)
00070 {
00071 if (zone>=2)
00072 {
00073 pixset.appendPixel(order,pix>>(2*(o-order)));
00074 stk.resize(stacktop);
00075 }
00076 else
00077 {
00078 if (o<omax)
00079 for (int i=0; i<4; ++i)
00080 stk.push_back(make_pair(4*pix+3-i,o+1));
00081 else
00082 {
00083 pixset.appendPixel(order,pix>>(2*(o-order)));
00084 stk.resize(stacktop);
00085 }
00086 }
00087 }
00088 else
00089 {
00090 if (zone>=2)
00091 pixset.appendPixel(order,pix);
00092 else if (inclusive)
00093 {
00094 if (order<omax)
00095 {
00096 stacktop=stk.size();
00097 for (int i=0; i<4; ++i)
00098 stk.push_back(make_pair(4*pix+3-i,o+1));
00099 }
00100 else
00101 pixset.appendPixel(order,pix);
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; }
00117 int myloc=loc--;
00118
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 }