;+ ; ; @file_comments ; Return the distance in meter between all np0 points P0 and all ; np1 points P1 on a sphere. If keyword /TWO_BY_TWO is given then ; returns the distances between number n of P0 points and number ; n of P1 points (in that case, np0 and np1 must be equal). ; Same as MAP_2POINTS with the meter parameter but for n ; points without do loop. ; ; @categories ; Maps ; ; @param Lon0 {in}{required} ; @param Lat0 {in}{required} ; np0 elements vector. longitudes and latitudes of np0 points P0 ; ; @param Lon1 {in}{required} ; @param Lat1 {in}{required} ; np1 elements vector. longitude and latitude of np1 points P1 ; ; @keyword AZIMUTH ; A named variable that will receive the azimuth of the great ; circle connecting the two points, P0 to P1 ; ; @keyword MIDDLE ; to get the longitude/latitude of the middle point between P0 and P1. ; ; @keyword RADIANS ; if set, inputs and angular outputs are in radians, otherwise degrees. ; ; @keyword RADIUS {default=6378206.4d0} ; If given, return the distance between the two points calculated using the ; given radius. ; Default value is the Earth radius. ; ; @keyword TWO_BY_TWO ; If given, then map_npoints returns the distances between ; number n of P0 points and number n of P1 pointsi. ; In that case, np0 and np1 must be equal. ; ; @returns ; An (np0,np1) array giving the distance in meter between np0 ; points P0 and np1 points P1. Element (i,j) of the output is the ; distance between element P0[i] and P1[j]. ; If keyword /TWO_BY_TWO is given then map_npoints returns ; an np-elements vector giving the distance in meter between P0[i] ; and P1[i] (in that case, we have np0 = np1 = np) ; if /MIDDLE see this keyword. ; @examples ; IDL> print, $ ; IDL> map_npoints([-105.15,1],[40.02,1],[-0.07,100,50],[51.30,20,0]) ; 7551369.3 5600334.8 ; 12864354. 10921254. ; 14919237. 5455558.8 ; ; IDL> lon0 = [-10, 20, 100] ; IDL> lat0 = [0, -10, 45] ; IDL> lon1 = [10, 60, 280] ; IDL> lat1 = [0, 10, 45] ; IDL> dist = map_npoints(lon0, lat0, lon1, lat1, AZIMUTH = azi) ; IDL> help, dist, azi ; DIST DOUBLE = Array[3, 3] ; AZI DOUBLE = Array[3, 3] ; IDL> print, dist[4*lindgen(3)], azi[4*lindgen(3)] ; 2226414.0 4957944.5 10018863. ; 90.000000 64.494450 4.9615627e-15 ; IDL> dist = map_npoints(lon0, lat0, lon1, lat1, AZIMUTH = azi, /TWO_BY_TWO) ; IDL> help, dist, azi ; DIST DOUBLE = Array[3] ; AZI DOUBLE = Array[3] ; IDL> print, dist, azi ; 2226414.0 4957944.5 10018863. ; 90.000000 64.494450 4.9615627e-15 ; IDL> print, map_2points(lon0[0], lat0[0], lon1[0], lat1[0]) ; 20.000000 90.000000 ; IDL> print, map_npoints(lon0[0], lat0[0], lon1[0], lat1[0], AZIMUTH=azi)/6378206.4d0 / !dtor, azi ; 20.000000 ; 90.000000 ; ; IDL> lon0 = [-10, 20, 100] ; IDL> lat0 = [0, -10, 45] ; IDL> lon1 = [10, 60, 280] ; IDL> lat1 = [0, 10, 45] ; IDL> mid = map_npoints(lon0, lat0, lon1, lat1, /MIDDLE, /TWO_BY_TWO) ; IDL> print, reform(mid[0,*]), reform(mid[1,*]) ; 0.0000000 40.000000 190.00000 ; 0.0000000 -1.5902773e-15 90.000000 ; IDL> print, (map_2points(lon0[0], lat0[0], lon1[0], lat1[0], npath = 3))[*, 1] ; 0.0000000 0.0000000 ; IDL> print, (map_2points(lon0[1], lat0[1], lon1[1], lat1[1], npath = 3))[*, 1] ; 40.000000 -1.5902773e-15 ; IDL> print, (map_2points(lon0[2], lat0[2], lon1[2], lat1[2], npath = 3))[*, 1] ; 190.00000 90.000000 ; ; @history ; Based on the IDL function map_2points.pro,v 1.6 2001/01/15 ; Sebastien Masson (smasson\@lodyc.jussieu.fr) ; October 2003 ; ; @version ; $Id$ ; ;- FUNCTION map_npoints, lon0, lat0, lon1, lat1, AZIMUTH=azimuth $ , RADIANS=radians, RADIUS=radius, MIDDLE=middle $ , TWO_BY_TWO=two_by_two ; compile_opt idl2, strictarrsubs ; IF (N_PARAMS() LT 4) THEN $ ras = report('Incorrect number of arguments.') np0 = n_elements(lon0) IF n_elements(lat0) NE np0 THEN $ ras = report('lon0 and lat0 must have the same number of elements') np1 = n_elements(lon1) IF n_elements(lat1) NE np1 THEN $ ras = report('lon1 and lat1 must have the same number of elements') if keyword_set(two_by_two) AND np0 NE np1 then $ ras = report('When using two_by_two keyword, P0 and P1 must have the same number of elements') mx = MAX(ABS([lat0[*], lat1[*]])) pi2 = !dpi/2 IF (mx GT (KEYWORD_SET(radians) ? pi2 : 90)) THEN $ ras = report('Value of Latitude is out of allowed range.') k = KEYWORD_SET(radians) ? 1.0d0 : !dpi/180.0 ;Earth equatorial radius, meters, Clarke 1866 ellipsoid r_sphere = n_elements(RADIUS) NE 0 ? RADIUS : 6378206.4d0 ; coslt1 = cos(k*lat1[*]) sinlt1 = sin(k*lat1[*]) coslt0 = cos(k*lat0[*]) sinlt0 = sin(k*lat0[*]) ; IF np0 EQ np1 AND np1 EQ 1 THEN two_by_two = 1 ; if NOT keyword_set(two_by_two) THEN BEGIN coslt1 = replicate(1.0d0, np0)#temporary(coslt1) sinlt1 = replicate(1.0d0, np0)#temporary(sinlt1) coslt0 = temporary(coslt0)#replicate(1.0d0, np1) sinlt0 = temporary(sinlt0)#replicate(1.0d0, np1) ENDIF ; if keyword_set(two_by_two) THEN BEGIN cosl0l1 = cos(k*(lon1[*]-lon0[*])) sinl0l1 = sin(k*(lon1[*]-lon0[*])) ENDIF ELSE BEGIN cosl0l1 = cos(k*(replicate(1.0d0, np0)#lon1[*]-lon0[*]#replicate(1.0d0, np1))) sinl0l1 = sin(k*(replicate(1.0d0, np0)#lon1[*]-lon0[*]#replicate(1.0d0, np1))) ENDELSE cosc = sinlt0 * sinlt1 + coslt0 * coslt1 * cosl0l1 ;Cos of angle between pnts ; Avoid roundoff problems by clamping cosine range to [-1,1]. cosc = -1.0d0 > cosc < 1.0d0 ; if arg_present(azimuth) OR keyword_set(middle) then begin sinc = sqrt(1.0d0 - cosc*cosc) bad = where(abs(sinc) le 1.0e-7) IF bad[0] NE -1 THEN sinc[bad] = 1 cosaz = (coslt0 * sinlt1 - sinlt0*coslt1*cosl0l1) / sinc sinaz = sinl0l1*coslt1/sinc IF bad[0] NE -1 THEN BEGIN sinc[bad] = 0.0d0 sinaz[bad] = 0.0d0 cosaz[bad] = 1.0d0 ENDIF ENDIF ; IF keyword_set(middle) then BEGIN s0 = 0.5d0 * acos(cosc) ; coss = cos(s0) sins = sin(s0) ; lats = asin(sinlt0 * coss + coslt0 * sins * cosaz) / k lons = atan(sins * sinaz, coslt0 * coss - sinlt0 * sins * cosaz) / k ; if keyword_set(two_by_two) THEN BEGIN return, transpose([[lon0[*] + lons], [lats]]) ENDIF ELSE BEGIN return, [ [[lon0[*]#replicate(1.0d0, np1) + lons]], [[lats]] ] ENDELSE ; ENDIF ; if arg_present(azimuth) then begin azimuth = atan(sinaz, cosaz) IF k NE 1.0d0 THEN azimuth = temporary(azimuth) / k ENDIF return, acos(cosc) * r_sphere ; end