//
// 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};
}
}