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