//
// GMSXnav.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;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.Math;
/**
* This class implements GMSX navigation. The code was modified
* from the original FORTRAN code (nvxgmsx.dlm) on the McIDAS system. It
* only supports latitude/longitude to line/element transformations (LL)
* and vice/versa. Transform to 'XYZ' not implemented.
* @see edu.wisc.ssec.mcidas.AREAnav
* @see <A HREF="http://www.ssec.wisc.edu/mcidas/doc/prog_man.html">
* McIDAS Programmer's Manual</A>
*
* @author Tommy Jasmin, University of Wisconsin, SSEC
*/
public class GMSXnav extends AREAnav
{
private static final long serialVersionUID = 1L;
private byte bParms[] = new byte[3200];
private float subLon;
private float subLat;
private float [] resLin = new float[4];
private float [] resEle = new float[4];
private float [] rlic = new float[4];
private float [] relmfc = new float[4];
private float [] senssu = new float[4];
private float [] rline = new float[4];
private float [] relem = new float[4];
private float [] vmis = new float[3];
private float [][] elmis = new float[3][3];
private double dtims = 0.0d;
private double dspin = 0.0d;
private double sitagt = 0.0d;
private double sunalp = 0.0d;
private double sundel = 0.0d;
private double [] sat = new double[3];
private double [] sp = new double[3];
private double [] ss = new double[3];
private double [][] orbt1 = new double[35][8];
private double [][] atit = new double[10][10];
// class constants
private static final double cdr = Math.PI / 180.0d;
private static final double crd = 180.0d / Math.PI;
private static final double hpai = Math.PI / 2.0d;
private static final double dpai = Math.PI * 2.0d;
private static final double ea = 6378136.0d;
private static final double ef = 1.0d / 298.257d;
/**
*
* constructor: copy nav block to a byte array, eliminating text fields
*
* @param navBlock - the navigation block from the image file
*
*/
public GMSXnav(int[] navBlock)
{
int i;
int j;
int index = 0;
byte [] tmpArr;
// copy data to new array, taking out text at start of each block
for (i = 0; i < 126; i++) {
tmpArr = intToBytes(navBlock[i + 1]);
for (j = 0; j < 4; j++) {
bParms[index] = tmpArr[j];
index++;
}
}
int srcOffset = 128;
for (int block = 0; block < 4; block++) {
for (i = 0; i < 127; i++) {
tmpArr = intToBytes(navBlock[i + srcOffset]);
for (j = 0; j < 4; j++) {
bParms[index] = tmpArr[j];
index++;
}
}
srcOffset += 128;
}
decOABlock(bParms, 0);
}
/**
*
* toLinEle converts lat/lon 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.
*
*/
public synchronized float[][] toLinEle (float[][] latlon)
{
int mode = 1;
int count = latlon[0].length;
float [] rtnPoint;
float[][] linele = new float[2][count];
float line = 0.0f;
float elem = 0.0f;
float lon = 0.0f;
for (int point = 0; point < count; point++) {
// initialize value as not navigable
linele[indexLine][point] = Float.NaN;
linele[indexEle][point] = Float.NaN;
if (Math.abs(latlon[indexLat][point]) > 90.0) {
continue;
}
// normalize to -180 to 180
lon = latlon[indexLon][point];
if (lon > 180.f) lon = lon - 360.f;
if (lon < -180.f) lon = lon + 360.f;
if (Math.abs(latlon[indexLon][point]) > 180.f) continue;
if (-lon > 90-subLon && -lon < 270-subLon) continue;
rtnPoint = mgivsr (
mode,
(float) elem,
(float) line,
(float) lon,
(float) latlon[indexLat][point]
);
linele[indexLine][point] = rtnPoint[0];
linele[indexEle][point] = rtnPoint[1];
}
// Return in 'File' coordinates
return imageCoordToAreaCoord(linele, linele);
}
public synchronized double[][] toLinEle (double[][] latlon)
{
int mode = 1;
int count = latlon[0].length;
float [] rtnPoint;
double[][] linele = new double[2][count];
double line = 0.0d;
double elem = 0.0d;
double lon = 0.0f;
for (int point = 0; point < count; point++) {
// initialize value as not navigable
linele[indexLine][point] = Double.NaN;
linele[indexEle][point] = Double.NaN;
if (Math.abs(latlon[indexLat][point]) > 90.0) {
continue;
}
// normalize to -180 to 180
lon = latlon[indexLon][point];
if (lon > 180.0) lon = lon - 360.0;
if (lon < -180.0) lon = lon + 360.0;
if (Math.abs(latlon[indexLon][point]) > 180.0) continue;
if (-lon > 90-subLon && -lon < 270-subLon) continue;
rtnPoint = mgivsr (
mode,
(float) elem,
(float) line,
(float) lon,
(float) latlon[indexLat][point]
);
linele[indexLine][point] = rtnPoint[0];
linele[indexEle][point] = rtnPoint[1];
}
// Return in 'File' coordinates
return imageCoordToAreaCoord(linele, linele);
}
/**
*
* toLatLon converts satellite line/element to lat/lon
*
* @param linele array of line/element pairs. Where
* linele[indexLine][] is a line and linele[indexEle][] is an element.
*
* @return array of lat/lon pairs. Where latlon[indexLat][]
* are latitudes and latlon[indexLon][] are longitudes.
*
*/
public synchronized float[][] toLatLon (float[][] linele)
{
int mode = -1;
int count = linele[0].length;
float [] rtnPoint;
float[][] latlon = new float[2][count];
float lat = 0.0f;
float lon = 0.0f;
// transform file to image coordinates
float[][] imgLinEle = areaCoordToImageCoord(linele);
for (int point = 0; point < count; point++) {
// initialize value as not navigable
latlon[indexLat][point] = Float.NaN;
latlon[indexLon][point] = Float.NaN;
rtnPoint = mgivsr (
mode,
(float) imgLinEle[indexEle][point],
(float) imgLinEle[indexLine][point],
(float) lon,
(float) lat
);
// normalize to -180 to 180
lon = rtnPoint[1];
if (lon > 180) lon = lon - 360;
if (lon < -180) lon = lon + 360;
if (Math.abs(lon) > 180 || (-lon > 90-subLon && -lon < 270-subLon)) {
rtnPoint[0] = Float.NaN;
lon = Float.NaN;
}
latlon[indexLat][point] = rtnPoint[0];
latlon[indexLon][point] = lon;
}
return (latlon);
}
public synchronized double[][] toLatLon (double[][] linele)
{
int mode = -1;
int count = linele[0].length;
float [] rtnPoint;
double[][] latlon = new double[2][count];
double lat = 0.0d;
double lon = 0.0d;
// transform file to image coordinates
double[][] imgLinEle = areaCoordToImageCoord(linele);
for (int point = 0; point < count; point++) {
// initialize value as not navigable
latlon[indexLat][point] = Double.NaN;
latlon[indexLon][point] = Double.NaN;
rtnPoint = mgivsr (
mode,
(float) imgLinEle[indexEle][point],
(float) imgLinEle[indexLine][point],
(float) lon,
(float) lat
);
// normalize to -180 to 180
lon = rtnPoint[1];
if (lon > 180.) lon = lon - 360.;
if (lon < -180.) lon = lon + 360.;
if (Math.abs(lon) > 180. || (-lon > 90.-subLon && -lon < 270.-subLon)) {
rtnPoint[0] = Float.NaN;
lon = Float.NaN;
}
latlon[indexLat][point] = rtnPoint[0];
latlon[indexLon][point] = lon;
}
return (latlon);
}
/** Get the lat,lon of the subpoint if available
*
* @return double[2] {lat, lon}
*
*/
public double[] getSubpoint() {
return new double[] {(double)subLat, (double)subLon};
}
/**
*
* sv0100 converts 4 or 6 byte byte values to double
*
* @param iWord - size of word in bytes from input array
* @param iPos - power of 10 to multiply result
* @param b - byte array to extract input bytes from
* @param bOffs - offset in byte array to begin conversion
*
* @return converted value
*
*/
private double sv0100 (
int iWord,
int iPos,
byte[] b,
int bOffs
)
{
boolean negative = false;
int [] tmpInt = new int[6];
double r8Dat = 0.0d;
if (b[bOffs] < 0) {
negative = true;
}
if (iWord == 4) {
for (int i = 1; i < 4; i++) {
if (b[i + bOffs] < 0) {
tmpInt[i] = (b[i + bOffs] & 0x7F) + 128;
} else {
tmpInt[i] = b[i + bOffs];
}
}
r8Dat = (
((double) (b[0 + bOffs] & 0x7F) * 16777216.0d) +
((double) (tmpInt[1]) * 65536.0d) +
((double) (tmpInt[2]) * 256.0d) +
(double) (tmpInt[3])
);
}
if (iWord == 6) {
for (int i = 1; i < 6; i++) {
if (b[i + bOffs] < 0) {
tmpInt[i] = (b[i + bOffs] & 0x7F) + 128;
} else {
tmpInt[i] = b[i + bOffs];
}
}
r8Dat = (
((double) (b[0 + bOffs] & 0x7F) * Math.pow(2.0d, 40)) +
((double) (tmpInt[1]) * Math.pow(2.0d, 32)) +
((double) (tmpInt[2]) * 16777216.0d) +
((double) (tmpInt[3]) * 65536.0d) +
((double) (tmpInt[4]) * 256.0d) +
((double) (tmpInt[5]))
);
}
r8Dat = r8Dat / Math.pow(10.0d, iPos);
if (negative) {
r8Dat = -r8Dat;
}
return(r8Dat);
}
/**
*
* decOABlock: decode Orbit and Attitude data block
*
* @param b - input byte array to decode
* @param form - long (1) or short (0)
*
*/
private void decOABlock (
byte[] b,
int form
)
{
int i = 0;
int j = 0;
dtims = sv0100(6, 8, b, 0);
dspin = sv0100(6, 8, b, 240);
resLin[0] = (float) sv0100(4, 8, b, 6);
resLin[1] = (float) sv0100(4, 8, b, 10);
resLin[2] = (float) sv0100(4, 8, b, 10);
resLin[3] = (float) sv0100(4, 8, b, 10);
resEle[0] = (float) sv0100(4, 10, b, 14);
resEle[1] = (float) sv0100(4, 10, b, 18);
resEle[2] = (float) sv0100(4, 10, b, 18);
resEle[3] = (float) sv0100(4, 10, b, 18);
rlic[0] = (float) sv0100(4, 4, b, 22);
rlic[1] = (float) sv0100(4, 4, b, 26);
rlic[2] = (float) sv0100(4, 4, b, 110);
rlic[3] = (float) sv0100(4, 4, b, 114);
relmfc[0] = (float) sv0100(4, 4, b, 30);
relmfc[1] = (float) sv0100(4, 4, b, 34);
relmfc[2] = (float) sv0100(4, 4, b, 118);
relmfc[3] = (float) sv0100(4, 4, b, 122);
senssu[0] = (float) sv0100(4, 0, b, 38);
senssu[1] = (float) sv0100(4, 0, b, 42);
senssu[2] = (float) sv0100(4, 0, b, 42);
senssu[3] = (float) sv0100(4, 0, b, 42);
rline[0] = (float) sv0100(4, 0, b, 46);
rline[1] = (float) sv0100(4, 0, b, 50);
rline[2] = (float) sv0100(4, 0, b, 50);
rline[3] = (float) sv0100(4, 0, b, 50);
relem[0] = (float) sv0100(4, 0, b, 54);
relem[1] = (float) sv0100(4, 0, b, 58);
relem[2] = (float) sv0100(4, 0, b, 58);
relem[3] = (float) sv0100(4, 0, b, 58);
vmis[0] = (float) sv0100(4, 10, b, 62);
vmis[1] = (float) sv0100(4, 10, b, 66);
vmis[2] = (float) sv0100(4, 10, b, 70);
elmis[0][0] = (float) sv0100(4, 7, b, 74);
elmis[1][0] = (float) sv0100(4, 10, b, 78);
elmis[2][0] = (float) sv0100(4, 10, b, 82);
elmis[0][1] = (float) sv0100(4, 10, b, 86);
elmis[1][1] = (float) sv0100(4, 7, b, 90);
elmis[2][1] = (float) sv0100(4, 10, b, 94);
elmis[0][2] = (float) sv0100(4, 10, b, 98);
elmis[1][2] = (float) sv0100(4, 10, b, 102);
elmis[2][2] = (float) sv0100(4, 7, b, 106);
subLon = (float) sv0100(6, 6, b, 198);
subLat = (float) sv0100(6, 6, b, 204);
for (i = 0; i < 10; i++) {
// long form
if (form == 1) {
j = ((i - 1) * 64) + 256;
}
// short form
if (form == 0) {
j = ((i - 1) * 48) + 256;
}
atit[0][i] = sv0100(6, 8, b, j);
atit[2][i] = sv0100(6, 8, b, j + 12);
atit[3][i] = sv0100(6, 11, b, j + 18);
atit[4][i] = sv0100(6, 8, b, j + 24);
atit[5][i] = sv0100(6, 8, b, j + 30);
}
for (i = 0; i < 8; i++) {
// long form
if (form == 1) {
j = ((i - 1) * 256) + 896;
}
// short form
if (form == 0) {
j = ((i - 1) * 200) + 736;
}
orbt1[ 0][i] = sv0100(6, 8, b, j + 0);
orbt1[ 8][i] = sv0100(6, 6, b, j + 48);
orbt1[ 9][i] = sv0100(6, 6, b, j + 54);
orbt1[10][i] = sv0100(6, 6, b, j + 60);
orbt1[14][i] = sv0100(6, 8, b, j + 84);
orbt1[17][i] = sv0100(6, 8, b, j + 102);
orbt1[18][i] = sv0100(6, 8, b, j + 108);
orbt1[19][i] = sv0100(6, 12, b, j + 128);
orbt1[20][i] = sv0100(6, 14, b, j + 134);
orbt1[21][i] = sv0100(6, 14, b, j + 140);
orbt1[22][i] = sv0100(6, 14, b, j + 146);
orbt1[23][i] = sv0100(6, 12, b, j + 152);
orbt1[24][i] = sv0100(6, 16, b, j + 158);
orbt1[25][i] = sv0100(6, 12, b, j + 164);
orbt1[26][i] = sv0100(6, 16, b, j + 170);
orbt1[27][i] = sv0100(6, 12, b, j + 176);
}
return;
}
/**
*
* mgivsr does the actual conversion to/from lat/lon or line/elem
*
* @param iMode - conversion mode, to lat/lon or to line/elem
* @param rPix - float pixel or element value
* @param rLin - float line value
* @param rLat - float latitude value
* @param rLon - float longitude value
*
* @return array of two floating point values, lat/lon or line/elem pair
*
*/
private float [] mgivsr (
int iMode,
float rPix,
float rLin,
float rLon,
float rLat
)
{
int lMode;
float rstep;
float rsamp;
float rfcl;
float rfcp;
float sens;
float rftl;
float rftp;
float ri;
float rj;
float rio;
float [] point = new float[2];
double bc;
double bs;
double beta = 0.0d;
double dd;
double dda;
double ddb;
double ddc;
double def;
double ee;
double en;
double dk;
double dk1;
double dk2;
double dLat = 0.0d;
double dLon = 0.0d;
double pc, ps;
double qc, qs;
double rtim = 0.0d;
double tf;
double tl = 0.0d;
double tp = 0.0d;
double [] stn1 = new double[3];
double [] sl;
double [] slv = new double[3];
double [] sx;
double [] sy;
double [] sw1;
double [] sw2;
double [] sw3 = new double[3];
point[0] = Float.NaN;
point[1] = Float.NaN;
// parameter checks
if (Math.abs(iMode) > 4) {
return (point);
}
if ((Math.abs(rLat) > 90) && (iMode > 0)) {
return (point);
}
// vissr frame information set
lMode = Math.abs(iMode) - 1;
rstep = resLin[lMode];
rsamp = resEle[lMode];
rfcl = rlic[lMode];
rfcp = relmfc[lMode];
sens = senssu[lMode];
rftl = (float) (rline[lMode] + 0.5);
rftp = (float) (relem[lMode] + 0.5);
// transformation, geographical -> VISSR
if (iMode > 0) {
dLat = (double) rLat * cdr;
dLon = (double) rLon * cdr;
ee = (2.0d * ef) - (ef * ef);
en = ea / Math.sqrt(1.0d - (ee * Math.sin(dLat) * Math.sin(dLat)));
stn1[0] = en * Math.cos(dLat) * Math.cos(dLon);
stn1[1] = en * Math.cos(dLat) * Math.sin(dLon);
stn1[2] = (en * (1.0d - ee)) * Math.sin(dLat);
rio = (float) (rfcl -
Math.atan(Math.sin(dLat) / (6.610689 - Math.cos(dLat))) / rstep);
rtim = dtims + (double) (rio / sens / 1440.0d) / dspin;
loop: while (true) {
beta = mg1100(rtim);
sw1 = mg1220(sp, ss);
sw2 = mg1220(sw1, sp);
bc = Math.cos(beta);
bs = Math.sin(beta);
sw3[0] = (sw1[0] * bs) + (sw2[0] * bc);
sw3[1] = (sw1[1] * bs) + (sw2[1] * bc);
sw3[2] = (sw1[2] * bs) + (sw2[2] * bc);
sx = mg1200(sw3);
sy = mg1220(sp, sx);
slv[0] = stn1[0] - sat[0];
slv[1] = stn1[1] - sat[1];
slv[2] = stn1[2] - sat[2];
sl = mg1200(slv);
sw2 = mg1210(sp, sl);
sw3 = mg1210(sy, sw2);
tp = mg1230(sy, sw2);
tf = (sp[0] * sw3[0]) + (sp[1] * sw3[1]) + (sp[2] * sw3[2]);
if (tf < 0.0d) {
tp = -tp;
}
tl = mg1230(sp, sl);
ri = (float) (hpai - tl) / rstep + rfcl - (vmis[1] / rstep);
rj = (float) (tp / rsamp + rfcp + (vmis[2] / rsamp) -
(hpai - tl) * Math.tan(vmis[0]) / rsamp);
if (Math.abs(ri - rio) >= 1.0d) {
rtim = (double) (Math.rint((ri - 1) / sens) +
(rj * rsamp) / dpai) / (dspin * 1440.0) + dtims;
rio = ri;
continue loop;
}
break loop;
}
point[0] = ri;
point[1] = rj;
rLin = ri;
rPix = rj;
if ((rLin < 0) || (rLin > rftl)) {
point[0] = Float.NaN;
point[1] = Float.NaN;
}
if ((rPix < 0) || (rPix > rftp)) {
point[0] = Float.NaN;
point[1] = Float.NaN;
}
}
// transformation, VISSR -> geographical
if (iMode < 0) {
rtim = (double) (Math.rint((rLin - 1) / sens) +
(rPix * rsamp) / dpai) / (dspin * 1440.0) + dtims;
beta = mg1100(rtim);
sw1 = mg1220(sp, ss);
sw2 = mg1220(sw1, sp);
bc = Math.cos(beta);
bs = Math.sin(beta);
sw3[0] = (sw1[0] * bs) + (sw2[0] * bc);
sw3[1] = (sw1[1] * bs) + (sw2[1] * bc);
sw3[2] = (sw1[2] * bs) + (sw2[2] * bc);
sx = mg1200(sw3);
sy = mg1220(sp, sx);
pc = Math.cos(rstep * (rLin - rfcl));
ps = Math.sin(rstep * (rLin - rfcl));
qc = Math.cos(rsamp * (rPix - rfcp));
qs = Math.sin(rsamp * (rPix - rfcp));
sw1[0] = (elmis[0][0] * pc) + (elmis[0][2] * ps);
sw1[1] = (elmis[1][0] * pc) + (elmis[1][2] * ps);
sw1[2] = (elmis[2][0] * pc) + (elmis[2][2] * ps);
sw2[0] = (qc * sw1[0]) - (qs * sw1[1]);
sw2[1] = (qs * sw1[0]) + (qc * sw1[1]);
sw2[2] = sw1[2];
sw3[0] = (sx[0] * sw2[0]) + (sy[0] * sw2[1]) + (sp[0] * sw2[2]);
sw3[1] = (sx[1] * sw2[0]) + (sy[1] * sw2[1]) + (sp[1] * sw2[2]);
sw3[2] = (sx[2] * sw2[0]) + (sy[2] * sw2[1]) + (sp[2] * sw2[2]);
sl = mg1200(sw3);
def = (1.0d - ef) * (1.0d - ef);
dda = def * ((sl[0] * sl[0]) + (sl[1] * sl[1])) + (sl[2] * sl[2]);
ddb = def * ((sat[0] * sl[0]) + (sat[1] * sl[1])) + (sat[2] * sl[2]);
ddc = def * ((sat[0] * sat[0]) + (sat[1] * sat[1]) - (ea * ea)) +
(sat[2] * sat[2]);
dd = (ddb * ddb) - (dda * ddc);
if ((dd >= 0.0d) && (dda != 0.0d)) {
dk1 = (-ddb + Math.sqrt(dd)) / dda;
dk2 = (-ddb - Math.sqrt(dd)) / dda;
} else {
return (point);
}
if (Math.abs(dk1) < Math.abs(dk2)) {
dk = dk1;
} else {
dk = dk2;
}
stn1[0] = sat[0] + (dk * sl[0]);
stn1[1] = sat[1] + (dk * sl[1]);
stn1[2] = sat[2] + (dk * sl[2]);
dLat = Math.atan(stn1[2] /
(def * Math.sqrt((stn1[0] * stn1[0]) + (stn1[1] * stn1[1]))));
if (stn1[0] != 0.0d) {
dLon = Math.atan(stn1[1] / stn1[0]);
if ((stn1[0] < 0.0d) && (stn1[1] >= 0.0d)) {
dLon = dLon + Math.PI;
}
if ((stn1[0] < 0.0d) && (stn1[1] < 0.0d)) {
dLon = dLon - Math.PI;
}
} else {
if (stn1[1] > 0.0d) {
dLon = hpai;
} else {
dLon = -hpai;
}
}
point[0] = (float) (dLat * crd);
point[1] = (float) (dLon * crd);
}
return (point);
}
/**
*
* mg1100 conversion routine of some sort
*
* @param rtim - ?
*
* @return converted value ?
*
*/
private double mg1100 (
double rtim
)
{
double beta = 0.0d;
double delt = 0.0d;
double attalp = 0.0d;
double attdel = 0.0d;
double wkcos = 0.0d;
double wksin = 0.0d;
double [] att1 = new double[3];
double [] att2 = new double[3];
double [] att3 = new double[3];
double [][] npa = new double[3][3];
for (int i = 0; i < 7; i++) {
if ((rtim > orbt1[0][i]) && (rtim < orbt1[0][i+1])) {
npa = mg1110(i, rtim, orbt1);
break;
}
}
for (int i = 0; i < 9; i++) {
if ((rtim >= atit[0][i]) && (rtim < atit[0][i+1])) {
delt = (rtim - atit[0][i]) / (atit[0][i+1] - atit[0][i]);
attalp = atit[2][i] + (atit[2][i+1] - atit[2][i]) * delt;
attdel = atit[3][i] + (atit[3][i+1] - atit[3][i]) * delt;
beta = atit[4][i] + (atit[4][i+1] - atit[4][i]) * delt;
if ((atit[4][i+1] - atit[4][i]) > 0.0d) {
beta = atit[4][i] + (atit[4][i+1] - atit[4][i] - 360.0d * cdr) * delt;
}
break;
}
}
wkcos = Math.cos(attdel);
att1[0] = Math.sin(attdel);
att1[1] = wkcos * (-Math.sin(attalp));
att1[2] = wkcos * Math.cos(attalp);
att2[0] = (
(npa[0][0] * att1[0]) +
(npa[0][1] * att1[1]) +
(npa[0][2] * att1[2])
);
att2[1] = (
(npa[1][0] * att1[0]) +
(npa[1][1] * att1[1]) +
(npa[1][2] * att1[2])
);
att2[2] = (
(npa[2][0] * att1[0]) +
(npa[2][1] * att1[1]) +
(npa[2][2] * att1[2])
);
wksin = Math.sin(sitagt);
wkcos = Math.cos(sitagt);
att3[0] = ( wkcos * att2[0]) + (wksin * att2[1]);
att3[1] = (-wksin * att2[0]) + (wkcos * att2[1]);
att3[2] = att2[2];
sp = mg1200(att3);
wkcos = Math.cos(sundel);
ss[0] = wkcos * Math.cos(sunalp);
ss[1] = wkcos * Math.sin(sunalp);
ss[2] = Math.sin(sundel);
return(beta);
}
/**
*
* mg1110 conversion routine of some sort
*
* @param i - ?
* @param rtim - ?
* @param orbta - ?
*
* @return 3 by 3 double array
*
*/
private double [][] mg1110 (
int i,
double rtim,
double [][] orbta
)
{
double [][] npa = new double[3][3];
double delt;
if (i != 7) {
delt = (rtim - orbta[0][i]) / (orbta[0][i+1] - orbta[0][i]);
sat[0] = orbta[ 8][i] + (orbta[ 8][i+1] - orbta[ 8][i]) * delt;
sat[1] = orbta[ 9][i] + (orbta[ 9][i+1] - orbta[ 9][i]) * delt;
sat[2] = orbta[10][i] + (orbta[10][i+1] - orbta[10][i]) * delt;
sitagt = (orbta[14][i] + (orbta[14][i+1] - orbta[14][i]) * delt) * cdr;
if ((orbta[14][i+1] - orbta[14][i]) < 0.0d) {
sitagt = (orbta[14][i] +
(orbta[14][i+1] - orbta[14][i] + 360.0d) * delt) * cdr;
}
sunalp = (orbta[17][i] + (orbta[17][i+1] - orbta[17][i]) * delt) * cdr;
if ((orbta[17][i+1] - orbta[17][i]) > 0.0d) {
sunalp = (orbta[17][i] +
(orbta[17][i+1] - orbta[17][i] - 360.0d) * delt) * cdr;
}
sundel = (orbta[18][i] + (orbta[18][i+1] - orbta[18][i]) * delt) * cdr;
npa[0][0] = orbta[19][i];
npa[1][0] = orbta[20][i];
npa[2][0] = orbta[21][i];
npa[0][1] = orbta[22][i];
npa[1][1] = orbta[23][i];
npa[2][1] = orbta[24][i];
npa[0][2] = orbta[25][i];
npa[1][2] = orbta[26][i];
npa[2][2] = orbta[27][i];
}
return(npa);
}
/**
*
* mg1200 conversion routine of some sort
*
* @param vec - ?
*
* @return double array size 3
*
*/
private double[] mg1200 (
double [] vec
)
{
double [] vecu = new double[3];
double rv1;
double rv2;
rv1 = (vec[0] * vec[0]) + (vec[1] * vec[1]) + (vec[2] * vec[2]);
if (rv1 == 0.0d) {
return(vecu);
}
rv2 = Math.sqrt(rv1);
vecu[0] = vec[0] / rv2;
vecu[1] = vec[1] / rv2;
vecu[2] = vec[2] / rv2;
return(vecu);
}
/**
*
* mg1210 conversion routine of some sort
*
* @param va - ?
* @param vb - ?
*
* @return double array size 3
*
*/
private double [] mg1210 (
double [] va,
double [] vb
)
{
double [] vc = new double[3];
vc[0] = (va[1] * vb[2]) - (va[2] * vb[1]);
vc[1] = (va[2] * vb[0]) - (va[0] * vb[2]);
vc[2] = (va[0] * vb[1]) - (va[1] * vb[0]);
return(vc);
}
/**
*
* mg1220 conversion routine of some sort
*
* @param va - ?
* @param vb - ?
*
* @return double array size 3
*
*/
private double [] mg1220 (
double [] va,
double [] vb
)
{
double [] vc = new double[3];
double [] vd = new double[3];
vc[0] = (va[1] * vb[2]) - (va[2] * vb[1]);
vc[1] = (va[2] * vb[0]) - (va[0] * vb[2]);
vc[2] = (va[0] * vb[1]) - (va[1] * vb[0]);
vd = mg1200(vc);
return(vd);
}
/**
*
* mg1230 conversion routine of some sort
*
* @param va - ?
* @param vb - ?
*
* @return double
*
*/
private double mg1230 (
double [] va,
double [] vb
)
{
double as1;
double as2;
double asita = 0.0d;
as1 = (va[0] * vb[0]) + (va[1] * vb[1]) + (va[2] * vb[2]);
as2 = (((va[0] * va[0]) + (va[1] * va[1]) + (va[2] * va[2])) *
((vb[0] * vb[0]) + (vb[1] * vb[1]) + (vb[2] * vb[2])));
if (as2 == 0.0d) {
return(asita);
}
//asita = Math.acos(Math.min(Math.max(as1,.0000001),1.0) / Math.sqrt(as2));
double temp = as1/Math.sqrt(as2);
if (temp > 1.0 && temp-1.0 < 0.000001) temp = 1;
asita = Math.acos(temp);
return(asita);
}
/**
* intToBytes converts an int to an array of 4 bytes.
*
* @param v input value
*
* @return the corresponding array of bytes
*
*/
static public byte[] intToBytes(int v) {
byte[] b = new byte[4];
int allbits = 255;
for(int i = 0; i < 4; i++){
b[3-i] = (byte)((v & (allbits << i * 8) ) >> i *8);
}
return b;
}
// main is used for unit testing
public static void main(String[] args) {
int [] navBlock = new int[800];
int [] dirBlock = new int[64];
DataInputStream dis = null;
GMSXnav gmsx = null;
String fileName = "GMSXAREA";
System.out.println("unit test of class GMSXnav begin...");
if (args.length > 0) fileName = args[0];
// test assumes presence of test area called GMSXAREA
try {
dis = new DataInputStream (
new BufferedInputStream(new FileInputStream(fileName), 2048)
);
} catch (Exception e) {
System.out.println("error creating DataInputStream: " + e);
System.exit(0);
}
// read and discard the directory
System.out.println("reading in, discarding directory words...");
try {
for (int i = 0; i < 64; i++) {
dirBlock[i] = dis.readInt();
}
} catch (IOException e) {
System.out.println("error reading area file directory: " + e);
System.exit(0);
}
// now read in the navigation data
System.out.println("reading in navigation words...");
try {
for (int i = 0; i < navBlock.length; i++) {
navBlock[i] = dis.readInt();
}
} catch (IOException e) {
System.out.println("error reading area file navigation data: " + e);
System.exit(0);
}
if (navBlock[0] != GMSX) {
System.out.println("error: not a GMS navigation block.");
System.exit(0);
}
System.out.println("creating GMSXnav object...");
gmsx = new GMSXnav(navBlock);
gmsx.setImageStart(dirBlock[5], dirBlock[6]);
System.out.println("#### ImageStart set to:"+dirBlock[5]+" "+dirBlock[6]);
gmsx.setRes(dirBlock[11], dirBlock[12]);
System.out.println("#### ImageRes set to:"+dirBlock[11]+" "+dirBlock[12]);
gmsx.setStart(1,1);
gmsx.setFlipLineCoordinates(dirBlock[8]); // invert Y axis coordinates
System.out.println(" test of toLatLon...");
System.out.println(" answer should be close to: -2.37, 133.31");
double [][] linEle = new double [2][1];
double [][] latLon = new double [2][1];
linEle[gmsx.indexLine][0] = 471.0f;
linEle[gmsx.indexEle][0] = 323.0f;
latLon = gmsx.toLatLon(linEle);
System.out.println(" answer is: " + latLon[gmsx.indexLat][0] +
", " + latLon[gmsx.indexLon][0]);
System.out.println(" test of toLinEle...");
System.out.println(" answer should be close to: 480.0, 1.0");
latLon[gmsx.indexLat][0] = -2.0f;
latLon[gmsx.indexLon][0] = 118.0f;
linEle = gmsx.toLinEle(latLon);
System.out.println(" answer is: " + linEle[gmsx.indexLine][0] +
", " + linEle[gmsx.indexEle][0]);
System.out.println(" answer should be close to: 16.0, 628.0");
latLon[gmsx.indexLat][0] = -24.0f;
latLon[gmsx.indexLon][0] = 148.0f;
linEle = gmsx.toLinEle(latLon);
System.out.println(" answer is: " + linEle[gmsx.indexLine][0] +
", " + linEle[gmsx.indexEle][0]);
System.out.println("unit test of class GMSXnav end...");
}
}