// // GOESnav.java // /* This source file is part of the edu.wisc.ssec.mcidas package and is Copyright (C) 1998 - 2017 by Tom Whittaker, Tommy Jasmin, Tom Rink, Don Murray, James Kelly, Bill Hibbard, Dave Glowacki, Curtis Rueden and others. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package edu.wisc.ssec.mcidas; /** * Navigation class for GOES (GOES D-H) type nav. This code was modified * from the original FORTRAN code (nvxgoes.dlm) on the McIDAS system. It * only supports latitude/longitude to line/element transformations (LL) * and vice/versa. Transform to 'XYZ' not implemented. * @see <A HREF="http://www.ssec.wisc.edu/mcidas/doc/prog_man.html"> * McIDAS Programmer's Manual</A> * * @author Don Murray */ public final class GOESnav extends AREAnav { private boolean isEastPositive = true; // NAVCOM variables private int navday; private int lintot; private double deglin; private int ieltot; private double degele; private double spinra; private int ietimy; private int ietimh; private double semima; private double oeccen; private double orbinc; private double perhel; private double asnode; private double nopcln; private double declin; private double rascen; private double piclin; private double prerat; private double predir; private double pitch; private double yaw; private double roll; private double skew; // BETCOM variables private int iajust; private int ibtcon; private int negbet; private int iseang; // VASCOM variables private double scan1; private double time1; private double scan2; private double time2; // NAVINI variables private double emega; private double ab; private double asq; private double bsq; private double r; private double rsq; private double rdpdg; private int numsen; private double totlin; private double radlin; private double totele; private double radele; private double picele; private double cpitch; private double cyaw; private double croll; private double pskew; private double rfact; private double roasin; private double tmpscl; private double b11; private double b12; private double b13; private double b21; private double b22; private double b23; private double b31; private double b32; private double b33; private double gamma; private double gamdot; private double rotm11; private double rotm13; private double rotm21; private double rotm23; private double rotm31; private double rotm33; private double pictim; private double xref; private int iold = 0; // variables needed for satvec private double tdife; private double xmmc; private double epsiln; private double srome2; private double pz; private double py; private double px; private double qz; private double qy; private double qx; /** * Set up for the real math work. Must pass in the int array * of the GOES nav 'codicil'. * * @param iarr the nav block from the image file * @throws IllegalArgumentException * if the nav block is not a GOES type. */ public GOESnav (int[] iarr) throws IllegalArgumentException { /* No longer needed. Kept for consistency with nvxgoes.dlm if (ifunc != 1) { if (iarr[0] == XY ) itype = 1; if (iarr[0] == LL ) itype = 2; return; } */ if (iarr[0] != GOES ) throw new IllegalArgumentException("Invalid navigation type" + iarr[0]); int jday = iarr[1]; int jtime = iarr[2]; // INITIALIZE NAVCOM navday = jday%100000; if ( iarr[6] <= 0 && iarr[7] <= 0 && iarr[8] <= 0 && iarr[9] <= 0 && iarr[10] <= 0 && iarr[11] <= 0 ) { throw new IllegalArgumentException("Invalid orbital parameters"); } ietimy = icon1(iarr[4]); ietimh = 100*(iarr[5]/100) + Math.round(.6f*(iarr[5]%100)); semima = (float) (iarr[6])/100.0; oeccen = (float) (iarr[7])/1000000.0; orbinc = (float) (iarr[8])/1000.0; double xmeana = (float) (iarr[9])/1000.0; perhel = (float) (iarr[10])/1000.0; asnode = (float) (iarr[11])/1000.0; if (iarr[4] == 0) throw new IllegalArgumentException("Invalid orbit type"); //CALL EPOCH(IETIMY,IETIMH,SEMIMA,OECCEN,XMEANA); epoch(ietimy,ietimh,semima,oeccen,xmeana); declin = McIDASUtil.mcPackedIntegerToDouble(iarr[12]); rascen = McIDASUtil.mcPackedIntegerToDouble(iarr[13]); piclin = iarr[14]; if (iarr[14] >= 1000000) piclin = piclin/10000.; if (iarr[12] == 0 && iarr[13] == 0 && iarr[14] == 0) throw new IllegalArgumentException( "Invalid ascension/declination parameters"); // ADDED 9/83 TO SUPPORT FRACTIONAL VALUES FOR PICLIN; if (iarr[15] == 0) throw new IllegalArgumentException("Invalid spin period"); spinra = iarr[15]/1000.0; if(iarr[15] != 0 && spinra < 300.0) spinra = 60000.0/spinra; deglin = McIDASUtil.mcPackedIntegerToDouble(iarr[16]); lintot = iarr[17]; degele = McIDASUtil.mcPackedIntegerToDouble(iarr[18]); ieltot = iarr[19]; pitch = McIDASUtil.mcPackedIntegerToDouble(iarr[20]); yaw = McIDASUtil.mcPackedIntegerToDouble(iarr[21]); roll = McIDASUtil.mcPackedIntegerToDouble(iarr[22]); skew = iarr[28]/100000.0; if (iarr[28] == McIDASUtil.MCMISSING) skew = 0.; //-----INITIALIZE BETCOM iajust = iarr[24]; iseang = iarr[27]; ibtcon = 6289920; negbet = 3144960; //-----INITIALIZE NAVINI COMMON BLOCK emega = .26251617; ab = 40546851.22; asq = 40683833.48; bsq = 40410330.18; r = 6371.221; rsq = r*r; rdpdg = 1.745329252E-02; numsen = (lintot/100000)%100; if (numsen < 1) numsen = 1; totlin = numsen * (lintot%100000); radlin = rdpdg*deglin/(totlin-1.0); totele = ieltot; radele = rdpdg*degele/(totele-1.0); picele = (1.0+totele)/2.0; cpitch = rdpdg*pitch; cyaw = rdpdg*yaw; croll = rdpdg*roll; pskew = Math.atan2(skew, radlin/radele); double stp = Math.sin(cpitch); double ctp = Math.cos(cpitch); double sty = Math.sin(cyaw-pskew); double cty = Math.cos(cyaw-pskew); double str = Math.sin(croll); double ctr = Math.cos(croll); rotm11 = ctr*ctp; rotm13 = sty*str*ctp + cty*stp; rotm21 = -str; rotm23 = sty*ctr; rotm31 = -ctr*stp; rotm33 = cty*ctp - sty*str*stp; rfact = Math.pow(rotm31,2) + Math.pow(rotm33,2); roasin = Math.atan2(rotm31, rotm33); tmpscl = spinra/3600000.0; double dec = declin*rdpdg; double sindec = Math.sin(dec); double cosdec = Math.cos(dec); double ras = rascen*rdpdg; double sinras = Math.sin(ras); double cosras = Math.cos(ras); b11 = -sinras; b12 = cosras; b13 = 0.0; b21 = -sindec*cosras; b22 = -sindec*sinras; b23 = cosdec; b31 = cosdec*cosras; b32 = cosdec*sinras; b33 = sindec; //XREF=RAERAC(NAVDAY,0,0.0)*RDPDG double raha = McIDASUtil.timdif(74001, 0, navday, 0)*1.00273791/4.0 + 100.26467; double rac = raha%360.0; if (rac < 0) rac = rac + 360.0; xref = rac*rdpdg; //-----TIME-SPECIFIC PARAMETERS (INCL GAMMA) pictim = McIDASUtil.mcPackedIntegerToDouble(jtime); gamma = ((float) iarr[38])/100.; gamdot = ((float) iarr[39])/100.; //-----INITIALIZE VASCOM int iss = jday/100000; if ( (iss > 25 || iss == 12) && iarr[30] > 0) { // THIS SECTION DOES VAS BIRDS AND GMS // IT USES TIMES AND SCAN LINE FROM BETA RECORDS scan1 = (double) iarr[30]; time1 = McIDASUtil.mcPackedIntegerToDouble(iarr[31]); scan2 = (double) iarr[34]; time2 = McIDASUtil.mcPackedIntegerToDouble(iarr[35]); } else { // THIS SECTION DOES THE OLD GOES BIRDS scan1 = 1.0; time1 = McIDASUtil.mcPackedIntegerToDouble(jtime); scan2 = (double) (lintot%100000); time2 = time1 + scan2*tmpscl; } iold = 0; } /** converts from satellite coordinates to latitude/longitude * * @param linele array of line/element pairs. Where * linele[indexLine][] is a 'line' and * linele[indexEle][] is an element. These are in * 'file' coordinates (not "image" coordinates.) * * @return latlon[][] array of lat/long pairs. Output array is * latlon[indexLat][] of latitudes and * latlon[indexLon][] of longitudes. * */ public float[][] toLatLon(float[][] linele) { int ilin; double parlin; double framet; double samtim; double xlin; double xele; double ylin; double yele; double xcor; double ycor; double rot; double coslin; double sinlin; double cosele; double sinele; double eli; double emi; double eni; double temp; double elo; double emo; double eno; double basq; double onemsq; double aq; double bq; double cq; double rad; double s; double x; double y; double z; double ct; double st; double x1; double y1; int number = linele[0].length; float[][] latlon = new float[2][number]; // Convert array to Image coordinates for computations float[][] imglinele = areaCoordToImageCoord(linele); for (int point=0; point < number; point++) { xlin = imglinele[indexLine][point]; xele = imglinele[indexEle][point]; ilin = Math.round( (float) xlin); parlin = (ilin - 1)/numsen + 1; framet = tmpscl*parlin; samtim = framet + pictim; double xyz[] = satvec(samtim); ylin = (xlin - piclin) * radlin; yele = (xele - picele + gamma + gamdot*samtim)*radele; xcor = b11*xyz[0] + b12*xyz[1] + b13*xyz[2]; ycor = b21*xyz[0] + b22*xyz[1] + b23*xyz[2]; rot = Math.atan2(ycor, xcor) + Math.PI; yele = yele - rot; coslin = Math.cos(ylin); sinlin = Math.sin(ylin); sinele = Math.sin(yele); cosele = Math.cos(yele); eli = rotm11*coslin - rotm13*sinlin; emi = rotm21*coslin - rotm23*sinlin; eni = rotm31*coslin - rotm33*sinlin; temp = eli; eli = cosele*eli + sinele*emi; emi = -sinele*temp + cosele*emi; elo = b11*eli + b21*emi + b31*eni; emo = b12*eli + b22*emi + b32*eni; eno = b13*eli + b23*emi + b33*eni; basq = bsq/asq; onemsq = 1.0 - basq; aq = basq + onemsq*Math.pow(eno,2); bq = 2.0 * ((elo*xyz[0] + emo*xyz[1])*basq + eno*xyz[2]); cq = (Math.pow(xyz[0],2) + Math.pow(xyz[1],2))*basq + Math.pow(xyz[2],2) - bsq; rad = Math.pow(bq,2) - 4.0*aq*cq; if (rad < 1.0) { latlon[indexLat][point] = Float.NaN; latlon[indexLon][point] = Float.NaN; } else { s = -(bq + Math.sqrt(rad))/(2.0*aq); x = xyz[0] + elo*s; y = xyz[1] + emo*s; z = xyz[2] + eno*s; ct = Math.cos(emega*samtim+xref); st = Math.sin(emega*samtim+xref); x1 = ct*x + st*y; y1 = -st*x + ct*y; double ll[] = nxyzll(x1, y1, z); latlon[indexLat][point] = (float) ll[0]; // put longitude into East Positive (form) latlon[indexLon][point] = (isEastPositive) ? (float)-ll[1] : (float)ll[1]; } } // end point for loop return latlon; } public double[][] toLatLon(double[][] linele) { int ilin; double parlin; double framet; double samtim; double xlin; double xele; double ylin; double yele; double xcor; double ycor; double rot; double coslin; double sinlin; double cosele; double sinele; double eli; double emi; double eni; double temp; double elo; double emo; double eno; double basq; double onemsq; double aq; double bq; double cq; double rad; double s; double x; double y; double z; double ct; double st; double x1; double y1; int number = linele[0].length; double[][] latlon = new double[2][number]; // Convert array to Image coordinates for computations double[][] imglinele = areaCoordToImageCoord(linele); for (int point=0; point < number; point++) { xlin = imglinele[indexLine][point]; xele = imglinele[indexEle][point]; ilin = Math.round( (float) xlin); parlin = (ilin - 1)/numsen + 1; framet = tmpscl*parlin; samtim = framet + pictim; double xyz[] = satvec(samtim); ylin = (xlin - piclin) * radlin; yele = (xele - picele + gamma + gamdot*samtim)*radele; xcor = b11*xyz[0] + b12*xyz[1] + b13*xyz[2]; ycor = b21*xyz[0] + b22*xyz[1] + b23*xyz[2]; rot = Math.atan2(ycor, xcor) + Math.PI; yele = yele - rot; coslin = Math.cos(ylin); sinlin = Math.sin(ylin); sinele = Math.sin(yele); cosele = Math.cos(yele); eli = rotm11*coslin - rotm13*sinlin; emi = rotm21*coslin - rotm23*sinlin; eni = rotm31*coslin - rotm33*sinlin; temp = eli; eli = cosele*eli + sinele*emi; emi = -sinele*temp + cosele*emi; elo = b11*eli + b21*emi + b31*eni; emo = b12*eli + b22*emi + b32*eni; eno = b13*eli + b23*emi + b33*eni; basq = bsq/asq; onemsq = 1.0 - basq; aq = basq + onemsq*Math.pow(eno,2); bq = 2.0 * ((elo*xyz[0] + emo*xyz[1])*basq + eno*xyz[2]); cq = (Math.pow(xyz[0],2) + Math.pow(xyz[1],2))*basq + Math.pow(xyz[2],2) - bsq; rad = Math.pow(bq,2) - 4.0*aq*cq; if (rad < 1.0) { latlon[indexLat][point] = Double.NaN; latlon[indexLon][point] = Double.NaN; } else { s = -(bq + Math.sqrt(rad))/(2.0*aq); x = xyz[0] + elo*s; y = xyz[1] + emo*s; z = xyz[2] + eno*s; ct = Math.cos(emega*samtim+xref); st = Math.sin(emega*samtim+xref); x1 = ct*x + st*y; y1 = -st*x + ct*y; double ll[] = nxyzll(x1, y1, z); latlon[indexLat][point] = ll[0]; // put longitude into East Positive (form) latlon[indexLon][point] = (isEastPositive) ? -ll[1] : ll[1]; } } // end point for loop return latlon; } /** * toLinEle converts lat/long to satellite line/element * * @param latlon array of lat/long pairs. Where latlon[indexLat][] * are latitudes and latlon[indexLon][] are longitudes. * * @return linele[][] array of line/element pairs. Where * linele[indexLine][] is a line and linele[indexEle][] * is an element. These are in 'file' coordinates * (not "image" coordinates); */ public float[][] toLinEle(float[][] latlon) { double xpar; double ypar; double xlin; double xele; double x1; double y1; double samtim; double ct; double st; double x; double y; double z; double xht; double vcste1; double vcste2; double vcste3; double vcses1; double vcses2; double vcses3; double oldlin; double orbtim; double xsat; double ysat; double zsat; double xnorm; double ynorm; double znorm; double umv; double x3; double xyzsat[] = new double[3]; int number = latlon[0].length; float[][] linele = new float[2][number]; for (int point=0; point < number; point++) { xpar = latlon[indexLat][point]; // expects positive West Longitude. ypar = isEastPositive ? -latlon[indexLon][point] : latlon[indexLon][point]; xlin = Double.NaN; xele = Double.NaN; if (Math.abs(xpar) <= 90.) { // initialize some variables oldlin = 910.; orbtim = -99999.; xsat = ysat = zsat = 0.0; x = y = z = 0.0; xht = znorm = 0.0; double xyz[] = nllxyz(xpar, ypar); x1 = xyz[0]; y1 = xyz[1]; z = xyz[2]; samtim = time1; for (int i = 0; i < 2; i++) { if (Math.abs(samtim - orbtim) >= 0.0005) { xyzsat = satvec(samtim); xsat = xyzsat[0]; ysat = xyzsat[1]; zsat = xyzsat[2]; orbtim = samtim; xht = Math.sqrt(Math.pow(xyzsat[0],2) + Math.pow(xyzsat[1],2) + Math.pow(xyzsat[2],2)); } ct = Math.cos(emega*samtim + xref); st = Math.sin(emega*samtim + xref); x = ct*x1 - st*y1; y = st*x1 + ct*y1; vcste1 = x - xsat; vcste2 = y - ysat; vcste3 = z - zsat; vcses3 = b31*vcste1 + b32*vcste2 + b33*vcste3; znorm = Math.sqrt(Math.pow(vcste1,2) + Math.pow(vcste2,2) + Math.pow(vcste3,2)); x3 = vcses3/znorm; umv = Math.atan2(x3,Math.sqrt(rfact - Math.pow(x3,2))) - roasin; xlin = piclin - umv/radlin; if (i == 0) { samtim = time2; oldlin = xlin; } } double scnnum = ( (double) (oldlin + xlin)/2.0 - 1.0)/numsen; double scnfrc = (scnnum - scan1)/(scan2 - scan1); xlin = oldlin + scnfrc*(xlin - oldlin); samtim = time1 + tmpscl*(scnnum - scan1); xyzsat = satvec(samtim); xsat = xyzsat[0]; ysat = xyzsat[1]; zsat = xyzsat[2]; double cosa = x*xsat + y*ysat + z*zsat; double ctst = 0.0001*r*xht + rsq; if (cosa >= ctst) { double xsats1 = b11*xsat + b12*ysat + b13*zsat; double ysats2 = b21*xsat + b22*ysat + b23*zsat; ct = Math.cos(emega*samtim + xref); st = Math.sin(emega*samtim + xref); x = ct*x1 - st*y1; y = st*x1 + ct*y1; vcste1 = x - xsat; vcste2 = y - ysat; vcste3 = z - zsat; vcses1 = b11*vcste1 + b12*vcste2 + b13*vcste3; vcses2 = b21*vcste1 + b22*vcste2 + b23*vcste3; vcses3 = b31*vcste1 + b32*vcste2 + b33*vcste3; xnorm = Math.sqrt(Math.pow(znorm,2) - Math.pow(vcses3,2)); ynorm = Math.sqrt(Math.pow(xsats1,2) + Math.pow(ysats2,2)); znorm = Math.sqrt(Math.pow(vcste1,2) + Math.pow(vcste2,2) + Math.pow(vcste3,2)); x3 = vcses3/znorm; umv = Math.atan2(x3,Math.sqrt(rfact - Math.pow(x3,2))) - roasin; double slin = Math.sin(umv); double clin = Math.cos(umv); double u = rotm11*clin + rotm13*slin; double v = rotm21*clin + rotm23*slin; xele = picele + Math.asin( (xsats1*vcses2 - ysats2*vcses1)/(xnorm*ynorm))/radele; xele = xele + Math.atan2(v,u)/radele; xele = xele-gamma-gamdot*samtim; } } linele[indexLine][point] = (float)xlin; linele[indexEle][point] = (float)xele; } // end point loop // Return in 'File' coordinates return imageCoordToAreaCoord(linele, linele); } public double[][] toLinEle(double[][] latlon) { double xpar; double ypar; double zpar; double xlin; double xele; double xdum; double x1; double y1; double samtim; double ct; double st; double x; double y; double z; double xht; double parlin; double vcste1; double vcste2; double vcste3; double vcses1; double vcses2; double vcses3; double oldlin; double orbtim; double xsat; double ysat; double zsat; double xnorm; double ynorm; double znorm; double umv; double x3; double xyzsat[] = new double[3]; int number = latlon[0].length; double[][] linele = new double[2][number]; for (int point=0; point < number; point++) { xpar = latlon[indexLat][point]; // expects positive West Longitude. ypar = isEastPositive ? -latlon[indexLon][point] : latlon[indexLon][point]; xlin = Double.NaN; xele = Double.NaN; if (Math.abs(xpar) <= 90.) { // initialize some variables oldlin = 910.; orbtim = -99999.; xsat = ysat = zsat = 0.0; x = y = z = 0.0; xht = znorm = 0.0; double xyz[] = nllxyz(xpar, ypar); x1 = xyz[0]; y1 = xyz[1]; z = xyz[2]; xdum = 0.0; samtim = time1; for (int i = 0; i < 2; i++) { if (Math.abs(samtim - orbtim) >= 0.0005) { xyzsat = satvec(samtim); xsat = xyzsat[0]; ysat = xyzsat[1]; zsat = xyzsat[2]; orbtim = samtim; xht = Math.sqrt(Math.pow(xyzsat[0],2) + Math.pow(xyzsat[1],2) + Math.pow(xyzsat[2],2)); } ct = Math.cos(emega*samtim + xref); st = Math.sin(emega*samtim + xref); x = ct*x1 - st*y1; y = st*x1 + ct*y1; vcste1 = x - xsat; vcste2 = y - ysat; vcste3 = z - zsat; vcses3 = b31*vcste1 + b32*vcste2 + b33*vcste3; znorm = Math.sqrt(Math.pow(vcste1,2) + Math.pow(vcste2,2) + Math.pow(vcste3,2)); x3 = vcses3/znorm; umv = Math.atan2(x3,Math.sqrt(rfact - Math.pow(x3,2))) - roasin; xlin = piclin - umv/radlin; parlin = (double) (xlin - 1.0)/numsen; if (i == 0) { samtim = time2; oldlin = xlin; } } double scnnum = ( (double) (oldlin + xlin)/2.0 - 1.0)/numsen; double scnfrc = (scnnum - scan1)/(scan2 - scan1); xlin = oldlin + scnfrc*(xlin - oldlin); samtim = time1 + tmpscl*(scnnum - scan1); xyzsat = satvec(samtim); xsat = xyzsat[0]; ysat = xyzsat[1]; zsat = xyzsat[2]; double cosa = x*xsat + y*ysat + z*zsat; double ctst = 0.0001*r*xht + rsq; if (cosa >= ctst) { double xsats1 = b11*xsat + b12*ysat + b13*zsat; double ysats2 = b21*xsat + b22*ysat + b23*zsat; ct = Math.cos(emega*samtim + xref); st = Math.sin(emega*samtim + xref); x = ct*x1 - st*y1; y = st*x1 + ct*y1; vcste1 = x - xsat; vcste2 = y - ysat; vcste3 = z - zsat; vcses1 = b11*vcste1 + b12*vcste2 + b13*vcste3; vcses2 = b21*vcste1 + b22*vcste2 + b23*vcste3; vcses3 = b31*vcste1 + b32*vcste2 + b33*vcste3; xnorm = Math.sqrt(Math.pow(znorm,2) - Math.pow(vcses3,2)); ynorm = Math.sqrt(Math.pow(xsats1,2) + Math.pow(ysats2,2)); znorm = Math.sqrt(Math.pow(vcste1,2) + Math.pow(vcste2,2) + Math.pow(vcste3,2)); x3 = vcses3/znorm; umv = Math.atan2(x3,Math.sqrt(rfact - Math.pow(x3,2))) - roasin; double slin = Math.sin(umv); double clin = Math.cos(umv); double u = rotm11*clin + rotm13*slin; double v = rotm21*clin + rotm23*slin; xele = picele + Math.asin( (xsats1*vcses2 - ysats2*vcses1)/(xnorm*ynorm))/radele; xele = xele + Math.atan2(v,u)/radele; xele = xele-gamma-gamdot*samtim; } } linele[indexLine][point] = xlin; linele[indexEle][point] = xele; } // end point loop // Return in 'File' coordinates return imageCoordToAreaCoord(linele, linele); } private int icon1(int yymmdd) { /* C $ FUNCTION ICON1 (YYMMDD) C $ CONVERTS YYMMDD TO YEAR-DAY (YYDDD) C $ YYMMDD = (I) INPUT DATE TO BE CONVERTED C $$ ICON1 = CONVERT, DATE */ int num[] = {0,31,59,90,120,151,181,212,243,273,304,334}; int year = (yymmdd/10000)%100; int month = (yymmdd/100)%100; int day = yymmdd%100; if (month < 0 || month > 12) month = 1; int julday = day + num[month - 1]; if (year%4 == 0 && month > 2) julday = julday + 1; return (1000*year + julday); } private void epoch(int ietimy, int ietimh, double semima, double oeccen, double xmeana) { double RDPDG = Math.PI/180.; double RE = 6378.388; double GRACON = 0.07436574; double axmmc = GRACON*Math.pow(Math.sqrt(RE/semima),3); double xmanom = RDPDG*xmeana; double time = (xmanom-oeccen*Math.sin(xmanom))/(60.0*axmmc); double time1 = McIDASUtil.mcPackedIntegerToDouble(ietimh); time = time1 - time; int iday = 0; if (time > 48.0) { time = time - 48.0; iday = 2; } else if (time > 24.0) { time = time - 24.0; iday = 1; } else if (time < -24.0) { time = time + 48.0; iday = -2; } else if (time < 0.0) { time = time + 24.0; iday = -1; } this.ietimh = McIDASUtil.mcDoubleToPackedInteger(time); if (iday != 0) { int jyear = (ietimy/1000)%100; // add 1000 so year will not go under zero jyear = jyear + 1000; int jday = ietimy%1000; jday = jday + iday; if (jday < 1) { jyear = jyear - 1; jday = leapyr(jyear) + jday; } else { int jtot = leapyr(jyear); if (jday > jtot) { jyear = jyear + 1; jday = jday + jtot; } } jyear = jyear%100; this.ietimy = 1000*jyear + jday; } } // End EPOCH /* helper method for epoch */ private int leapyr(int iy) { return 366-( (iy%4) + 3)/4; } /* SUBROUTINE NLLXYZ(XLAT,XLON,X,Y,Z) CONVERT LAT,LON TO EARTH CENTERED X,Y,Z (DALY, 1978) XLAT,XLON ARE IN DEGREES, WITH NORTH AND WEST POSITIVE X,Y,Z ARE GIVEN IN KM. THEY ARE THE COORDINATES IN A RECTANGULAR FRAME WITH ORIGIN AT THE EARTH CENTER, WHOSE POSITIVE X-AXIS PIERCES THE EQUATOR AT LON 0 DEG, WHOSE POSITIVE Y-AXIS PIERCES THE EQUATOR AT LON 90 DEG, AND WHOSE POSITIVE Z-AXIS INTERSECTS THE NORTH POLE. */ private double[] nllxyz(double xlat, double xlon) { double ylat = rdpdg*xlat; ylat = Math.atan2(bsq*Math.sin(ylat), asq*Math.cos(ylat)); double ylon = -rdpdg*xlon; double snlt = Math.sin(ylat); double cslt = Math.cos(ylat); double csln = Math.cos(ylon); double snln = Math.sin(ylon); double tnlt = Math.pow((snlt/cslt),2); double r = ab*Math.sqrt((1.0+tnlt)/(bsq+asq*tnlt)); double x = r*cslt*csln; double y = r*cslt*snln; double z = r*snlt; return new double[] {x, y, z}; } /* SUBROUTINE NXYZLL(X,Y,Z,XLAT,XLON) CONVERT EARTH-CENTERED X,Y,Z TO LAT & LON X,Y,Z ARE GIVEN IN KM. THEY ARE THE COORDINATES IN A RECTANGULAR COORDINATE SYSTEM WITH ORIGIN AT THE EARTH CENTER, WHOSE POS. X-AXIS PIERCES THE EQUATOR AT LON 0 DEG, WHOSE POSITIVE Y-AXIS PIERCES THE EQUATOR AT LON 90 DEG, AND WHOSE POSITIVE Z-AXIS INTERSECTS THE NORTH POLE. XLAT,XLON ARE IN DEGREES, WITH NORTH AND WEST POSITIVE */ private double[] nxyzll(double x, double y, double z) { double xlat; double xlon; xlat = Double.NaN; xlon = Double.NaN; if (x != 0.0 && y != 0.0 && z != 0.0) { double a = Math.atan(z/Math.sqrt(x*x + y*y)); xlat = Math.atan2(asq*Math.sin(a), bsq*Math.cos(a))/rdpdg; xlon = -Math.atan2(y,x)/rdpdg; } return new double[] {xlat, xlon}; } /* C SATVEC PHILLI 0880 NAVLIB COMPUTES EARTH SATELLITE AS FUNCTION OF TIM C VECTOR EARTH-CENTER-TO-SAT (FUNC OF TIME) */ private double[] satvec(double samtim) { if (iold != 1) { iold = 1; double rdpdg = Math.PI/180.0; double re = 6378.388; double gracon = .07436574; double sha = 100.26467; sha = rdpdg*sha; int irayd = 74001; int irahms = 0; double o = rdpdg*orbinc; double p = rdpdg*perhel; double a = rdpdg*asnode; double so = Math.sin(o); double co = Math.cos(o); double sp = Math.sin(p)*semima; double cp = Math.cos(p)*semima; double sa = Math.sin(a); double ca = Math.cos(a); px = cp*ca - sp*sa*co; py = cp*sa + sp*ca*co; pz = sp*so; qx = -sp*ca - cp*sa*co; qy = -sp*sa + cp*ca*co; qz = cp*so; srome2 = Math.sqrt(1.0 - oeccen) * Math.sqrt(1.0 + oeccen); xmmc = gracon*re*Math.sqrt(re/semima)/semima; int iey = (ietimy/1000)%100; int ied = ietimy%1000; int iefac = (iey-1)/4 + 1; double de = 365*(iey-1) + iefac + ied - 1; double te = 1440.0*de + 60.0*McIDASUtil.mcPackedIntegerToDouble(ietimh); int iray = irayd/1000; int irad = irayd%1000; int irafac = (iray-1)/4 + 1; double dra = 365*(iray-1) + irafac + irad -1; double tra = 1440.0*dra + 60.0*McIDASUtil.mcPackedIntegerToDouble(irahms); int inavy = (navday/1000)%100; int inavd = navday%1000; int infac = (inavy-1)/4 + 1; double dnav = 365*(inavy-1) + infac + inavd -1; tdife = dnav*1440. - te; double tdifra = dnav*1440. - tra; epsiln = 1.0E-8; } double timsam = samtim*60.0; double diftim = tdife + timsam; double xmanom = xmmc*diftim; double ecanm1 = xmanom; double ecanom = 0; int i = 0; for (i = 0; i < 20; i++) { ecanom = xmanom + oeccen*Math.sin(ecanm1); if (Math.abs(ecanom-ecanm1) < epsiln) break; ecanm1 = ecanom; } double xomega = Math.cos(ecanom) - oeccen; double yomega = srome2*Math.sin(ecanom); double z = xomega*pz + yomega*qz; double y = xomega*py + yomega*qy; double x = xomega*px + yomega*qx; return new double[] {x, y, z}; } /** Get the lat,lon of the subpoint if available * * @return double[2] {lat, lon} * */ public double[] getSubpoint() { double samtim; double[] xyzsat; double ct; double st; double x; double y; double z; double x1; double y1; double ssp_lat; double ssp_lon; samtim = time1; xyzsat = satvec(samtim); ct = Math.cos(emega*samtim+xref); st = Math.sin(emega*samtim+xref); x = xyzsat[0]; y = xyzsat[1]; z = xyzsat[2]; x1 = ct*x + st*y; y1 = -st*x + ct*y; double ll[] = nxyzll(x1, y1, z); ssp_lat = ll[0]; ssp_lon = (isEastPositive) ? -ll[1] : ll[1]; return new double[] {ssp_lat, ssp_lon}; } }