//
// KALPnav.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;
/**
* The KALPnav class creates the ability to navigate KALP
* image data. It is a math copy of the McIDAS nvxgvar.dlm
* code.
*
* When used with AreaFile class, set up like this:
*
* <pre><code>
* AreaFile af;
* try {
* af = new AreaFile("/home/user/mcidas/data/AREA0001");
* } catch (AreaFileException e) {
* System.out.println(e);
* return;
* }
* int[] dir;
* try { dir=af.getDir();
* } catch (AreaFileException e){
* System.out.println(e);
* return;
* }
* int[] nav;
* try { nav=af.getNav();
* } catch (AreaFileException e){
* System.out.println(e);
* return;
* }
* try {
* GVARnav ng = new GVARnav(nav); // XXXXnav is the specific implementation
* } catch (IllegalArgumentException excp) {
* System.out.println(excp);
* return;
* }
* ng.setImageStart(dir[5], dir[6]);
* ng.setRes(dir[11], dir[12]);
* ng.setMag(1,1);
* ng.setStart(0,0);
* ......................
* </code></pre>
*
* @author Tom Whittaker
*
*/
public class KALPnav extends AREAnav {
private static final long serialVersionUID = 1L;
private double h, a, rp, re, cdr, crd, lpsi2, deltax, deltay;
private double sublat, sublon, cenlin, cenele, altitude;
private boolean isEastPositive = true;
public KALPnav (int[] iparms) {
this(1, iparms);
}
public KALPnav (int ifunc, int[] iparms) {
if (ifunc != 1) ifunc = 1;
if (iparms[0] != KALP ) {
throw new IllegalArgumentException("Invalid navigation type" + iparms[0]);
}
// H=42150.766-6378.155
altitude = (double)iparms[11] / 10000.0;
h=altitude-6378.155;
re=6378.155;
a=1./297.;
rp=re/(1.+a);
cdr=Math.PI/180.;
crd=180./Math.PI;
lpsi2=1.0;
// DELTAX=18.03674/1408.
// DELTAY=18.03674/1408.
deltax = (double)iparms[12] / 1000000000.0;
deltax = deltax * crd;
deltay = deltax;
sublat=(double)iparms[10]/10000.;
sublon=(double)iparms[6]/10000.;
// The center line and element are in full res coords *10
// They are used in scan coords, so divide by 40.
cenlin = (double)iparms[13]/40.;
cenele = (double)iparms[14]/40.;
if(iparms[13] == 0) {
cenlin = 704.5;
cenele = 704.5;
}
}
public float[][] toLatLon(float[][] linele) {
double xele2, xlin2, x, y, xr, yr, rs, tanx, tany, val1, val2, yk;
double vmu, cosrf, sinrf, xt, yt, zt, xfi, xla, teta;
int number = linele[0].length;
float[][] latlon = new float[2][number];
float[][] imglinele = areaCoordToImageCoord(linele);
for (int point=0; point<number; point++) {
xele2 = imglinele[indexEle][point]/4.0;
xlin2 = imglinele[indexLine][point]/4.0;
x = cenele - xele2;
y = cenlin - xlin2;
xr = x;
yr = y;
x=xr*lpsi2*deltax*cdr;
y=yr*lpsi2*deltay*cdr;
rs=re+h;
tanx=Math.tan(x);
tany=Math.tan(y);
val1=1.+tanx*tanx;
val2=1.+(tany*tany)*((1.+a)*(1.+a));
yk=rs/re;
if((val1*val2) > ((yk*yk)/(yk*yk-1.0))) {
latlon[indexLine][point] = Float.NaN;
latlon[indexEle][point] = Float.NaN;
continue;
}
vmu=(rs-(re*(Math.sqrt((yk*yk)-(yk*yk-1)*val1*val2))))/(val1*val2);
cosrf=Math.cos(sublat*cdr);
sinrf=Math.sin(sublat*cdr);
xt=(rs*cosrf)+(vmu*(tanx*sinrf-cosrf));
yt=(rs*sinrf)-(vmu*(tanx*cosrf+sinrf));
zt=vmu*tany/Math.cos(x);
teta=Math.asin(zt/rp);
xfi=(Math.atan(((Math.tan(teta))*re)/rp))*crd;
xla=-Math.atan(yt/xt)*crd;
//--- CHANGE LONGITUDE FOR CORRECT SUBPOINT
xla=xla+sublon;
if (isEastPositive) xla = -xla;
latlon[indexLat][point] = (float) xfi;
latlon[indexLon][point] = (float) xla;
}
return latlon;
}
public float[][] toLinEle(float [][] latlon) {
double x1, y1, xfi, xla, rom, y, r1, r2, rs, reph, rpph;
double coslo, sinlo, teta, xt, yt, zt, px, py, xr, yr ;
int number = latlon[0].length;
float[][] linele = new float[2][number];
for (int point=0; point<number; point++) {
x1 = (double) latlon[indexLat][point];
y1 = (double) latlon[indexLon][point];
if (!isEastPositive) y1 = -y1;
//--- CORRECT FOR SUBLON
y1=y1+sublon;
xfi=x1*cdr;
xla=y1*cdr;
rom=(re*rp)/Math.sqrt(rp*rp*Math.cos(xfi) *
Math.cos(xfi)+re*re*Math.sin(xfi)*Math.sin(xfi));
y=Math.sqrt(h*h+rom*rom-2*h*rom*Math.cos(xfi)*Math.cos(xla));
r1=y*y+rom*rom;
r2=h*h;
if (r1 > r2) {
linele[indexLine][point] = Float.NaN;
linele[indexEle][point] = Float.NaN;
} else {
rs=re+h;
reph=re;
rpph=rp;
coslo=Math.cos(sublat*cdr);
sinlo=Math.sin(sublat*cdr);
teta=Math.atan((rpph/reph)*Math.tan(xfi));
xt=reph*Math.cos(teta)*Math.cos(xla);
yt=reph*Math.cos(teta)*Math.sin(xla);
zt=rpph*Math.sin(teta);
px=Math.atan((coslo*(yt-rs*sinlo)-(xt-rs*coslo)*sinlo)/
(sinlo*(yt-rs*sinlo)+(xt-rs*coslo)*coslo));
py=Math.atan(zt*((Math.tan(px)*sinlo-coslo)/(xt-rs*coslo))*Math.cos(px));
px=px*crd;
py=py*crd;
xr=px/(deltax*lpsi2);
yr=py/(deltay*lpsi2);
xr=cenele-xr;
yr=cenlin-yr;
xr=xr*4.0;
yr=yr*4.0;
linele[indexLine][point] = (float)yr;
linele[indexEle][point] = (float)xr;
}
}
return imageCoordToAreaCoord(linele, linele);
}
public double[][] toLinEle(double [][] latlon) {
double x1, y1, xfi, xla, rom, y, r1, r2, rs, reph, rpph;
double coslo, sinlo, teta, xt, yt, zt, px, py, xr, yr;
int number = latlon[0].length;
double[][] linele = new double[2][number];
for (int point=0; point<number; point++) {
x1 = latlon[indexLat][point];
y1 = latlon[indexLon][point];
if (!isEastPositive) y1 = -y1;
//--- CORRECT FOR SUBLON
y1=y1+sublon;
xfi=x1*cdr;
xla=y1*cdr;
rom=(re*rp)/Math.sqrt(rp*rp*Math.cos(xfi) *
Math.cos(xfi)+re*re*Math.sin(xfi)*Math.sin(xfi));
y=Math.sqrt(h*h+rom*rom-2*h*rom*Math.cos(xfi)*Math.cos(xla));
r1=y*y+rom*rom;
r2=h*h;
if (r1 > r2) {
linele[indexLine][point] = Float.NaN;
linele[indexEle][point] = Float.NaN;
continue;
}
rs=re+h;
reph=re;
rpph=rp;
coslo=Math.cos(sublat*cdr);
sinlo=Math.sin(sublat*cdr);
teta=Math.atan((rpph/reph)*Math.tan(xfi));
xt=reph*Math.cos(teta)*Math.cos(xla);
yt=reph*Math.cos(teta)*Math.sin(xla);
zt=rpph*Math.sin(teta);
px=Math.atan((coslo*(yt-rs*sinlo)-(xt-rs*coslo)*sinlo)/
(sinlo*(yt-rs*sinlo)+(xt-rs*coslo)*coslo));
py=Math.atan(zt*((Math.tan(px)*sinlo-coslo)/(xt-rs*coslo))*Math.cos(px));
px=px*crd;
py=py*crd;
xr=px/(deltax*lpsi2);
yr=py/(deltay*lpsi2);
xr=cenele-xr;
yr=cenlin-yr;
xr=xr*4.0;
yr=yr*4.0;
linele[indexLine][point] = yr;
linele[indexEle][point] = xr;
}
return imageCoordToAreaCoord(linele, linele);
}
public double[][] toLatLon(double[][] linele) {
double xele2, xlin2, x, y, xr, yr, rs, tanx, tany, val1, val2, yk;
double vmu, cosrf, sinrf, xt, yt, zt, xfi, xla, teta;
int number = linele[0].length;
double[][] latlon = new double[2][number];
double[][] imglinele = areaCoordToImageCoord(linele);
for (int point=0; point<number; point++) {
xele2 = imglinele[indexEle][point]/4.0;
xlin2 = imglinele[indexLine][point]/4.0;
x = cenele - xele2;
y = cenlin - xlin2;
xr = x;
yr = y;
x=xr*lpsi2*deltax*cdr;
y=yr*lpsi2*deltay*cdr;
rs=re+h;
tanx=Math.tan(x);
tany=Math.tan(y);
val1=1.+tanx*tanx;
val2=1.+(tany*tany)*((1.+a)*(1.+a));
yk=rs/re;
if((val1*val2) > ((yk*yk)/(yk*yk-1.0))) {
latlon[indexLine][point] = Float.NaN;
latlon[indexEle][point] = Float.NaN;
continue;
}
vmu=(rs-(re*(Math.sqrt((yk*yk)-(yk*yk-1)*val1*val2))))/(val1*val2);
cosrf=Math.cos(sublat*cdr);
sinrf=Math.sin(sublat*cdr);
xt=(rs*cosrf)+(vmu*(tanx*sinrf-cosrf));
yt=(rs*sinrf)-(vmu*(tanx*cosrf+sinrf));
zt=vmu*tany/Math.cos(x);
teta=Math.asin(zt/rp);
xfi=(Math.atan(((Math.tan(teta))*re)/rp))*crd;
xla=-Math.atan(yt/xt)*crd;
//--- CHANGE LONGITUDE FOR CORRECT SUBPOINT
xla=xla+sublon;
if (isEastPositive) xla = -xla;
latlon[indexLat][point] = xfi;
latlon[indexLon][point] = xla;
}
return latlon;
}
public static void main(String[] args) {
int [] navBlock = new int[800];
int [] dirBlock = new int[64];
DataInputStream dis = null;
KALPnav kalp = null;
String fileName = "KALPAREA";
System.out.println("unit test of class KALP begin...");
if (args.length > 0) fileName = args[0];
// test assumes presence of test area called KALPXAREA
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] != KALP) {
System.out.println("error: not a KALP navigation block.");
System.exit(0);
}
double [][] linEle = new double [2][1];
double [][] latLon = new double [2][1];
System.out.println("creating KALPnav object...");
kalp = new KALPnav(navBlock);
kalp.setImageStart(dirBlock[5], dirBlock[6]);
System.out.println("#### ImageStart set to:"+dirBlock[5]+" "+dirBlock[6]);
kalp.setRes(dirBlock[11], dirBlock[12]);
System.out.println("#### ImageRes set to:"+dirBlock[11]+" "+dirBlock[12]);
kalp.setStart(0,0);
//System.out.println("#### setFlipLineCoord called with "+dirBlock[8]);
//kalp.setFlipLineCoordinates(dirBlock[8]); // invert Y axis coordinates
System.out.println(" test of toLinEle...");
latLon[kalp.indexLat][0] = 11.0f;
latLon[kalp.indexLon][0] = 50.f;
linEle = kalp.toLinEle(latLon);
System.out.println(" answer is: " + linEle[kalp.indexLine][0] +
", " + linEle[kalp.indexEle][0]);
latLon[0][0] = Double.NaN;
latLon = kalp.toLatLon(linEle);
System.out.println("testing inverse of 11N/50E");
System.out.println(" answer is: " + latLon[kalp.indexLat][0] +
", " + latLon[kalp.indexLon][0]);
System.out.println(" another test of toLinEle...");
latLon[kalp.indexLat][0] = -20.0f;
latLon[kalp.indexLon][0] = 100.f;
linEle = kalp.toLinEle(latLon);
System.out.println(" answer is: " + linEle[kalp.indexLine][0] +
", " + linEle[kalp.indexEle][0]);
latLon[0][0] = Double.NaN;
latLon = kalp.toLatLon(linEle);
System.out.println("testing inverse of 20S/100E");
System.out.println(" answer is: " + latLon[kalp.indexLat][0] +
", " + latLon[kalp.indexLon][0]);
System.out.println("unit test of class KALPnav end...");
}
}