001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
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 http://www.gnu.org/licenses.
027     */
028    
029    package edu.wisc.ssec.mcidasv.data;
030    
031    import edu.wisc.ssec.mcidas.AREAnav;
032    import edu.wisc.ssec.mcidas.McIDASUtil;
033    
034    import java.io.*;
035    import java.util.Date;
036    
037    /**
038     * Class FrameDirectory holds information obtained
039     * from frame directory files, FRAMEn.p, from McIdas-X
040     */
041    public 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    }