// // LALOnav.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.lang.Float; import java.lang.Double; import visad.Gridded2DSet; /** * Navigation class for Radar (RECT) type nav. This code was modified * from the original FORTRAN code (nvxrect.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 LALOnav extends AREAnav { private static final long serialVersionUID = 1L; int rows, cols, latres, lonres, latpoint, lonpoint, numPoints; int ulline, ulelem, aux_size, lat_aux_offset, lon_aux_offset; int lrlin, lrele; double minlat, maxlat, minlon, maxlon; float[] latData, lonData; float LAT_MISSING = 0.f; float LON_MISSING = 0.f; boolean debug = false; int count = 0; Gridded2DSet gs = null; /** * Set up for the real math work. Must pass in the int array * of the RECT nav 'codicil'. * * @param iparms the nav block from the image file * @throws IllegalArgumentException * if the nav block is not a RECT type. */ public LALOnav (int[] iparms, int[] auxBlock) throws IllegalArgumentException { if (iparms[0] != LALO ) throw new IllegalArgumentException("Invalid navigation type" + iparms[0]); if (debug) { System.out.println("Len of nav = "+iparms.length); for (int i=0; i< iparms.length; i++) { System.out.println("i="+i+" iparm="+iparms[i]); } } rows = iparms[65]; cols = iparms[66]; /* minlat = McIDASUtil.integerLatLonToDouble(iparms[67]); minlon = McIDASUtil.integerLatLonToDouble(iparms[68]); maxlat = McIDASUtil.integerLatLonToDouble(iparms[69]); maxlon = McIDASUtil.integerLatLonToDouble(iparms[70]); */ minlat = (double) Float.intBitsToFloat(iparms[67]); minlon = (double) Float.intBitsToFloat(iparms[68]); maxlat = (double) Float.intBitsToFloat(iparms[69]); maxlon = (double) Float.intBitsToFloat(iparms[70]); latres = iparms[71]; lonres = iparms[72]; latpoint = iparms[73]; lonpoint = iparms[74]; ulline = iparms[75]; ulelem = iparms[76]; aux_size = iparms[77]; lat_aux_offset = iparms[78]; lon_aux_offset = iparms[79]; int begLat = lat_aux_offset/4; int begLon = lon_aux_offset/4; lrlin = ulline + (rows -1) * latres; lrele = ulelem + (cols - 1) * lonres; if (debug) { System.out.println("rows, cols="+rows+" "+cols); System.out.println("min/max lat, lon="+minlat+" "+maxlat+" / "+minlon+" "+maxlon); System.out.println("latres, lonres="+latres+" "+lonres); System.out.println("latpoint, lonpoint="+latpoint+" "+lonpoint); System.out.println("ulline, ulelem="+ulline+" "+ulelem); System.out.println("size_aux, lat_aux, lon_aux="+aux_size+" "+lat_aux_offset+" "+lon_aux_offset); System.out.println("len of auxBlock"+auxBlock.length); System.out.println("begLat/Lon="+begLat+" "+begLon); System.out.println("len of auxBlock="+auxBlock.length); } /* float[][] lats = new float[cols][rows]; float[][] lons = new float[cols][rows]; */ numPoints = cols * rows; latData = new float[numPoints]; lonData = new float[numPoints]; float[][] lalo = new float[2][numPoints]; for (int k=0; k<numPoints; k++) { latData[k] = Float.intBitsToFloat(auxBlock[k + begLat]); lonData[k] = Float.intBitsToFloat(auxBlock[k + begLon]); lalo[0][k] = lonData[k]; lalo[1][k] = latData[k]; if (latData[k] < -90.f || latData[k] > 90.f || lonData[k] < -180.f || lonData[k] > 360.f) { latData[k] = LAT_MISSING; lonData[k] = LON_MISSING; lalo[0][k] = Float.NaN; lalo[1][k] = Float.NaN; } } count = 0; // look up VisAD stuff...if available... try { gs = new Gridded2DSet(visad.RealTupleType.SpatialEarth2DTuple, lalo, cols, rows, null, null, null, false, false); } catch (Exception ge) { System.out.println("#### The VisAD library visad.jar is needed for this operation"); ge.printStackTrace(); } if (debug) System.out.println("done coverting"); } /** 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. * * this code cobbled from McIDAS laloutil.c */ public float[][] toLatLon(float[][] linele) { int number = linele[0].length; double rlin, rele; int tl_entry, tr_entry, bl_entry, br_entry; float tl_lats, tr_lats, bl_lats, br_lats; float tl_lons, tr_lons, bl_lons, br_lons; float frac_row, frac_col; float ax, bx, cx; float[][] latlon = new float[2][number]; // Convert array to Image coordinates for computations float[][] imglinele = areaCoordToImageCoord(linele); for (int point=0; point < number; point++) { rlin = imglinele[indexLine][point]; rele = imglinele[indexEle][point]; if (debug) { count ++; //if (count < 20) { System.out.println(" floats...ulline, lrlin, ulelem, lrele="+ulline+" "+lrlin+" "+ulelem+" "+lrele); System.out.println(" rlin, rele="+" "+rlin+" "+rele); //} } if (rlin < ulline || rlin > lrlin || rele < ulelem || rele > lrele) { latlon[indexLat][point] = Float.NaN; latlon[indexLon][point] = Float.NaN; } else { /* offset to the top_left (tl) corner lat/lon */ tl_entry = (((((int)rlin-ulline)/latres) * cols) + ((int)rele-ulelem) / lonres); /* offsets for top_right, bottom_left and bottom_left lat/lon corners */ tr_entry = tl_entry + 1; bl_entry = tl_entry + cols; br_entry = bl_entry + 1; // check to see if on last row or column... if ( (((int)rlin - ulline)/latres) >= rows-1) { bl_entry = tl_entry; br_entry = bl_entry + 1; } if ( (((int)rele -ulelem)/lonres) >= cols-1) { tr_entry = tl_entry; br_entry = bl_entry; } if (debug) { System.out.println(" tl_entry="+tl_entry+ " bl_entry="+bl_entry); } /* read the 4 corner latitudes */ tl_lats = latData[tl_entry]; tr_lats = latData[tr_entry]; bl_lats = latData[bl_entry]; br_lats = latData[br_entry]; /* read the 4 corner longitudes */ tl_lons = lonData[tl_entry]; tr_lons = lonData[tr_entry]; bl_lons = lonData[bl_entry]; br_lons = lonData[br_entry]; /* Check for missing lat/lon */ if ( (tl_lats == LAT_MISSING && tl_lons == LON_MISSING) || (tr_lats == LAT_MISSING && tr_lons == LON_MISSING) || (bl_lats == LAT_MISSING && bl_lons == LON_MISSING) || (br_lats == LAT_MISSING && br_lons == LON_MISSING) ) { latlon[indexLat][point] = Float.NaN; latlon[indexLon][point] = Float.NaN; } else { /* compute the fractional part of the row and column */ frac_row = (float)(((int)rlin-ulline) % latres) / (float)latres; frac_col = (float)(((int)rele-ulelem) % lonres) / (float)lonres; if (debug && count < 20) { if (linele[indexLine][point] < .1) { System.out.println(" lats: tl, tr, bl, br="+tl_lats+" "+tr_lats+" "+bl_lats+" "+br_lats); System.out.println(" frac_row="+frac_row+" frac_col="+frac_col); } } /* Calc the real lat */ ax = tr_lats - tl_lats; bx = bl_lats - tl_lats; cx = (tl_lats + br_lats) - (bl_lats + tr_lats); latlon[indexLat][point] = (ax * frac_col) + (bx * frac_row) + (cx * frac_row * frac_col) + tl_lats; /* Calc the real lon */ ax = tr_lons - tl_lons; bx = bl_lons - tl_lons; cx = (tl_lons + br_lons) - (bl_lons + tr_lons); latlon[indexLon][point] = (ax * frac_col) + (bx * frac_row) + (cx * frac_row * frac_col) + tl_lons; } } if (debug && count < 20) System.out.println(" line/ele = "+linele[indexLine][point]+"/"+linele[indexEle][point]+" rlin/rele="+rlin+"/"+rele+" Lat/Lon="+latlon[indexLat][point]+"/"+latlon[indexLon][point]); } // end point for loop return latlon; } public double[][] toLatLon(double[][] linele) { int number = linele[0].length; double[][] latlon = new double[2][number]; double rlin, rele; int tl_entry, tr_entry, bl_entry, br_entry; float tl_lats, tr_lats, bl_lats, br_lats; float tl_lons, tr_lons, bl_lons, br_lons; float frac_row, frac_col; float ax, bx, cx; // Convert array to Image coordinates for computations double[][] imglinele = areaCoordToImageCoord(linele); for (int point=0; point < number; point++) { rlin = imglinele[indexLine][point]; rele = imglinele[indexEle][point]; if (debug) { count ++; if (count < 20) { System.out.println(" double....ulline, lrlin, ulelem, lrele="+ulline+" "+lrlin+" "+ulelem+" "+lrele); System.out.println(" rlin, rele="+" "+rlin+" "+rele); } } if (rlin < ulline || rlin > lrlin || rele < ulelem || rele > lrele) { latlon[indexLat][point] = Double.NaN; latlon[indexLon][point] = Double.NaN; } else { /* offset to the top_left (tl) corner lat/lon */ tl_entry = (((((int)rlin-ulline)/latres) * cols) + ((int)rele-ulelem) / lonres); /* offsets for top_right, bottom_left and bottom_left lat/lon corners */ tr_entry = tl_entry + 1; bl_entry = tl_entry + cols; br_entry = bl_entry + 1; // check to see if on last row or column... if ( (((int)rlin - ulline)/latres) >= rows-1) { bl_entry = tl_entry; br_entry = bl_entry + 1; } if ( (((int)rele -ulelem)/lonres) >= cols-1) { tr_entry = tl_entry; br_entry = bl_entry; } if (debug && count < 20) { System.out.println(" tl_entry="+tl_entry+ " bl_entry="+bl_entry); } /* read the 4 corner latitudes */ tl_lats = latData[tl_entry]; tr_lats = latData[tr_entry]; bl_lats = latData[bl_entry]; br_lats = latData[br_entry]; /* read the 4 corner longitudes */ tl_lons = lonData[tl_entry]; tr_lons = lonData[tr_entry]; bl_lons = lonData[bl_entry]; br_lons = lonData[br_entry]; /* Check for missing lat/lon */ if ( (tl_lats == LAT_MISSING && tl_lons == LON_MISSING) || (tr_lats == LAT_MISSING && tr_lons == LON_MISSING) || (bl_lats == LAT_MISSING && bl_lons == LON_MISSING) || (br_lats == LAT_MISSING && br_lons == LON_MISSING) ) { latlon[indexLat][point] = Double.NaN; latlon[indexLon][point] = Double.NaN; } else { /* compute the fractional part of the row and column */ frac_row = (float)(((int)rlin-ulline) % latres) / (float)latres; frac_col = (float)(((int)rele-ulelem) % lonres) / (float)lonres; if (debug && count < 20) { System.out.println(" tl_entry="+tl_entry); if (linele[indexLine][point] < .1) { System.out.println(" lats: tl, tr, bl, br="+tl_lats+" "+tr_lats+" "+bl_lats+" "+br_lats); System.out.println(" frac_row="+frac_row+" frac_col="+frac_col); } } /* Calc the real lat */ ax = tr_lats - tl_lats; bx = bl_lats - tl_lats; cx = (tl_lats + br_lats) - (bl_lats + tr_lats); latlon[indexLat][point] = (ax * frac_col) + (bx * frac_row) + (cx * frac_row * frac_col) + tl_lats; /* Calc the real lon */ ax = tr_lons - tl_lons; bx = bl_lons - tl_lons; cx = (tl_lons + br_lons) - (bl_lons + tr_lons); latlon[indexLon][point] = (ax * frac_col) + (bx * frac_row) + (cx * frac_row * frac_col) + tl_lons; } } if (debug && count < 20) System.out.println(" line/ele = "+linele[indexLine][point]+"/"+linele[indexEle][point]+" rlin/rele="+rlin+"/"+rele+" Lat/Lon="+latlon[indexLat][point]+"/"+latlon[indexLon][point]); } // end point for loop return latlon; } /** * toLinEle converts lat/long to satellite line/element * transform an array of values in R^DomainDimension to an array * of non-integer grid coordinates * * @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) { try { float[][] ll = new float[2][latlon[0].length]; for (int k=0; k<ll[0].length; k++) { ll[0][k] = latlon[indexLon][k]; ll[1][k] = latlon[indexLat][k]; } float[][] linele = gs.valueToGrid(ll); for (int k=0; k<linele[0].length; k++) { linele[indexLine][k] = ulline + latres*linele[1][k]; linele[indexEle][k] = ulelem + lonres*linele[0][k]; } return imageCoordToAreaCoord(linele,linele); } catch (Exception e) { return null; } } public double[][] toLinEle(double[][] latlon) { try { float[][] ll = new float[2][latlon[0].length]; for (int k=0; k<ll[0].length; k++) { ll[0][k] = (float)latlon[indexLon][k]; ll[1][k] = (float)latlon[indexLat][k]; } float[][] xy = gs.valueToGrid(ll); double[][] linele = new double[2][xy[0].length]; for (int k=0; k<xy[0].length; k++) { linele[indexLine][k] = ulline + latres*xy[1][k]; linele[indexEle][k] = ulelem + lonres*xy[0][k]; } return imageCoordToAreaCoord(linele,linele); } catch (Exception e) { return null; } } }