001/*
002 * $Id: FrameDirectory.java,v 1.10 2011/03/24 16:06:32 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 * 
012 * All Rights Reserved
013 * 
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.  
016 * 
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 * 
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025 * GNU Lesser Public License for more details.
026 * 
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program.  If not, see http://www.gnu.org/licenses.
029 */
030
031package edu.wisc.ssec.mcidasv.data;
032
033import edu.wisc.ssec.mcidas.AREAnav;
034import edu.wisc.ssec.mcidas.McIDASUtil;
035
036import java.io.*;
037import java.util.Date;
038
039/**
040 * Class FrameDirectory holds information obtained
041 * from frame directory files, FRAMEn.p, from McIdas-X
042 */
043public class FrameDirectory {
044
045    /** time of data in frame */
046    private Date nominalTime;
047
048    /** Sensor source name */
049    private String sensorName;
050
051    /** Sensor source number */
052    private int sensorNumber;
053
054    /** Year and Julian day, ccyyddd */
055    private int cyd;
056
057    /** Time, hhmmss */
058    private int hms;
059
060    /** Band number */
061    private int band;
062
063    /** Upper-left corner satellite coordinates */
064    private int uLLine;
065    private int uLEle;
066
067    /** Magnification factors */
068    private int lineMag;
069    private int eleMag;
070
071    /** Resolution factors */
072    private int lineRes;
073    private int eleRes;
074
075    /** Navigation block */
076    private int[] nav;
077
078    /** Navigation block */
079    private int[] aux;
080    
081    /** GRAF navigation type */
082    private int AREAnavGRAF = 1196572998;
083    
084    /**
085     * Constructor
086     */
087    public FrameDirectory() { }
088    
089    /**
090     * Copy constructor
091     *
092     * @param that The FrameDirectory to copy
093     *
094     */
095    public FrameDirectory(FrameDirectory that) {
096        this.sensorName = that.sensorName;
097        this.sensorNumber = that.sensorNumber;
098        this.cyd = that.cyd;
099        this.hms = that.hms;
100        this.nominalTime = new Date(1000*McIDASUtil.mcDayTimeToSecs(that.cyd,that.hms));
101        this.band = that.band;
102        this.uLLine = that.uLLine;
103        this.uLEle = that.uLEle;
104        this.lineMag = that.lineMag;
105        this.eleMag = that.eleMag;
106        this.lineRes = that.lineRes;
107        this.eleRes = that.eleRes;
108        this.nav = that.nav;
109        this.aux = that.aux;
110    }
111
112    /**
113     * Constructor
114     *
115     * @param directory frame directory from McIdax-X
116     *
117     */
118    public FrameDirectory(int[] directory) {
119        //System.out.println("FrameDirectory constructor:");
120        this.sensorNumber = directory[0];
121//        if (this.sensorNumber != -1)
122//          this.sensorName = getName(directory[0]);
123//        else
124//          this.sensorName = "";
125        this.sensorName = "";
126        this.cyd = directory[1];
127        this.hms = directory[2];
128        this.nominalTime = new Date(1000*McIDASUtil.mcDayTimeToSecs(cyd,hms));
129        this.band = directory[3];
130        this.uLLine = directory[4];
131        this.uLEle = directory[5];
132        this.lineRes = directory[10];
133        this.eleRes = directory[11];
134        this.lineMag = directory[19];
135        this.eleMag = directory[20];
136
137//        if (this.lineMag < 0) this.lineMag = 1;
138//        if (this.eleMag < 0) this.eleMag = 1;     
139//        this.lineMag=1;
140//        this.eleMag=1;
141        
142/*
143        System.out.println("  cyd=" + cyd);
144        System.out.println("  hms=" + hms);
145        System.out.println("  band=" + band);
146        System.out.println("  uLLine=" + uLLine);
147        System.out.println("  uLEle=" + uLEle);
148        System.out.println("  lineMag=" + lineMag);
149        System.out.println("  eleMag=" + eleMag);
150        System.out.println("  lineRes=" + lineRes);
151        System.out.println("  eleRes=" + eleRes);
152*/
153//        System.out.println("Navigation type " + directory[64] + ": " + navIntToString(directory[64]));
154               
155        int navLength;
156        if (directory[64] == AREAnav.LALO) navLength = 128;
157        else navLength = 640;
158        this.nav = new int[navLength];
159        System.arraycopy(directory, 64, this.nav, 0, navLength);
160        
161        if (this.nav[0] == this.AREAnavGRAF)
162                this.nav = transformGRAFIntoRECT(this.nav);
163        
164        int auxLength = 0;
165        int rows = 0;
166        int cols = 0;
167        int begLat = 0;
168        int begLon = 0;
169        if (this.nav[0] == AREAnav.LALO) {
170          rows = this.nav[65];
171          cols = this.nav[66];
172          begLat = this.nav[78]/4;
173          begLon = this.nav[79]/4;
174          auxLength = begLon + (rows*cols);
175          this.aux = new int[auxLength];
176        }
177        else {
178          this.aux = new int[1];
179        }
180        int numPoints = rows * cols;
181        System.arraycopy(directory, 64+navLength, this.aux, begLat, numPoints);
182        if (auxLength > 0) {
183                System.arraycopy(directory, 64+navLength+numPoints, this.aux, begLon, numPoints);
184        }
185//        System.out.println("FrameDirectory navLength: " + navLength + ", auxLength: " + auxLength); 
186    }
187
188    /* 
189     * TODO: FrameDirectory.getName() is not used right now... keep the code here just in case.
190     * If you do decide you need it, read SATANNOT over the bridge, not locally...
191     */
192/*
193     public String getName(int num) {
194       String name = "";
195       FileInputStream fis;
196       //byte[] bline={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
197       byte[] bline = new byte[31];
198       int off=0;
199       int ret = 0;
200       int sensor=0;
201
202       System.out.println("Fix this: SATANNOT should not be read locally");
203       try {
204         fis  = new FileInputStream("/home/mcidas/data/SATANNOT");
205       } catch(Exception e) {
206           System.out.println("FrameDirectory: Can't find SATANNOT");
207           return name;
208       }
209       int counter=0;
210       int sensor1=0;
211       int sensor2=0;
212       int sensor3=0;
213       while (ret != -1) {
214         try {
215           int ptr=0;
216           int next=0;
217           for (int i=0;i<19; i++) { 
218             next = fis.read();
219             bline[ptr] = (byte)next;
220             ptr++;
221           }
222           name = new String(bline, 0, ptr);
223           for (int i=20;i<30; i++) {
224             off = fis.read();
225           }
226           sensor1 = fis.read()-48;
227           sensor2 = fis.read()-48;
228           sensor3 = fis.read()-48;
229           sensor = 0;
230           if (sensor1 >= 0) {
231             sensor = sensor1;
232           }
233           if (sensor2 >= 0) {
234             sensor *= 10;
235             sensor += sensor2;
236           }
237           if (sensor3 >= 0) {
238             sensor *= 10;
239             sensor += sensor3;
240           }
241           for (int i=32; i<80; i++)
242             off = fis.read();
243         } catch(Exception e) {
244           System.out.println("FrameDirectory: Can't read SATANNOT");
245           try {
246               fis.close();
247           } catch (Exception ee) {
248           }
249           return name;
250         }
251         if (sensor == num) ret =-1;
252         counter++;
253         if (counter>200) ret=-1;
254       }
255       try {
256           fis.close();
257       } catch (Exception e) {
258       }
259       return name;
260     }
261*/
262
263    /**
264     * Get the nominalTime.
265     *
266     * @return The nominalTime.
267     */
268    public Date getNominalTime() {
269        return this.nominalTime;
270    }
271
272    /**
273     * Get the sensorName.
274     *
275     * @return The sensorName.
276     */
277    public String getSensorName() {
278        return this.sensorName;
279    }
280
281    /**
282     * Get the sensorNumber.
283     *
284     * @return The sensorNumber.
285     */
286    public int getSensorNumber() {
287        return this.sensorNumber;
288    }
289
290    /**
291     * Get cyd.
292     *
293     * @return cyd.
294     */
295    public int getCyd() {
296        return this.cyd;
297    }
298
299    /**
300     * Get hms.
301     *
302     * @return hms.
303     */
304    public int getHms() {
305        return this.hms;
306    }
307
308    /**
309     * Get band.
310     *
311     * @return band.
312     */
313    public int getBand() {
314        return this.band;
315    }
316
317    /**
318     * Set sensorName.
319     *
320     * @param newName The new vaue for sensorName.
321     */
322    public void setSensorName(String newName) {
323        this.sensorName = newName;
324    }
325
326    /**
327     * Set cyd.
328     *
329     * @param newCyd The new vaue for cyd.
330     */
331    public void setCyd(int newCyd) {
332        this.cyd = newCyd;
333    }
334
335    /**
336     * Set hms.
337     *
338     * @param newHms The new vaue for hms.
339     */
340    public void setHms(int newHms) {
341        this.hms = newHms;
342    }
343
344    /**
345     * Set band.
346     *
347     * @param newBand The new vaue for band.
348     */
349    public void setBand(int newBand) {
350        this.band = newBand;
351    }
352
353    /**
354     * Get a String representation of this object
355     * @return a string representation
356     */
357    public String toString() {
358        StringBuffer buf = new StringBuffer();
359        buf.append(this.sensorName + " ");
360        buf.append(this.sensorNumber + " ");
361        buf.append(this.cyd + " ");
362        buf.append(this.hms + " ");
363        buf.append(this.band);
364        return buf.toString();
365    }
366
367    public int[] getFrameNav() {
368        return nav;
369    }
370
371    public int[] getFrameAux() {
372        return aux;
373    }
374
375    public int getLineRes() {
376        return lineRes;
377    }
378
379    public int getEleRes() {
380        return eleRes;
381    }
382
383    public int getULLine() {
384        return uLLine;
385    }
386
387    public int getULEle() {
388        return uLEle;
389    }
390    
391    /**
392     * Print the nav type
393     */
394    private String navIntToString(int navInt) {
395        int int1 = navInt/0x1000000&0xff;
396        int int2 = navInt/0x10000&0xff;
397        int int3 = navInt/0x100&0xff;
398        int int4 = navInt&0xff;
399        String char1 = new Character((char)int1).toString();
400        String char2 = new Character((char)int2).toString();
401        String char3 = new Character((char)int3).toString();
402        String char4 = new Character((char)int4).toString();
403        String returnString = char1 + char2 + char3 + char4;
404        return returnString;
405    }
406    
407    /**
408     * Since GRAF is not a real data projection, try to munge it into RECT for VisAD
409     */
410    private int[] transformGRAFIntoRECT(int[] nav) {
411        if (nav[0] != this.AREAnavGRAF) return nav;
412        int[] RECT = nav;
413        int minLat = RECT[21];
414        int maxLat = RECT[22];
415        int minLon = RECT[23];
416        int maxLon = RECT[24];
417        int minY = RECT[25];
418        int maxY = RECT[26];
419        int minX = RECT[27];
420        int maxX = RECT[28];
421        int centerLat = Math.round((maxLat - minLat) / 2) + minLat;
422        int centerLon = Math.round((maxLon - minLon) / 2) + minLon;
423        int rangeLat = maxLat - minLat;
424        int rangeLon = maxLon - minLon;
425        int centerY = Math.round((maxY - minY) / 2) + minY;
426        int centerX = Math.round((maxX - minX) / 2) + minX;
427        int rangeY = maxY - minY;
428        int rangeX = maxX - minX;
429        RECT[0] = AREAnav.RECT;
430        RECT[1] = centerY - minY;
431        RECT[2] = centerLat;
432        RECT[3] = centerX - minX;
433        RECT[4] = centerLon;
434        RECT[5] = Math.round(rangeLat / rangeY);
435        RECT[6] = Math.round(rangeLon / rangeX);
436        // Earth constants (eccentricity and radius)
437        RECT[7] = 6378388;
438        RECT[8] = 81992;
439        for (int i=9; i<24; i++) RECT[i] = 0;
440        return RECT;
441    }
442}