subroutine rotate (glt, gln, phir, thetar, psir, rlt, rln) c c double precision translator for drotate c c real glt, gln, phir, thetar, psir, rlt, rln real*8 dglt, dgln, dphir, dthetar, dpsir, drlt, drln c dglt = glt dgln = gln dphir = phir dthetar = thetar dpsir = psir drlt = rlt drln = rln call drotate (dglt, dgln, dphir, dthetar, dpsir, drlt, drln) rlt = drlt rln = drln c return end subroutine drotate (glt, gln, phir, thetar, psir, rlt, rln) c c======================================================================= c subroutine drotate takes a geographic latitude and longitude and c finds the the equivalent latitude and longitude on a rotated grid. c when going from a geographic grid to a rotated grid, all of the c defined rotation angles given to drotate by the calling program c are positive, but when going from a rotated grid back to the c geographic grid, the calling program must reverse the angle order c (phir and psir are switched) and all of the angles made negative. c c the first rotation angle phir is defined as a rotation about the c original z axis. the second rotation angle thetar is defined as a c rotation about the new x axis. the final rotation angle psir is c defined as a rotation about the new z axis. these rotation angles c are just the Euler angles as defined in "classical mechanics" c Goldstein (1951). c c author: M. Eby e-mail [email protected] c======================================================================= c c real*8 glt, gln, phir, thetar, psir, phis, thetas, rlt, rln &, gy, gx, gz, rx, ry, rz, d0, d1, d90, d180, d360, rad c c g... = geographic value c r... = rotated value c ...lt = latitude (or equivalent spherical coordinate) c ...ln = longitude (or equivalent spherical coordinate) c ...x = x coordinate c ...y = y coordinate c ...z = z coordinate c psir, thetar, phir = Euler angles defining rotation c d0 = 0.D+00 d1 = 1.D+00 d90 = 90.D+00 d180 = 180.D+00 d360 = 360.D+00 c c define rad for conversion to radians. rad = acos(-d1)/d180 c c convert latitude and longitude to spherical coordinates thetas = gln if (thetas .gt. d180) thetas = thetas - d360 if (thetas .lt. -d180) thetas = thetas + d360 thetas = thetas*rad phis = (d90 - glt)*rad c c translate point into Cartesian coordinates for rotation. gx = sin(phis)*cos(thetas) gy = sin(phis)*sin(thetas) gz = cos(phis) c c rotate the point (gx, gy, gz) about the z axis by phir then the x c axis by thetar and finally about the z axis by psir. c rx = gx*(cos(psir)*cos(phir) - cos(thetar)*sin(phir)*sin(psir)) + & gy*(cos(psir)*sin(phir) + cos(thetar)*cos(phir)*sin(psir)) + & gz*sin(psir)*sin(thetar) c ry = gx*(-sin(psir)*cos(phir) - cos(thetar)*sin(phir)*cos(psir)) + & gy*(-sin(psir)*sin(phir) + cos(thetar)*cos(phir)*cos(psir)) + & gz*(cos(psir)*sin(thetar)) c rz = gx*(sin(thetar)*sin(phir)) + gy*(-sin(thetar)*cos(phir)) + & gz*(cos(thetar)) c c convert rotated point back to spherical coordinates c c check for rounding error (arccos(x): abs(x) must be .le. 1) rz = min(rz, d1) rz = max(rz, -d1) rlt = acos(rz) c if point is at a pole set rotated longitude equal to initial. if (rlt .le. d0 .or. rlt .ge. d180*rad) then rln = thetas else c if rln lies between -135 and -45 or between 45 and 135 degrees c it is more accurate to use an arccos calculation. if (abs(rx/sin(rlt)) .lt. cos(45.D+00*rad)) then rln = acos(max(min(rx/sin(rlt), d1), -d1)) c arccos will give rln between 0 and 180 degrees. if the point c is negative in y, rln must be equal to negative rln. if (ry .lt. d0) rln = -rln else c if rln lies between -45 and 45 or between 135 and -135 degrees c it is more accurate to use an arcsin calculation. rln = asin(max(min(ry/sin(rlt), d1), -d1)) c arcsin will give rln between -90 and 90 degrees. if the point c is negative in x, rln must be equal to 180 degrees minus rln. if (rx .lt. d0) rln = d180*rad - rln endif endif c c convert back to degrees of latitude and longitude. rlt = d90 - rlt/rad rln = rln/rad if (rln .gt. d180) rln = rln - d360 if (rln .le. -d180) rln = rln + d360 return end