// // 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..."); } }