1; ----------------------------------------------------------------------------- 2; 3; Copyright (C) 1997-2013 Krzysztof M. Gorski, Eric Hivon, Anthony J. Banday 4; 5; 6; 7; 8; 9; This file is part of HEALPix. 10; 11; HEALPix is free software; you can redistribute it and/or modify 12; it under the terms of the GNU General Public License as published by 13; the Free Software Foundation; either version 2 of the License, or 14; (at your option) any later version. 15; 16; HEALPix is distributed in the hope that it will be useful, 17; but WITHOUT ANY WARRANTY; without even the implied warranty of 18; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19; GNU General Public License for more details. 20; 21; You should have received a copy of the GNU General Public License 22; along with HEALPix; if not, write to the Free Software 23; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24; 25; For more information about HEALPix see http://healpix.sourceforge.net 26; 27; ----------------------------------------------------------------------------- 28pro intrs_intrv, d1, d2, di, ni 29;======================================================================= 30; computes the intersection di 31; of 2 intervals d1 (= [a1,b1]) and d2 (= [a2,b2]) 32; on the periodic domain ( = [A,B], where A and B are arbitrary) 33; ni is the resulting number of intervals (0,1, or 2) 34; 35; if a1<b1 then d1 = {x | a1 <= x <= b1} 36; if a1>b1 then d1 = {x | a1 <= x <= B U A <= x <= b1} 37;======================================================================= 38 39tr12 = (d1[0] lt d1[1]) 40tr21 = ~tr12 41tr34 = (d2[0] lt d2[1]) 42tr43 = ~tr34 43tr13 = (d1[0] lt d2[0]) 44tr31 = ~tr13 45tr24 = (d1[1] lt d2[1]) 46tr42 = ~tr24 47tr14 = (d1[0] lt d2[1]) 48tr32 = (d2[0] lt d1[1]) 49 50ik = -1 51dk = replicate(-1.0d9,4) 52 53 54if ((tr31 && tr14) || (tr43 && (tr31 || tr14))) then begin 55 ik ++ 56 dk[ik] = d1[0] ; a1 57endif 58if ((tr13 && tr32) || (tr21 && (tr13 || tr32))) then begin 59 ik ++ 60 dk[ik] = d2[0] ; a2 61endif 62if ((tr32 && tr24) || (tr43 && (tr32 || tr24))) then begin 63 ik ++ 64 dk[ik] = d1[1] ; b1 65endif 66if ((tr14 && tr42) || (tr21 && (tr14 || tr42))) then begin 67 ik ++ 68 dk[ik] = d2[1] ; b2 69endif 70 71 72di = replicate(0.0d0,4) 73nk = ik+1 74case nk of 75 0 : begin 76 ni = 0 77 end 78 2 : begin 79 ni = 1 80 di[0:1] = [ dk[0], dk[1] ] ; [a1,b1] or [a1,b2] or [a2,b1] or [a2,b2] 81 end 82 4 : begin 83 ni = 2 84 di[0:3] = [ dk[0], dk[3], dk[1], dk[2] ] ; [a1,b2] U [a2,b1] 85 end 86 else : begin 87 print, ik 88 print,dk 89 print,d1,d2 90 message,"error in intrs_intrv" 91 end 92endcase 93 94return 95end 96 97 98;=========================================================================== 99pro process_intervals, interval1, interval_list, interval_out, n_out 100 101interval_out = 0.0d0 102n_out = 0 103 104n_in = n_elements(interval_list)/2 105if (n_in gt 0) then begin 106 interval_out = dblarr(2*n_in+2) 107 for i_in =0, n_in-1 do begin 108 intrs_intrv, interval1, interval_list[2*i_in:2*i_in+1], tmp_list_out, n_tmp_out ; 0, 1 or 2 intervals 109 if (n_tmp_out gt 0) then begin 110 interval_out[2*n_out] = tmp_list_out[0:2*n_tmp_out-1] 111 n_out += n_tmp_out 112 endif 113 endfor 114 interval_out = (n_out gt 0) ? interval_out[0:2*n_out-1] : 0.0d0 115endif 116 117return 118end 119 120;=========================================================================== 121 122pro query_triangle, nside, v1, v2, v3, listpix, nlist, $ 123 help=help, $ 124 nested=nested, $ 125 inclusive=inclusive, $ 126 walltime=walltime ;, circle=circle 127;+ 128; NAME: 129; QUERY_TRIANGLE 130; 131; PURPOSE: 132; Returns the list of Healpix pixels enclose in a spherical triangles 133; defined by its 3 vertices 134; 135; CATEGORY: 136; 137; 138; 139; CALLING SEQUENCE: 140; query_triangle, Nside, V1, V2, V3, Listpix, Nlist [, /HELP, /NESTED, /INCLUSIVE, WALLTIME=] 141; 142; 143; INPUTS: 144; 145; Nside = Healpix resolution parameter (a power of 2) 146; 147; V1, V2, V3 = 3D vector location of the 3 triangle vertices 148; They do not need to be normalised to unity 149; 150; KEYWORD PARAMETERS: 151; 152; /HELP: prints this documentation header and exits 153; 154; /INCLUSIVE :0 by default, only the pixels whose center 155; lie in the triangle are listed on output 156; if set to 1, all pixels overlapping the triangle are output 157; 158; /NESTED :0 by default, the output list is in RING scheme 159; if set to 1, the output list is in NESTED scheme 160; 161; OUTPUTS: 162; 163; List_pix = list of pixel lying in the triangle 164; 165; Nlist = number of pixels in the list 166; 167; 168; OPTIONAL OUTPUTS: 169; WALLTIME= contains on output the wall clock time used by the routine [s] 170; 171; COMMON BLOCKS: 172; SIDE EFFECTS: 173; RESTRICTIONS: 174; PROCEDURE: 175; calls angulardistance, ring_num, ring2z, discphirange_at_z, in_ring, ring2nest 176; and process_intervals, intrs_intrv (included in this file). 177; 178; EXAMPLE: 179; query_triangle, 128, [1,0,0], [0,1,0], [0,0,1], listpix, nlist 180; will return the pixels contained in the octant (x,y,z)>0 181; 182; 183; MODIFICATION HISTORY: 184; 185; 186; v1.0, EH, Caltech, Aug-Sep-2002 : adapted from F90 code 187; v1.1, EH, IAP, Mar-2011: added walltime 188; v1.2, EH, IAP, Apr-2011: fewer spurious false positive pixels 189; (for squeezed triangles in inclusive mode) by requiring 190; pixels to be within a disc enclosing the triangle 191; 2012-01-14: systematically returns Listpix=[-1], Nlist=0 in case of problem 192;======================================================================= 193;- 194 195tstart = systime(1) 196routine = 'query_triangle' 197syntax = routine+', Nside, V1, V2, V3, Listpix [, Nlist, HELP=, NESTED=, INCLUSIVE=, WALLTIME=]' 198nlist = 0 & listpix = [-1] 199 200if keyword_set(help) then begin 201 doc_library,routine 202 return 203endif 204 205if (n_params() lt 5 or n_params() gt 6) then begin 206 print,syntax 207 return 208endif 209 210 211npix = nside2npix(nside) 212if (npix lt 0) then begin 213 message,"Invalid Nside = "+string(nside) 214endif 215lnside = long(nside) 216 217do_inclusive = keyword_set(inclusive) 218 219; normalize vectors 220vv = dblarr(3,3) 221vv[*,0] = v1 / sqrt(total(v1*v1, /double)) 222vv[*,1] = v2 / sqrt(total(v2*v2, /double)) 223vv[*,2] = v3 / sqrt(total(v3*v3, /double)) 224 225 226; determ = (vect1 X vect2) . vect3 227; determines the left(<0)/right(>0) handedness of the triangle 228determ = vv[0,0]*vv[1,1]*vv[2,2] + vv[0,1]*vv[1,2]*vv[2,0] + vv[0,2]*vv[1,0]*vv[2,1] $ 229 - vv[2,0]*vv[1,1]*vv[0,2] - vv[2,1]*vv[1,2]*vv[0,0] - vv[2,2]*vv[1,0]*vv[0,1] 230 231; scalar product of vertices vectors 232sprod = dblarr(3) 233sprod[0] = total(vv[*,1]*vv[*,2]) 234sprod[1] = total(vv[*,2]*vv[*,0]) 235sprod[2] = total(vv[*,0]*vv[*,1]) 236 237; vector orthogonal to the great circle containing the vertex doublet 238vo = dblarr(3,3) 239vo[0,0] = vect_prod( vv[*,1], vv[*,2]) 240vo[0,1] = vect_prod( vv[*,2], vv[*,0]) 241vo[0,2] = vect_prod( vv[*,0], vv[*,1]) 242vonorm = sqrt(total(vo^2, 1)) 243 244if (abs(determ) lt 1.d-20 || min(vonorm) lt 1.d-20) then begin 245 message,/info,' ************************************************************' 246 message,/info,' The triangle is degenerate (2 of the vertices are antipodal or degenerate)' 247 message,/info,' The query can not be performed ' 248 message,/info,' ************************************************************' 249 return 250endif 251sdet = (determ lt 0.d0) ? -1.d0 : 1.d0 ; = +1 or -1, the sign of determ 252; normalize the orthogonal vector 253for i=0,2 do vo[0,i] = vo[*,i] / vonorm[i] ;;;;SQRT(total(vo[*,i]^2)) 254 255; test presence of poles in the triangle 256zmax = -1.0d0 257zmin = 1.0d0 258testp = (vo[2,*] * sdet ge 0.0d0) ; north pole in each hemisphere 259if (total(testp) eq 3) then begin 260 zmax = 1.0d0 ; north pole in the triangle 261endif 262if (total(testp) eq 0) then begin 263 zmin = -1.0d0 ; south pole in the triangle 264endif 265 266; look for northernest and southernest points in the triangle 267; node(1,2) = vector of norm=1, in the plane defined by (1,2) and with z=0 268test1a = ((vv[2,2] - sprod[0] * vv[2,1]) ge 0.0d0) ; segment 2-3 : -vector(3) . node(2,3) 269test1b = ((vv[2,1] - sprod[0] * vv[2,2]) ge 0.0d0) ; vector(2) . node(2,3) 270test2a = ((vv[2,2] - sprod[1] * vv[2,0]) ge 0.0d0) ; segment 1-3 : -vector(3) . node(1,3) 271test2b = ((vv[2,0] - sprod[1] * vv[2,2]) ge 0.0d0) ; vector(1) . node(1,3) 272test3a = ((vv[2,1] - sprod[2] * vv[2,0]) ge 0.0d0) ; segment 1-2 : -vector(2) . node(1,2) 273test3b = ((vv[2,0] - sprod[2] * vv[2,1]) ge 0.0d0) ; vector(1) . node(1,2) 274 275; sin of theta for orthogonal vector 276sto = SQRT( (1.0d0-vo[2,*])*(1.0d0+vo[2,*]) ) 277 278; for each segment (=side of the triangle) the extrema are either 279; - the 2 vertices 280; - one of the vertices and a point within the segment 281 282; segment 2-3 283z1max = vv[2,1] 284z1min = vv[2,2] 285if ( test1a EQ test1b ) then begin 286 zz = sto[0] 287 if ((z1min+z1max) ge 0.0d0) then z1max = zz else z1min = -zz 288endif 289 290; segment 1-3 291z2max = vv[2,2] 292z2min = vv[2,0] 293if ( test2a EQ test2b ) then begin 294 zz = sto[1] 295 if ((z2min+z2max) ge 0.0d0) then z2max = zz else z2min = -zz 296endif 297 298; segment 1-2 299z3max = vv[2,0] 300z3min = vv[2,1] 301if ( test3a EQ test3b ) then begin 302 zz = sto[2] 303 if ((z3min+z3max) ge 0.0d0) then z3max = zz else z3min = -zz 304endif 305 306zmax = MAX([z1max, z2max, z3max, zmax]) 307zmin = MIN([z1min, z2min, z3min, zmin]) 308 309; if we are inclusive, move the upper point up, and the lower point down, by a half pixel size 310offset = 0.0d0 311sin_off = 0.0d0 312if (do_inclusive) then begin 313; offset = 1.36d0 * !DPI / (4.0d0*nside) 314 offset = fudge_query_radius(nside, 0.d0) 315 sin_off = sin(offset) 316 cos_off = cos(offset) 317; zmax = cos( acos(zmax) - offset) < 1.d0 318; zmin = cos( acos(zmin) + offset) > (-1.d0) 319 zmax = (cos_off * zmax + sin_off * sqrt(1.d0 - zmax^2)) < 1.d0 ;cos(theta_zmax-offset) 320 zmin = (cos_off * zmin - sin_off * sqrt(1.d0 - zmin^2)) > (-1.d0) ;cos(theta_zmin+offset) 321endif 322 323; northernmost and sourthernmost ring number 324irmin = ring_num(lnside, zmax) 325irmax = ring_num(lnside, zmin) 326 327; build list of phi range for disc containing triangle 328nz = irmax - irmin + 1 329help,nz,irmin,irmax,zmin,zmax 330izlist = irmin + lindgen(nz) ; list of rings 331zlist = ring2z(lnside, izlist) ; list of z 332if (do_inclusive) then begin 333; find one small circle containing all points, 334; increased by fudge offset in inclusive case 335 junk = min(sprod, longside) 336 lsp1 = (longside+1) mod 3 337 lsp2 = (longside+2) mod 3 338 vcenter = 0.5d0*(vv[*,lsp1] + vv[*,lsp2]) ; mid point of longest side 339 vcenter /= sqrt(total(vcenter^2)) 340 dd = angulardistance(vcenter, transpose(vv)) 341 radius_eff = max(dd) + offset 342 dphilist = discphirange_at_z (vcenter, radius_eff, zlist, phi0=phi0disc) ; phi range in each ring 343; print,'radius',radius_eff,offset 344; print,'vcenter',vcenter 345endif 346; -------- loop on the rings ------------------------- 347 348tgthi = -1.0d30 * vo[2,*] 349phi0i = replicate(0.0d0, 3) 350kk = where(sto gt 1.0d-10, nkk) 351if (nkk gt 0) then begin 352 tgthi[kk] = -vo[2,kk] / sto[kk] ; -cotan(theta_orth) 353 phi0i[kk] = ATAN(vo[1,kk],vo[0,kk]) 354endif 355 356; the triangle boundaries are geodesics : intersection of the sphere with plans going thru (0,0,0) 357; if we are inclusive, the boundaries are the intersecion of the sphere with plans pushed outward 358; by sin(offset) 359twopi = 2.0d0 * !DPI 360 361dom = dblarr(2,4) 362 363; create WORK array to collect list of pixels 364l64 = (nside gt 8192) 365nw = ceil(surface_triangle(vv[*,0], vv[*,1], vv[*,2]) / (4*!DPI) * npix * 1.4 + 12*nside, l64=l64) 366nw <= npix 367work = (l64) ? lon64arr(nw,/nozero) : lonarr(nw,/nozero) 368; 369nlist = 0 370for iz = irmin, irmax do begin 371 iz0 = iz - irmin 372 z = zlist[iz0] 373 374 ; computes the 3 intervals described by the 3 great circles 375 st = SQRT(1.0d0 - z*z) 376 tgth = z / st ; cotan(theta_ring) 377 dc = tgthi * tgth - sdet * sin_off / ((sto+1.d-30) * st) ; !!! sto is slightly offset to avoid division by 0 378 for j=0,2 do begin 379 if (dc[j]*sdet le -1.0d0) then begin ; the whole iso-latitude ring is on the right side of the great circle 380 dom[0:1, j] = [ 0.0d0, twopi ] 381 endif else if (dc[j]*sdet ge 1.0d0) then begin ; all on the wrong side 382 dom[0:1, j] = [ -1.000001d0, -1.0d0 ] * (j+1) *0.5d0 383 endif else begin ; some is good, some is bad 384 dom[0:1, j] = (phi0i[j] + ACOS(dc[j]) * sdet * [-1.0d0, 1.0d0] + twopi) MOD twopi 385 endelse 386 endfor 387 dom[0:1,3] = [ -1.000001d0, -1.0d0 ] * 2.d0 388 if (do_inclusive && dphilist[iz0] ge 0.d0) then dom[0:1,3] = (phi0disc + dphilist[iz0]*[-1.d0,1.d0] + twopi) mod twopi 389 390 391 ; identify the intersections (0,1,2 or 3) of the 3 intervals 392 ; ------------------------------------------------------- 393 ; start with the first 2 intervals 394 process_intervals, dom[0:1,1], dom[0:1,0], alldom, ndom ; ndom = 0, 1 or 2 395 if (ndom eq 0) then goto, empty 396 ; add the third interval 397 process_intervals, dom[0:1,2], alldom[0:2*ndom-1], alldom, ndom ; ndom = 0, 1, 2 or 3 398 if (ndom eq 0) then goto, empty 399 ; add the fourth interval in inclusive mode 400 if (do_inclusive) then begin 401 process_intervals, dom[0:1,3], alldom[0:2*ndom-1], alldom, ndom ; ndom = 0, 1, 2, 3 or 4 402 if (ndom eq 0) then goto, empty 403 endif 404 ;print,'alldom',alldom[0:2*ndom-1] 405 406 for idom=0,ndom-1 do begin 407 a_i = alldom[2*idom] 408 b_i = alldom[2*idom+1] 409 phi0 = (a_i + b_i) * 0.5d0 410 dphiring = (b_i - a_i) * 0.5d0 411 if (dphiring lt 0.0d0) then begin 412 phi0 = phi0 + !dpi 413 dphiring = dphiring + !dpi 414 endif 415 416 ; ------- finds pixels in the triangle on that ring --------- 417 listir=in_ring( lnside, iz, phi0, dphiring, nir) 418 ;print,'iz, phi0, dphiring', iz, phi0, dphiring, nir 419 420 ; ----------- merge pixel lists ----------- 421 if (nir gt 0) then begin 422 work[nlist] = listir 423 nlist = nlist + nir 424 endif 425 endfor 426empty: 427endfor ;----------------------------------------- 428 429if (nlist eq 0) then begin 430 listpix = [-1L] 431endif else begin 432 listpix = work[0:nlist-1] 433 if keyword_set(nested) then begin 434 ring2nest, nside, listpix, listpix 435 endif 436endelse 437 438walltime = systime(1) - tstart 439return 440end 441 442