Healpix C++  3.83
moc_query.cc
Go to the documentation of this file.
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 /*! \file moc_query.cc
28  * Copyright (C) 2014-2015 Max-Planck-Society
29  * \author Martin Reinecke
30  */
31 
32 #include "moc_query.h"
33 #include "geom_utils.h"
34 #include "lsconstants.h"
35 
36 using namespace std;
37 
38 namespace {
39 
40 template<typename I> class queryHelper
41  {
42  private:
43  int order, omax;
44  bool inclusive;
45  vector<MocQueryComponent> comp;
46  vector<T_Healpix_Base<I> > base;
47  vector<int> shortcut;
48  arr<double> cr;
49  arr2<double> crmin;
50  arr2<double> crmax;
51 
52  vector<pair<I,int> > stk; // stack for pixel numbers and their orders
53  I pix;
54  int o;
55  int stacktop; // a place to save a stack position
56  vec3 pv;
57 
58  void check_pixel (int zone, Moc<I> &pixset)
59  {
60  if (zone==0) return;
61  if (o<order)
62  {
63  if (zone>=3)
64  pixset.appendPixel(o,pix); // output all subpixels
65  else // (zone>=1)
66  for (int i=0; i<4; ++i)
67  stk.push_back(make_pair(4*pix+3-i,o+1)); // add children
68  }
69  else if (o>order) // this implies that inclusive==true
70  {
71  if (zone>=2) // pixel center in shape
72  {
73  pixset.appendPixel(order,pix>>(2*(o-order))); // output parent pixel
74  stk.resize(stacktop); // unwind the stack
75  }
76  else // (zone>=1): pixel center in safety range
77  {
78  if (o<omax) // check sublevels
79  for (int i=0; i<4; ++i) // add children in reverse order
80  stk.push_back(make_pair(4*pix+3-i,o+1));
81  else // at resolution limit
82  {
83  pixset.appendPixel(order,pix>>(2*(o-order))); // output parent pixel
84  stk.resize(stacktop); // unwind the stack
85  }
86  }
87  }
88  else // o==order
89  {
90  if (zone>=2)
91  pixset.appendPixel(order,pix);
92  else if (inclusive) // and (zone>=1)
93  {
94  if (order<omax) // check sublevels
95  {
96  stacktop=stk.size(); // remember current stack position
97  for (int i=0; i<4; ++i) // add children in reverse order
98  stk.push_back(make_pair(4*pix+3-i,o+1));
99  }
100  else // at resolution limit
101  pixset.appendPixel(order,pix); // output the pixel
102  }
103  }
104  }
105 
106  void correctLoc(int &loc) const
107  {
108  int myloc=loc--;
109  planck_assert((myloc>=0)&&(myloc<int(comp.size())),"inconsistency");
110  for (int i=0; i<comp[myloc].nops; ++i)
111  correctLoc(loc);
112  }
113 
114  int getZone (int &loc, int zmin, int zmax) const
115  {
116  if (zmin==zmax) { loc=shortcut[loc]; return zmin; } // short-circuit
117  int myloc=loc--;
118 // planck_assert((myloc>=0)&&(myloc<int(comp.size())),"inconsistency");
119  switch (comp[myloc].op)
120  {
121  case AND:
122  {
123  int z1=zmax;
124  for (int i=0; i<comp[myloc].nops; ++i)
125  z1 = getZone(loc,zmin,z1);
126  return z1;
127  }
128  case OR:
129  {
130  int z1=zmin;
131  for (int i=0; i<comp[myloc].nops; ++i)
132  z1 = getZone(loc,z1,zmax);
133  return z1;
134  }
135  case XOR:
136  {
137  int z1=getZone(loc,0,3);
138  int z2=getZone(loc,0,3);
139  return max(zmin,min(zmax,max(min(z1,3-z2),min(3-z1,z2))));
140  }
141  case NOT:
142  return 3-getZone(loc,3-zmax,3-zmin);
143  case NONE:
144  {
145  int res=zmax;
146  double crad=dotprod(pv,comp[myloc].center);
147  if (crad<=crmax(o,myloc)) res=0;
148  else if (crad<=cr[myloc]) res=1;
149  else if (crad<=crmin(o,myloc)) res=2;
150  return max(zmin,min(zmax,res));
151  }
152  }
153  planck_fail("must not get here");
154  }
155 
156  public:
157  queryHelper (int order_, int omax_, bool inclusive_,
158  const vector<MocQueryComponent> &comp_)
159  : order(order_), omax(omax_), inclusive(inclusive_), comp(comp_),
160  base(omax+1), shortcut(comp.size()), cr(comp.size()),
161  crmin(omax+1,comp.size()), crmax(omax+1,comp.size())
162  {
163  planck_assert(comp.size()>=1,"bad query component vector");
164  planck_assert(order<=omax,"order>omax");
165  if (!inclusive) planck_assert(order==omax,"inconsistency");
166  planck_assert(omax<=T_Healpix_Base<I>::order_max,"omax too high");
167 
168  for (tsize i=0; i<comp.size(); ++i)
169  if (comp[i].op==NONE) // it's a cap
170  cr[i]=cos(comp[i].radius);
171  for (o=0; o<=omax; ++o) // prepare data at the required orders
172  {
173  base[o].Set(o,NEST);
174  double dr=base[o].max_pixrad(); // safety distance
175  for (tsize i=0; i<comp.size(); ++i)
176  if (comp[i].op==NONE) // it's a cap
177  {
178  crmax(o,i) = (comp[i].radius+dr>=pi) ? -1.01:cos(comp[i].radius+dr);
179  crmin(o,i) = (comp[i].radius-dr<=0.) ? 1.01:cos(comp[i].radius-dr);
180  }
181  }
182 
183  for (tsize i=0; i<comp.size(); ++i)
184  {
185  int loc=int(i);
186  correctLoc(loc);
187  shortcut[i]=loc;
188  }
189  }
190  Moc<I> result()
191  {
192  Moc<I> pixset;
193  stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation
194  for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order
195  stk.push_back(make_pair(I(11-i),0));
196 
197  stacktop=0; // a place to save a stack position
198 
199  while (!stk.empty()) // as long as there are pixels on the stack
200  {
201  // pop current pixel number and order from the stack
202  pix=stk.back().first;
203  o=stk.back().second;
204  stk.pop_back();
205  pv = base[o].pix2vec(pix);
206 
207  int loc=comp.size()-1;
208  tsize zone=getZone(loc,0,3);
209  check_pixel (zone, pixset);
210  planck_assert(loc==-1,"stack not used up");
211  }
212  return pixset;
213  }
214  };
215 
216 double isLeft (const vec3 &a, const vec3 &b, const vec3 &c)
217  { return dotprod(crossprod(a,b),c); }
218 
219 // adapted from code available at http://geomalgorithms.com/a12-_hull-3.html
220 // Original copyright notice follows:
221 // Copyright 2001 softSurfer, 2012 Dan Sunday
222 // This code may be freely used and modified for any purpose
223 // providing that this copyright notice is included with it.
224 // SoftSurfer makes no warranty for this code, and cannot be held
225 // liable for any real or imagined damage resulting from its use.
226 // Users of this code must verify correctness for their application.
227 vector<int> getHull (const vector<vec3> &vert, const vector<int> &P)
228  {
229  // initialize a deque D[] from bottom to top so that the
230  // 1st three vertices of P[] are a ccw triangle
231  int n = P.size();
232  arr<int> D(2*n+1);
233  int bot = n-2, top = bot+3; // initial bottom and top deque indices
234  D[bot] = D[top] = P[2]; // 3rd vertex is at both bot and top
235  if (isLeft(vert[P[0]], vert[P[1]], vert[P[2]]) > 0)
236  {
237  D[bot+1] = P[0];
238  D[bot+2] = P[1]; // ccw vertices are: 2,0,1,2
239  }
240  else
241  {
242  D[bot+1] = P[1];
243  D[bot+2] = P[0]; // ccw vertices are: 2,1,0,2
244  }
245 
246  // compute the hull on the deque D[]
247  for (int i=3; i<n; i++)
248  { // process the rest of vertices
249  // test if next vertex is inside the deque hull
250  if ((isLeft(vert[D[bot]], vert[D[bot+1]], vert[P[i]]) > 0) &&
251  (isLeft(vert[D[top-1]], vert[D[top]], vert[P[i]]) > 0) )
252  continue; // skip an interior vertex
253 
254  // incrementally add an exterior vertex to the deque hull
255  // get the rightmost tangent at the deque bot
256  while (isLeft(vert[D[bot]], vert[D[bot+1]], vert[P[i]]) <= 0)
257  ++bot; // remove bot of deque
258  D[--bot] = P[i]; // insert P[i] at bot of deque
259 
260  // get the leftmost tangent at the deque top
261  while (isLeft(vert[D[top-1]], vert[D[top]], vert[P[i]]) <= 0)
262  --top; // pop top of deque
263  D[++top] = P[i]; // push P[i] onto top of deque
264  }
265 
266  // transcribe deque D[] to the output hull array H[]
267  int nout = top-bot;
268  vector<int> res(nout);
269  for (int h=0; h<nout; h++)
270  res[h] = D[bot + h +1];
271 
272  return res;
273  }
274 
275 void prepPolyHelper (const vector<vec3> &vv, const vector<int> &P,
276  vector<MocQueryComponent> &comp, bool doLast)
277  {
278  vector<int> hull=getHull(vv,P);
279  vector<bool> addHull(hull.size());
280 
281  // sync both sequences at the first point of the convex hull
282  int ihull=0, ipoly=0, nhull=hull.size(), npoly=P.size();
283  while (hull[ihull]!=P[ipoly]) ++ipoly;
284 
285  // iterate over the pockets between the polygon and its convex hull
286  int npockets=0;
287  if (P.size()==3) // really P.size(), not vv.size()?
288  for (int i=0; i<3; i++) addHull[i]=true;
289  else
290  {
291  do
292  {
293  int ihull_next = (ihull+1)%nhull,
294  ipoly_next = (ipoly+1)%npoly;
295  if (hull[ihull_next]==P[ipoly_next]) // no pocket found
296  { addHull[ihull]=true; ihull=ihull_next; ipoly=ipoly_next; }
297  else // query pocket
298  {
299  int nvpocket=2; // number of vertices for this pocket
300  while (P[ipoly_next]!=hull[ihull_next])
301  {
302  ipoly_next = (ipoly_next+1)%npoly;
303  ++nvpocket;
304  }
305  vector<int> ppocket(nvpocket);
306  int idx=0;
307  int ipoly_bw=ipoly_next;
308  while (P[ipoly_bw]!=hull[ihull])
309  {
310  ppocket[idx++]=P[ipoly_bw];
311  ipoly_bw=(ipoly_bw+npoly-1)%npoly;
312  }
313  ppocket[idx]=hull[ihull];
314  // process pocket recursively
315  ++npockets;
316  prepPolyHelper (vv, ppocket, comp, false);
317  ihull=ihull_next;
318  ipoly=ipoly_next;
319  }
320  } while (ihull!=0);
321  }
322  if (npockets>1)
323  comp.push_back(MocQueryComponent(OR,npockets));
324  if (npockets>0)
325  comp.push_back(MocQueryComponent(NOT));
326 
327  if (!doLast)
328  addHull.back()=false;
329 
330  // add convex hull
331  for (tsize i=0; i<hull.size(); ++i)
332  if (addHull[i])
333  comp.push_back(MocQueryComponent
334  (crossprod(vv[hull[i]],vv[hull[(i+1)%hull.size()]]).Norm(),0.5*pi));
335 
336  int num_and = 0;
337  for (tsize i=0; i<hull.size(); ++i)
338  if (addHull[i]) ++num_and;
339  if (npockets>0) ++num_and;
340  if (num_and>1)
341  comp.push_back(MocQueryComponent(AND,num_and));
342  }
343 
344 } // unnamed namespace
345 
346 template<typename I> Moc<I> mocQuery (int order,
347  const vector<MocQueryComponent> &comp)
348  { return queryHelper<I>(order,order,false,comp).result(); }
349 template Moc<int> mocQuery (int order, const vector<MocQueryComponent> &comp);
350 template Moc<int64> mocQuery (int order, const vector<MocQueryComponent> &comp);
351 
352 template<typename I> Moc<I> mocQueryInclusive (int order, int omax,
353  const vector<MocQueryComponent> &comp)
354  { return queryHelper<I>(order,omax,true,comp).result(); }
355 template Moc<int> mocQueryInclusive (int order, int omax,
356  const vector<MocQueryComponent> &comp);
357 template Moc<int64> mocQueryInclusive (int order, int omax,
358  const vector<MocQueryComponent> &comp);
359 
360 vector<MocQueryComponent> prepPolygon (const vector<vec3> &vertex)
361  {
362  planck_assert(vertex.size()>=3,"not enough vertices in polygon");
363  vector<vec3> vv(vertex.size());
364  for (tsize i=0; i<vertex.size(); ++i)
365  vv[i]=vertex[i].Norm();
366 
367  vector<int> P(vv.size());
368  for (tsize i=0; i<P.size(); ++i)
369  P[i]=i;
370  vector<MocQueryComponent> comp;
371  prepPolyHelper(vv,P,comp,true);
372  return comp;
373  }

Generated on Wed Nov 13 2024 12:18:30 for Healpix C++