001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2017
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
029package edu.wisc.ssec.mcidasv.adt;
030
031public class Scene {
032
033   private static double[] BDCurve_Points =
034   { 30.0,  9.0,-30.0,-42.0,-54.0,
035    -64.0,-70.0,-76.0,-80.0,-84.0,-100.0};
036
037   private static double LARGE_EYE_RADIUS = 38.0;
038   private static double RING_WIDTH = 4.0;
039   private static double MANUAL_EYE_RADIUS = 24.0;
040   private static float[][] IRImageLatitudeArrayLocal = new float[200][200];
041   private static float[][] IRImageLongitudeArrayLocal = new float[200][200];
042   private static float[][] IRImageTemperatureArrayLocal = new float[200][200];
043   private static int IRImageXSize;
044   private static int IRImageYSize;
045
046   public Scene() {
047      IRImageXSize = -1;
048      IRImageYSize = -1;
049   }
050   
051   /**
052    * adt_classify in original ADT codebase.
053    *
054    * @param RunFullAnalysis Whether or not a complete scene analysis should
055    *                        happen.
056    */
057   public static void DetermineSceneType(boolean RunFullAnalysis) {
058      
059      int XInc;
060      int PreviousHistoryEyeSceneID = -1;
061      int PreviousHistoryCloudSceneID = -1;
062      double PreviousHistoryTnoValueMinus12hrs = 0.0;
063      boolean FoundHistoryRecMinus12hrTF = false;
064      double TemperatureValue = -999.0;
065      int LogSpiralAmount = 0;
066
067      int CloudBDCategory = -99;
068      int CloudCWBDCategory = -99;
069      int EyeBDCategory = -99;
070      int CloudBDDifference = -99;
071      int EyeCloudBDCategoryDifference = -99;
072      double TnoInterpValue = -99.9;
073      double CloudBDCategoryFloat = -99.9;
074      double EyeBDCategoryFloat = -99.9;
075      double CloudCWBDCategoryFloat = -99.9;
076      double CloudTemperatureDifference = -99.9;
077      double EyeCloudCWBDCategoryFloatDiff = -99.9;
078      double EyeCloudBDCategoryFloatDiff = -99.9;
079      double CloudBDCategoryFloatDiff = -99.9;
080      double EyeCloudTemperatureDiff2 = -99.9;
081
082      boolean LandFlagTF = Env.LandFlagTF;
083      double InitStrengthValue = Env.InitRawTValue;
084      double RMWSize = Env.RMWSize;
085
086      int EyeFFTValue = History.IRCurrentRecord.eyefft;
087      int CloudFFTValue = History.IRCurrentRecord.cloudfft;
088      double StormLatitude = History.IRCurrentRecord.latitude;
089      double StormLongitude = History.IRCurrentRecord.longitude;
090      double EyeTemperature = History.IRCurrentRecord.eyet;
091      double EyeStdvValue = History.IRCurrentRecord.eyestdv;
092      double CloudCWTemperature = History.IRCurrentRecord.cwcloudt;
093      double CloudTemperature = History.IRCurrentRecord.cloudt;
094      double CloudSymmetryValue = History.IRCurrentRecord.cloudsymave;
095      double CurvedBandBDMaxLatitude = StormLatitude;
096      double CurvedBandBDMaxLongitude = StormLongitude;
097
098      for(XInc=0;XInc<10;XInc++) {
099         /* compute cloud category */
100         if((CloudTemperature<=BDCurve_Points[XInc])&&
101            (CloudTemperature>BDCurve_Points[XInc+1])) {
102            CloudBDCategory = XInc;
103            TnoInterpValue = (CloudTemperature-BDCurve_Points[CloudBDCategory])/
104                           (BDCurve_Points[CloudBDCategory+1]-
105                            BDCurve_Points[CloudBDCategory]);
106            if(CloudBDCategory==0) {
107               TnoInterpValue = 0.0;
108            }
109            CloudBDCategoryFloat = (double)CloudBDCategory+TnoInterpValue;
110         }
111         /* compute eye category */
112         if((EyeTemperature<=BDCurve_Points[XInc])&&
113            (EyeTemperature>BDCurve_Points[XInc+1])) {
114            EyeBDCategory = XInc;
115            TnoInterpValue = (EyeTemperature-BDCurve_Points[EyeBDCategory])/
116                           (BDCurve_Points[EyeBDCategory+1]-
117                            BDCurve_Points[EyeBDCategory]);
118            if(EyeBDCategory==0) {
119               TnoInterpValue = 0.0;
120            }
121            EyeBDCategoryFloat = (double)EyeBDCategory+TnoInterpValue;
122         }
123         /* compute C-W eye category */
124         if((CloudCWTemperature<=BDCurve_Points[XInc])&&
125            (CloudCWTemperature>BDCurve_Points[XInc+1])) {
126            CloudCWBDCategory = XInc;
127            TnoInterpValue = (CloudCWTemperature-BDCurve_Points[CloudCWBDCategory])/
128                           (BDCurve_Points[CloudCWBDCategory+1]-
129                            BDCurve_Points[CloudCWBDCategory]);
130            if(CloudCWBDCategory==0) {
131               TnoInterpValue = 0.0;
132            }
133            CloudCWBDCategoryFloat = (double)CloudCWBDCategory+TnoInterpValue;
134         }
135      }
136   
137      /*
138       * System.out.printf("EYE = temp=%f cat=%d part=%f \n",EyeTemperature,EyeBDCategory,
139       *                                        EyeBDCategoryFloat);
140       * System.out.printf("CLD = temp=%f cat=%d part=%f \n",CloudTemperature,CloudBDCategory,
141       *                                        CloudBDCategoryFloat);
142       * System.out.printf("CWT = temp=%f cat=%d part=%f \n",CloudCWTemperature,
143       *                                        CloudCWBDCategory,
144       *                                        CloudCWBDCategoryFloat);
145       */
146
147      CloudTemperatureDifference = CloudTemperature-CloudCWTemperature;
148      EyeCloudCWBDCategoryFloatDiff = CloudCWBDCategoryFloat-EyeBDCategoryFloat;
149      EyeCloudBDCategoryFloatDiff = CloudBDCategoryFloat-EyeBDCategoryFloat;
150      CloudBDCategoryFloatDiff = CloudBDCategoryFloat-CloudCWBDCategoryFloat;
151      CloudBDDifference = CloudBDCategory-CloudCWBDCategory;
152      EyeCloudBDCategoryDifference = CloudBDCategory-EyeBDCategory;
153      EyeCloudTemperatureDiff2 = EyeTemperature-(Math.min(CloudTemperature,CloudCWTemperature));
154
155      /*
156       * System.out.printf("BDCategoryDifference=%d\n",BDCategoryDifference);
157       * System.out.printf("EyeCloudBDCategoryDifference=%d\n",EyeCloudBDCategoryDifference);
158       * System.out.printf("CloudBDDifference=%d\n",CloudBDDifference);
159       * System.out.printf("CloudTemperatureDifference=%f\n",CloudTemperatureDifference);
160       * System.out.printf("EyeCloudTemperatureDifference=%f\n",EyeCloudTemperatureDifference);
161       * System.out.printf("EyeCloudCWBDCategoryFloatDiff=%f\n",EyeCloudCWBDCategoryFloatDiff);
162       * System.out.printf("EyeCloudBDCategoryFloatDiff=%f\n",EyeCloudBDCategoryFloatDiff);
163       * System.out.printf("CloudBDCategoryFloatDiff=%f\n",CloudBDCategoryFloatDiff);
164       * System.out.printf("EyeCloudTemperatureDiff2=%f\n",EyeCloudTemperatureDiff2);
165       */
166      
167      int ImageDate = History.IRCurrentRecord.date;
168      int ImageTime = History.IRCurrentRecord.time;
169
170      double CurrentTime = Functions.calctime(ImageDate,ImageTime);
171      /* System.out.printf("current time=%f\n",CurrentTime); */
172
173      double CurrentTimeMinus12hr = CurrentTime-0.5;
174      boolean FoundEyeSceneTF = false;
175      double MaximumRule9Value = -99.0;
176      int LastRule9Value = 0;
177      double PreviousHistoryTnoValue = MaximumRule9Value;
178      double PreviousValidHistoryTnoValue = PreviousHistoryTnoValue;
179
180      int HistoryFileRecords = History.HistoryNumberOfRecords();
181
182      if((HistoryFileRecords==0)||(!RunFullAnalysis)) {
183         FoundHistoryRecMinus12hrTF = true;
184         PreviousHistoryEyeSceneID = 3;
185         LastRule9Value = 1;
186         if((CloudCWBDCategoryFloat<3.5)&&(InitStrengthValue<3.5)) {
187            PreviousHistoryCloudSceneID = 3;
188            PreviousHistoryTnoValueMinus12hrs = InitStrengthValue;
189         } else {
190            PreviousHistoryCloudSceneID = 0;
191            PreviousHistoryTnoValueMinus12hrs = Math.max(InitStrengthValue,4.0);
192         }
193
194      } else {
195         FoundHistoryRecMinus12hrTF = false;
196         PreviousHistoryCloudSceneID = 3;
197
198         int RecDate,RecTime,RecLand;
199         int RecEyeScene,RecCloudScene;
200         int RecRule9;
201         double LastValidHistoryRecTime=0.0;
202         double HistoryRecTime;
203         double RecTnoRaw,RecTnoFinal;
204         boolean LandCheckTF;
205         for(XInc=0;XInc<HistoryFileRecords;XInc++) {
206            RecDate = History.HistoryFile[XInc].date;
207            RecTime = History.HistoryFile[XInc].time;
208            RecLand = History.HistoryFile[XInc].land;
209            RecTnoRaw = History.HistoryFile[XInc].Traw;
210            HistoryRecTime = Functions.calctime(RecDate,RecTime);
211            LandCheckTF = true; 
212            if(((LandFlagTF)&&(RecLand==1))||(RecTnoRaw<1.0)) {
213               LandCheckTF = false;
214            }
215            if((HistoryRecTime<CurrentTime)&&(LandCheckTF)) {
216               LastValidHistoryRecTime = HistoryRecTime;
217               RecTnoFinal = History.HistoryFile[XInc].Tfinal;
218               RecEyeScene = History.HistoryFile[XInc].eyescene;
219               RecCloudScene = History.HistoryFile[XInc].cloudscene;
220               RecRule9 = History.HistoryFile[XInc].rule9;
221               if((HistoryRecTime>=CurrentTimeMinus12hr)&&
222                  (!FoundHistoryRecMinus12hrTF)) {
223                 PreviousHistoryTnoValueMinus12hrs = RecTnoFinal;
224                 FoundHistoryRecMinus12hrTF = true;
225               }
226               PreviousHistoryTnoValue = RecTnoFinal;
227               PreviousHistoryCloudSceneID = RecCloudScene;
228               PreviousHistoryEyeSceneID = RecEyeScene;
229               if(PreviousHistoryEyeSceneID<=2) {
230                  FoundEyeSceneTF = true;
231               }
232               if((PreviousHistoryCloudSceneID==4)&&
233                  (PreviousHistoryEyeSceneID==3)) {
234                  FoundEyeSceneTF = false;
235               }
236               PreviousValidHistoryTnoValue = PreviousHistoryTnoValue;
237               LastRule9Value = RecRule9;
238               if(PreviousHistoryTnoValue>MaximumRule9Value) {
239                  MaximumRule9Value = PreviousHistoryTnoValue;
240               }
241            } else {
242               if(!LandCheckTF) {
243                  /* if over land for > 12 hours, turn off FoundEyeSceneTF */
244                  if((HistoryRecTime-LastValidHistoryRecTime)>0.5) {
245                     FoundEyeSceneTF = false;
246                     PreviousHistoryTnoValue = PreviousValidHistoryTnoValue-
247                              (1.0*(HistoryRecTime-LastValidHistoryRecTime));
248                     /*
249                      * printf("PreviousValidHistoryTnoValue=%f  deltatime=%f
250                      *         PreviousHistoryTnoValue=%f\n",
251                      *         PreviousValidHistoryTnoValue,
252                      *         HistoryRecTime-LastValidHistoryRecTime,
253                      *         PreviousHistoryTnoValue);
254                      */
255                  }
256               }
257            }
258         }
259         /* check for large break in history file */
260         if(!FoundHistoryRecMinus12hrTF) {
261            PreviousHistoryTnoValueMinus12hrs = PreviousHistoryTnoValue;
262         }
263      }
264
265      /* System.out.printf("FoundHistoryRecMinus12hrTF=%b\n",FoundHistoryRecMinus12hrTF); */
266      /* System.out.printf("PreviousHistoryTnoValueMinus12hrs=%f\n",PreviousHistoryTnoValueMinus12hrs); */
267
268      int EyeSceneIDValue;
269      double EyeSceneFactorC = 0.0;
270      double EyeSceneFactorE = 0.0;
271      double EyeSceneFactorA = 1.0-((EyeFFTValue-2)*0.1);
272      double EyeSceneFactorB = -(EyeBDCategoryFloat*0.5);
273
274      if(EyeStdvValue>10.0) {
275         EyeSceneFactorC = 0.50;
276      }
277      double EyeSceneFactorD = (EyeCloudBDCategoryFloatDiff*0.25)+
278                      (EyeCloudCWBDCategoryFloatDiff*0.50);
279      
280      /* System.out.printf("EyeSceneFactorD=%f\n",EyeSceneFactorD); */
281      /* System.out.printf("MaximumRule9Value=%f EyeSceneFactorE=%f\n",MaximumRule9Value,EyeSceneFactorE); */
282      
283      if((FoundHistoryRecMinus12hrTF)&&(PreviousHistoryEyeSceneID<3)&&
284         (MaximumRule9Value>5.0)) {
285         EyeSceneFactorC = EyeSceneFactorC+0.25;    /* changed from EyeSceneFactorE */
286      }
287      /* System.out.printf("EyeSceneFactorE=%f\n",EyeSceneFactorE); */
288      if(PreviousHistoryTnoValueMinus12hrs<=4.5) {
289         EyeSceneFactorE = Math.max(-1.0,PreviousHistoryTnoValueMinus12hrs-4.5);
290      }
291      
292      /* System.out.printf("PreviousHistoryTnoValueMinus12hrs=%f  EyeSceneFactorE=%f\n",
293                          PreviousHistoryTnoValueMinus12hrs,EyeSceneFactorE); */ 
294
295      if((LastRule9Value>0)&&(PreviousHistoryTnoValue<4.0)) {
296         EyeSceneFactorE = EyeSceneFactorE-0.5;
297      }
298      /* System.out.printf("EyeSceneFactorE=%f\n",EyeSceneFactorE); */
299      double EyeFactorTotal = EyeSceneFactorA+EyeSceneFactorB+EyeSceneFactorC+
300                              EyeSceneFactorD+EyeSceneFactorE;
301      EyeSceneIDValue = 3;                                 /* NO EYE */
302      if(EyeFactorTotal>=0.50) {
303         EyeSceneIDValue = 0;                              /* EYE */
304      }
305      
306      /* System.out.printf("EyeFactorTotal= %f  EyeSceneIDValue=%d \n",EyeFactorTotal,EyeSceneIDValue); */
307      
308      double EyeCDOSizeValue = 0.0;
309      /* System.out.printf("RMW SIZE=%f\n",RMWSize); */
310      if(RMWSize>0.0) {
311         /* System.out.printf("Manually Entered RMW Size=%f\n",RMWSize); */
312         History.IRCurrentRecord.rmw = RMWSize;
313         EyeCDOSizeValue = RMWSize-1.0; /* manually input eye size */
314      } else {
315         /* System.out.printf("Calculating RMW Size\n"); */
316         double LocalValue[] = Data.CalcRMW();
317         double RadiusMaxWind = LocalValue[0];
318         /* System.out.printf("Calculated RMW Size=%f\n",RadiusMaxWind); */
319         History.IRCurrentRecord.rmw = RadiusMaxWind;
320      }
321    
322      /* LARGE EYE CHECKS */
323      double LargeEyeRadius = LARGE_EYE_RADIUS;
324      if((EyeSceneIDValue==0)&&(EyeCDOSizeValue>=LargeEyeRadius)) {
325         EyeSceneIDValue = 2;                               /* large eye */
326      }
327
328      /* NEW CLOUD SCENE THRESHOLD DETERMINATION */
329      boolean ShearSceneTF = false;
330      boolean IrregularCDOSceneTF = false;
331      boolean CurvedBandSceneTF = true;
332      boolean CurvedBandBDGrayShadeTF = true;
333      boolean CurvedBandBDBlackWhiteTF = false;
334      boolean EmbeddedCenterCheckTF = false;
335      boolean EmbeddedCenterSceneTF = false;
336    
337      double CloudSceneFactorC = 0.0;
338      double CloudSceneFactorD = 0.5;
339      double CloudSceneFactorE = 0.0;
340      double CloudSceneFactorA = CloudCWBDCategoryFloat*0.25;
341      double CloudSceneFactorB = CloudBDCategoryFloat*0.25;
342      if(CloudFFTValue<=2) {
343         CloudSceneFactorC = Math.min(1.50,CloudCWBDCategoryFloat*0.25);
344      }
345      if(PreviousHistoryCloudSceneID>=3) {
346         CloudSceneFactorD = -0.50;
347      }
348      
349      /* System.out.printf("CloudCWBDCategoryFloat=%f PreviousHistoryTnoValueMinus12hrs=%f\n",
350               CloudCWBDCategoryFloat,PreviousHistoryTnoValueMinus12hrs); */
351      
352      if(CloudCWBDCategoryFloat>2.0) {
353         if(PreviousHistoryTnoValueMinus12hrs>=2.5) {
354            if(EyeSceneIDValue==0) {
355               CloudSceneFactorE = Math.min(1.00,PreviousHistoryTnoValueMinus12hrs-2.5);
356            }
357            if(PreviousHistoryTnoValueMinus12hrs>=3.5) {
358               CloudSceneFactorE = CloudSceneFactorE+1.00;
359            }
360         }
361         if((FoundHistoryRecMinus12hrTF)&&
362            (FoundEyeSceneTF)) CloudSceneFactorE = CloudSceneFactorE+1.25;
363      }
364      double CloudFactorTotal = CloudSceneFactorA+CloudSceneFactorB+CloudSceneFactorC+
365                                CloudSceneFactorD+CloudSceneFactorE;
366      if(CloudFactorTotal<0.0) {
367         ShearSceneTF = true;                            /* SHEAR */
368      }
369      if(CloudFactorTotal>=0.00) {
370         CurvedBandSceneTF = true;                       /* CURVED BAND (gray) */
371      }
372      if(CloudFactorTotal>=1.00) {
373         CurvedBandSceneTF = true;                       /* CURVED BAND (gray) */
374         /* check for irregular CDO */
375         if((EyeCloudTemperatureDiff2<0.0)&&(CloudSymmetryValue>40.0)) {
376            IrregularCDOSceneTF = true;                  /* IRREGULAR CDO */
377         }
378      }
379      if((CloudFactorTotal>=2.00)&&(CloudFactorTotal<3.00)) {
380         CurvedBandSceneTF = true;                       /* CURVED BAND (gray) */
381        /* check for irregular CDO */
382         if((EyeCloudTemperatureDiff2<0.0)&&(CloudSymmetryValue>30.0)) {
383            IrregularCDOSceneTF = true;                  /* IRREGULAR CDO */
384         }
385         if(CloudCWBDCategory>=3) {
386            /* if xcwt>3.0 try black/white CB check */
387            if((CloudBDDifference>0)&&
388               (CloudTemperatureDifference<-8.0)) {
389               CurvedBandBDGrayShadeTF = false;          /* CURVED BAND (b/w) */
390               CurvedBandBDBlackWhiteTF = true;
391            }
392            /* check for large/ragged eye */
393            if((EyeSceneIDValue==0)||
394               ((EyeBDCategoryFloat>1.00)&&
395                (EyeCloudBDCategoryDifference>=2.00))) {
396               CurvedBandSceneTF = false;                /* EYE */
397            }
398            /* check for CDO */
399            if((CloudBDCategoryFloatDiff<=0.0)&&
400               (EyeCloudCWBDCategoryFloatDiff<1.00)) {
401               CurvedBandSceneTF = false;                /* CDO */
402            }
403         }
404      }
405      if(CloudFactorTotal>=3.00) {
406         CurvedBandSceneTF=false;                      /* CDO */
407         /* check for irregular CDO */
408         if((CloudBDDifference<0)&&
409            (CloudTemperatureDifference>8.0)&&(CloudSymmetryValue>30.0)) {
410            IrregularCDOSceneTF = true;                  /* IRREGULAR CDO */
411            CurvedBandSceneTF = true;
412         }
413      }
414      /* EMBEDDED CENTER CHECK */
415      if((CloudTemperature<CloudCWTemperature)&&
416         (CloudCWTemperature<EyeTemperature)) {
417         EmbeddedCenterCheckTF = true;
418      }
419      if((!CurvedBandSceneTF)&&(EmbeddedCenterCheckTF)) {
420         TemperatureValue=BDCurve_Points[CloudCWBDCategory+1]+273.16;
421         double ReturnValues[] = Scene.adt_logspiral(StormLatitude,StormLongitude,TemperatureValue,1);
422         LogSpiralAmount = (int)ReturnValues[0];
423         if((LogSpiralAmount>=8)&&(LogSpiralAmount<20)) {
424            EmbeddedCenterSceneTF = true;
425         }
426        
427         /* System.out.printf(" EMBDD : CloudCWBDCategory=%d LogSpiralAmount=%d \n",
428                 CloudCWBDCategory,LogSpiralAmount); */
429        
430      }
431      
432      /* System.out.printf("CloudFactorTotal= %f  ShearSceneTF=%b CurvedBandSceneTF=%b CurvedBandBDGrayShadeTF=%b IrregularCDOSceneTF=%b \n",
433               CloudFactorTotal,ShearSceneTF,CurvedBandSceneTF,CurvedBandBDGrayShadeTF,IrregularCDOSceneTF); */
434       
435      /*
436       * System.out.printf("%9s %6d %4.1f %4.1f %2d %2d %5.1f %5.1f  %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f  %2d %2d %4.1f %4.1f  %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f   %6.2f %7.2f %3.1f  \n",ImageDateString,ImageTime,
437       * CloudBDCategoryFloat,CloudCWBDCategoryFloat,CloudFFTValue,
438       * CloudBDDifference,CloudTemperatureDifference,CloudSymmetryValue,
439       * CloudSceneFactorA,CloudSceneFactorB,0.0,CloudSceneFactorC,
440       * CloudSceneFactorD,CloudSceneFactorE,CloudFactorTotal,
441       * EyeFFTValue,EyeCloudBDCategoryDifference,EyeBDCategoryFloat,EyeStdvValue,
442       * EyeSceneFactorA,EyeSceneFactorB,EyeSceneFactorC,EyeSceneFactorD,
443       * EyeSceneFactorE,EyeFactorTotal,StormLatitude,StormLongitude,
444       * PreviousHistoryTnoValue);
445       */
446
447      /* CLASSIFY CLOUD REGION */
448      int CurvedBandBDCategory = 0;
449      int CurvedBandBDAmount = 0;
450      int CurvedBandBDMaxAmount = 0;
451      int CloudSceneIDValue = -99;
452      boolean FoundCurvedBandSceneTF = false;
453      double ShearDistance = -99.0;
454    
455      /* System.out.printf("CurvedbandsceneTF=%b  IrregularCDOTF=%b  ShearSceneTF=%b \n",CurvedBandSceneTF,IrregularCDOSceneTF,ShearSceneTF); */
456      if(CurvedBandSceneTF) {
457         if(ShearSceneTF) {
458            EyeSceneIDValue = 3;                         /* NO EYE */
459            CloudSceneIDValue = 4;                       /* SHEAR */
460            TemperatureValue = ((BDCurve_Points[2]+BDCurve_Points[3])/2.0)+273.16;
461            ShearDistance = adt_cdoshearcalc(StormLatitude,StormLongitude,TemperatureValue,3);
462            EyeCDOSizeValue = Math.max(4.0,ShearDistance);
463         }
464         else if(IrregularCDOSceneTF) {
465            EyeSceneIDValue = 3;                         /* NO EYE */
466            CloudSceneIDValue = 2;                       /* IRREGULAR CDO */
467         }
468         else {
469            FoundCurvedBandSceneTF = false;
470            if(CurvedBandBDGrayShadeTF) {
471               /* perform Curved Band analysis */
472               XInc = 4;  /* start with LIGHT GRAY */
473               while((XInc>=2)&&(!FoundCurvedBandSceneTF)) {
474                  TemperatureValue = BDCurve_Points[XInc]+273.16;
475                  double ReturnValues[] = Scene.adt_logspiral(StormLatitude,StormLongitude,TemperatureValue,1);
476                  LogSpiralAmount = (int)ReturnValues[0];
477                  if((LogSpiralAmount>=8)||(XInc==2)) {
478                     /* 10 = .375% -- 10 ==> 9 arcs of 15 degrees */
479                     if(LogSpiralAmount>25) {
480                        if(XInc==4) {
481                          CurvedBandBDGrayShadeTF = false;
482                          CurvedBandBDBlackWhiteTF = true;
483                          /* following line to exit out of While statement */
484                          FoundCurvedBandSceneTF = true;
485                        }
486                        else {
487                          XInc = 0;
488                        }
489                     }
490                     else {
491                      if((XInc==2)&&(LogSpiralAmount<7)) {
492                          /* 7 = .25% -- 10 ==> 6 arcs of 15 degrees */
493                          /* probably shear */
494                          FoundCurvedBandSceneTF = false;
495                          CurvedBandBDBlackWhiteTF = false;
496                          ShearSceneTF = true;
497                          /* gross error check... added 08/15/13 */
498                          if((EyeBDCategoryFloat>1.5)||(CloudBDCategoryFloat>2.5)) {
499                            ShearSceneTF = false;
500                            IrregularCDOSceneTF = true;
501                          }
502                          /* following line to exit out of While statement */
503                          XInc--;
504                       }
505                       else {
506                          FoundCurvedBandSceneTF = true;
507                       }
508                     }
509                  }
510                  else {
511                     XInc--;
512                  }
513               }
514            }
515            if(CurvedBandBDBlackWhiteTF) {
516               /* try BLACK and WHITE rings */
517               FoundCurvedBandSceneTF = false;
518               CurvedBandSceneTF = false;
519               XInc = 6;
520               while((XInc>4)&&(!FoundCurvedBandSceneTF)) {
521                  TemperatureValue = BDCurve_Points[XInc]+273.16;
522                  double ReturnValues[] = Scene.adt_logspiral(StormLatitude,StormLongitude,TemperatureValue,1);
523                  LogSpiralAmount = (int)ReturnValues[0];
524                  if((LogSpiralAmount>=9)&&(LogSpiralAmount<=25)) {
525                     FoundCurvedBandSceneTF = true;
526                     /* EmbeddedCenterSceneTF = true;   needed here? */
527                  }
528                  else {
529                     XInc--;
530                  }
531               }
532            }
533            if(FoundCurvedBandSceneTF) {
534               /* found curved band scenes */
535               CurvedBandBDCategory = XInc;
536               CurvedBandBDAmount = LogSpiralAmount;
537               EyeSceneIDValue = 3;                      /* NO EYE */
538               CloudSceneIDValue = 3;                    /* CURVED BAND */
539               /* search for max curved band analysis location w/in 1-degree box */
540               TemperatureValue = BDCurve_Points[CurvedBandBDCategory]+273.16;
541               boolean CBSearchTF_Global = true;
542               if(CBSearchTF_Global) {   /* need global variable here */
543                  double ReturnValues[] = Scene.adt_logspiral(StormLatitude,StormLongitude,TemperatureValue,2);
544                  CurvedBandBDMaxAmount = (int)ReturnValues[0];
545                  CurvedBandBDMaxLatitude = ReturnValues[1];
546                  CurvedBandBDMaxLongitude = ReturnValues[2];
547                  /* System.out.printf("max amounts %d %f %f\n",CurvedBandBDMaxAmount,CurvedBandBDMaxLatitude,CurvedBandBDMaxLongitude); */
548               }
549            }
550            else {
551              /* did not find curved band scenes, mark as non-eye/eye scene */
552              CloudSceneIDValue = 0;
553              CurvedBandSceneTF = false;
554              EmbeddedCenterSceneTF = false;
555            }
556         }
557      }
558      /* System.out.printf("CurvedbandsceneTF=%b  IrregularCDOTF=%b  ShearSceneTF=%b EmbeddedCenterTF=%b \n",
559          CurvedBandSceneTF,IrregularCDOSceneTF,ShearSceneTF,EmbeddedCenterSceneTF); */
560      if(!CurvedBandSceneTF) {
561         if(ShearSceneTF) {
562            /* shear scene */
563            EyeSceneIDValue = 3;                         /* NO EYE */
564            CloudSceneIDValue = 4;                       /* SHEAR */
565            TemperatureValue = ((BDCurve_Points[2]+BDCurve_Points[3])/2.0)+273.16;
566            ShearDistance = adt_cdoshearcalc(StormLatitude,StormLongitude,TemperatureValue,3);
567            EyeCDOSizeValue = Math.max(4.0,ShearDistance);
568         }
569         else {
570            CloudSceneIDValue = 0;                          /* UNIFORM */
571            if(EmbeddedCenterSceneTF) {
572               CloudSceneIDValue = 1;                       /* EMBEDDED CENTER */
573            }
574            /* added 08/15/13 */
575            if(IrregularCDOSceneTF) {
576               CloudSceneIDValue = 2;                       /* Irregular CDO */
577            }
578            /* PINHOLE EYE TEST */
579             /*
580              * System.out.printf("EyeFactorTotal=%f\n",
581              *      "EyeSceneIDValue=%d EyeCloudBDCategoryDifference=%d ",
582              *      "EyeFFTValue=%d CloudCWBDCategoryFloat=%f \n",
583              *      "CloudSceneIDValue=%d CloudFFTValue=%d ",
584              *      "PreviousHistoryTnoValueMinus12hrs=%f\n",EyeFactorTotal,
585              *       EyeSceneIDValue,EyeCloudBDCategoryDifference,EyeFFTValue,
586              *       CloudCWBDCategoryFloat,CloudSceneIDValue,CloudFFTValue,
587              *       PreviousHistoryTnoValueMinus12hrs);
588              */
589            if((RMWSize>0.0)&&(RMWSize<12.0)) {
590               EyeSceneIDValue = 1;                         /* PINHOLE EYE CHECK */
591            }
592            if((EyeFactorTotal>-0.25)&&(EyeFactorTotal<1.50)&&
593               (EyeCloudBDCategoryDifference>=2)&&(EyeFFTValue<=2)&&
594               (CloudCWBDCategoryFloat>6.0)&&(CloudSceneIDValue<=1)&&
595               (CloudFFTValue<=4)&&(PreviousHistoryTnoValueMinus12hrs>=3.5)) {
596               EyeSceneIDValue = 1;                         /* PINHOLE EYE CHECK */
597            }
598         }
599      }
600      double CDOSize = -999.0;
601      /* System.out.printf("cloudsceneID=%d eyesceneID=%d\n",CloudSceneIDValue,EyeSceneIDValue); */
602      if((CloudSceneIDValue<=2)&&(EyeSceneIDValue==3)) {
603         /* for CDO TESTS */
604         for(XInc=2;XInc<=6;XInc++) {  /* DG,MG,LG,B,W */
605            TemperatureValue = BDCurve_Points[XInc]+273.16;
606            /* System.out.printf("LatitudeValue=%f LongitudeValue=%f TemperatureValue=%f\n",StormLatitude,StormLongitude,TemperatureValue); */
607            CDOSize = adt_cdoshearcalc(StormLatitude,StormLongitude,TemperatureValue,1);
608            /* System.out.printf("CDO : XInc=%d  CDOSize=%f  CDOSize/111=%f  \n",XInc,CDOSize,CDOSize/111.0); */
609            if(XInc==2) {
610               EyeCDOSizeValue = CDOSize;
611            }
612         }
613      }
614    
615      /* System.out.printf("eyescene=%d cloudscene=%d eyecdosize=%f ringcb=%d ringcbval=%d\n",
616                 EyeSceneIDValue,CloudSceneIDValue,EyeCDOSizeValue,CurvedBandBDCategory,CurvedBandBDAmount); */ 
617      /* System.out.printf("CBMAX :ringcbval=%d ringcb=%d ringcbval=%d\n",CurvedBandBDMaxAmount,CurvedBandBDCategory,CurvedBandBDAmount); */
618
619      /* System.out.printf("EyeScene=%d CloudScene=%d EyeCDOSize=%f \n",EyeSceneIDValue,CloudSceneIDValue,EyeCDOSizeValue); */
620      History.IRCurrentRecord.eyescene = EyeSceneIDValue;
621      History.IRCurrentRecord.cloudscene = CloudSceneIDValue;
622      History.IRCurrentRecord.eyesceneold = -1;
623      History.IRCurrentRecord.cloudsceneold = -1;
624      History.IRCurrentRecord.eyecdosize = EyeCDOSizeValue;
625      History.IRCurrentRecord.ringcb = CurvedBandBDCategory;
626      History.IRCurrentRecord.ringcbval = CurvedBandBDAmount;
627      History.IRCurrentRecord.ringcbvalmax = CurvedBandBDMaxAmount;
628      History.IRCurrentRecord.ringcbvalmaxlat = CurvedBandBDMaxLatitude;
629      History.IRCurrentRecord.ringcbvalmaxlon = CurvedBandBDMaxLongitude;
630      History.IRCurrentRecord.mwscore = Env.MWScore;
631      History.IRCurrentRecord.mwdate = Env.MWJulianDate;
632      History.IRCurrentRecord.mwtime = Env.MWHHMMSSTime;
633      
634   }
635   
636   /**
637    * Determine storm location using 10^ Log-spiral analysis.
638    *
639    * <p>Algorithm will attempt to match the spiral with the image
640    * pixels at or below the threshold temperature based on
641    * BD-enhancement curve values.</p>
642    *
643    * @param InputLatitude Center latitude of analysis grid
644    * @param InputLongitude Center longitude of analysis grid
645    * @param TemperatureThreshold Temperature threshold value
646    * @param AnalysisTypeIDValue 1=search at single point
647    *                            2=search over 2^box
648    *
649    * @return Array of three double values. In order, they
650    * are:
651    * <ol>
652    *   <li>SpiralArcLatitude - best latitude location from analysis.</li>
653    *   <li>SpiralArcLongitude - best longitude location from analysis.</li>
654    *   <li>SpiralArcDistance - number of consecutive arcs through which
655    *   spiral passes</li>
656    * </ol>
657    */
658   public static double[] adt_logspiral(double InputLatitude,
659                                        double InputLongitude,
660                                        double TemperatureThreshold,
661                                        int AnalysisTypeIDValue)
662   {
663      int XInc,YInc,ZInc;
664      int SpiralArcDistance=-99;
665      int SearchLatitudeMaxInteger,SearchLatitudeMinInteger;
666      int SearchLongitudeMaxInteger,SearchLongitudeMinInteger;
667      double SearchLatitudeMaximum,SearchLatitudeMinimum;
668      double SearchLongitudeMaximum,SearchLongitudeMinimum;
669      double SpiralArcLatitude=-999.99;
670      double SpiralArcLongitude=-999.99;
671      float ValidPixelLatitudeArray[] = new float[40000];
672      float ValidPixelLongitudeArray[] = new float[40000];
673      float ValidPixelTemperatureArray[] = new float[40000];
674
675      double ImageResolution = Data.GetCurrentImageResolution();
676      double DistanceDifferenceMaximumKM=ImageResolution+(ImageResolution/2.0);
677      int IncAddVal=(ImageResolution>RING_WIDTH) ? 1 : ((int)(RING_WIDTH-ImageResolution+1.0));
678
679      if(AnalysisTypeIDValue==2) {
680         /* search over 2.0 degree box */
681         SearchLatitudeMaximum = InputLatitude+1.0;
682         SearchLatitudeMinimum = InputLatitude-1.0;
683         SearchLongitudeMaximum = InputLongitude+1.0;
684         SearchLongitudeMinimum = InputLongitude-1.0;
685         SearchLatitudeMaxInteger = (int)(SearchLatitudeMaximum*100.0);
686         SearchLatitudeMinInteger = (int)(SearchLatitudeMinimum*100.0);
687         SearchLongitudeMaxInteger = (int)(SearchLongitudeMaximum*100.0);
688         SearchLongitudeMinInteger = (int)(SearchLongitudeMinimum*100.0);
689      } else {
690         /* search at a single point */
691         SearchLatitudeMaxInteger = (int)(InputLatitude*100.0);
692         SearchLatitudeMinInteger = (int)(InputLatitude*100.0);
693         SearchLongitudeMaxInteger = (int)(InputLongitude*100.0);
694         SearchLongitudeMinInteger = (int)(InputLongitude*100.0);
695      }
696      
697      /* allocate memory, if necessary */
698      if(IRImageXSize==-1) {
699         IRImageXSize = Data.GetCurrentImageXSize();
700         IRImageYSize = Data.GetCurrentImageYSize();
701         IRImageLatitudeArrayLocal = Data.GetCurrentImageLatitudeArray();
702         IRImageLongitudeArrayLocal = Data.GetCurrentImageLongitudeArray();
703         IRImageTemperatureArrayLocal = Data.GetCurrentImageTemperatureArray();
704      }
705
706      /* System.out.printf("temperature threshold=%f\n",TemperatureThreshold); */
707      /* initialize arrays */
708      int ValidPointCounter = 0;
709      for(YInc=0;YInc<IRImageYSize;YInc=YInc+IncAddVal) {
710         for(XInc=0;XInc<IRImageXSize;XInc=XInc+IncAddVal) {
711            if(IRImageTemperatureArrayLocal[YInc][XInc]<=TemperatureThreshold) {
712               ValidPixelLatitudeArray[ValidPointCounter] = IRImageLatitudeArrayLocal[YInc][XInc];
713               ValidPixelLongitudeArray[ValidPointCounter] = IRImageLongitudeArrayLocal[YInc][XInc];
714               ValidPixelTemperatureArray[ValidPointCounter] = IRImageTemperatureArrayLocal[YInc][XInc];
715               ValidPointCounter++;
716            }
717         }
718      }
719      /* System.out.printf("Valid Point Counter=%d\n",ValidPointCounter); */
720
721      int ArcSkipCounter;
722      int ThresholdCounter;
723      int SpiralConsecutiveArcCounter;
724      int SpiralConsecutiveArcMaximum;
725      double SpiralStartMinimumDistance;
726      double SearchIncrementLatitude=0.0;
727      double SearchIncrementLongitude=0.0;
728      double SpiralArcBestRotationAngleValue=0.0;
729      double ArcAngleTheta_Radians;
730      double RadialDistanceKM;
731      double FinalArcAngleTheta,FinalArcAngleThetaPlus180;
732      double RadiansValue=57.29578;          /* degree to radians conversion value*/
733      double SpiralConstantAValue=25.0;      /* 10^ log spiral distance constant */
734      double SpiralConstantBValue=10.0/RadiansValue; /* 10^ log spiral increase */
735      double LatitudeDifference;
736      double LongitudeDifference;
737
738      for(XInc=SearchLatitudeMinInteger;XInc<=SearchLatitudeMaxInteger;XInc=XInc+20) {
739         SearchIncrementLatitude = (double)XInc/100.0;
740         /* loop through y-axis/lines of analysis grid box */
741         for(YInc=SearchLongitudeMinInteger;YInc<=SearchLongitudeMaxInteger;YInc=YInc+20) {
742            SearchIncrementLongitude = (double)YInc/100.0;
743            ArcSkipCounter = 0;
744            /* determine distance from each point in box to current location */
745            if(AnalysisTypeIDValue==2) {
746               SpiralStartMinimumDistance = 12.0;
747               for(ZInc=0;ZInc<ValidPointCounter;ZInc++) {
748                  double LocalValue[] = Functions.distance_angle(SearchIncrementLatitude,SearchIncrementLongitude,
749                                                                     ValidPixelLatitudeArray[ZInc], 
750                                                                     ValidPixelLongitudeArray[ZInc],1);
751                  double DistanceValue = LocalValue[0];
752                  if(DistanceValue<=SpiralStartMinimumDistance) {
753                    /*
754                     * if the lat/lon point is too close to cold cloud tops, do
755                     * not calculate log spiral at this point.  Trying to eliminate
756                     * "false" arc locations by forcing the system to use some
757                     * of the arc points on the spiral away from the start of
758                     * the spiral (were getting "false echos" without this".
759                     */
760                    ArcSkipCounter = 1;
761                    break;
762                  }
763               }
764            }
765    
766            int SpiralArcMaximumValue = 0;
767            int SpiralArcMaximumValueRotationFactor = 0;
768            /*
769             * if arc location passes analysis above,
770             * proceed with placement of spiral
771             */
772
773            if(ArcSkipCounter==0) {
774               /* rotate the arc spiral thru entire revolution at 30^ interval */
775               for(int RotationFactor=0;RotationFactor<=330;RotationFactor=RotationFactor+30) {
776                  SpiralConsecutiveArcCounter = 0;
777                  SpiralConsecutiveArcMaximum = 0;
778    
779                 /* calculate position of each point on spiral from 0 to 540^ */
780                  for(int ArcAngleTheta=0;ArcAngleTheta<=540;ArcAngleTheta=ArcAngleTheta+15) {
781                     ArcAngleTheta_Radians = (double)ArcAngleTheta/RadiansValue;
782                     RadialDistanceKM = SpiralConstantAValue*Math.exp((SpiralConstantBValue*ArcAngleTheta_Radians));
783                     FinalArcAngleTheta = (double)ArcAngleTheta+(double)RotationFactor;
784                     if(SearchIncrementLatitude<0.0) {
785                        FinalArcAngleTheta = (double)(-1*ArcAngleTheta)+(double)RotationFactor;
786                     }
787                     FinalArcAngleThetaPlus180 = FinalArcAngleTheta+180.0;
788                     double LocalValue2[] = Functions.distance_angle2(SearchIncrementLatitude,SearchIncrementLongitude,
789                                                                          RadialDistanceKM,FinalArcAngleThetaPlus180);
790                     double SearchGuessLatitude = LocalValue2[0];
791                     double SearchGuessLongitude = LocalValue2[1];
792                     ThresholdCounter = 0;
793                     for(ZInc=0;ZInc<ValidPointCounter;ZInc++) {
794                        LatitudeDifference = Math.abs(SearchGuessLatitude-
795                                                 ValidPixelLatitudeArray[ZInc]);
796                        LongitudeDifference = Math.abs(SearchGuessLongitude-
797                                                  ValidPixelLongitudeArray[ZInc]);
798                        /*
799                         * if a point is within 0.1^ latitude/longitude
800                         * determine distance
801                         */
802                        if((LatitudeDifference<=0.1)&&(LongitudeDifference<=0.1)) {
803                            double LocalValue3[] = Functions.distance_angle(SearchGuessLatitude,SearchGuessLongitude,
804                                                                               ValidPixelLatitudeArray[ZInc], 
805                                                                               ValidPixelLongitudeArray[ZInc],1);
806                            double DistanceValue3 = LocalValue3[0];
807                           /*
808                            * if distance from spiral point is within 6km from an
809                            * accepted temperature threshold point, count it
810                            */
811                           if(DistanceValue3<=DistanceDifferenceMaximumKM) {
812                              ThresholdCounter++;
813                           }
814                        }
815                     }
816                     /*
817                      * if there are 4 or more threshold points associated
818                      * with each spiral point, count within consecutive
819                      * spiral point counter
820                      */
821                     if(ThresholdCounter>=4) {
822                        SpiralConsecutiveArcCounter++;
823                        /*
824                         * save spiral that has maximum consecutive spiral counts
825                         * for each rotation though 360^ at each center location
826                         */
827                        if(SpiralConsecutiveArcCounter>SpiralConsecutiveArcMaximum) {
828                           SpiralConsecutiveArcMaximum = SpiralConsecutiveArcCounter;
829                        }
830                     } else {
831                        SpiralConsecutiveArcCounter = 0;
832                     }
833                     /*
834                      * if this spiral has the greatest number of consecutive
835                      * spiral points, save the location and number of points
836                      */
837                     if(SpiralConsecutiveArcMaximum>SpiralArcMaximumValue) {
838                        SpiralArcMaximumValue = SpiralConsecutiveArcMaximum;
839                        SpiralArcMaximumValueRotationFactor = RotationFactor;
840                     }
841                  }
842               } /* RotationFactor loop */
843               if(SpiralArcMaximumValue>SpiralArcDistance) {
844                  SpiralArcDistance = SpiralArcMaximumValue;
845                  SpiralArcLatitude = SearchIncrementLatitude;
846                  SpiralArcLongitude = SearchIncrementLongitude;
847                  SpiralArcBestRotationAngleValue = SpiralArcMaximumValueRotationFactor;
848               }
849            } /* ArcSkipCounter if */
850         } /* YInc loop */
851      } /* XInc loop */
852    
853      /* load array for best spiral band */
854      for(int ArcAngleTheta=0;ArcAngleTheta<=540;ArcAngleTheta=ArcAngleTheta+15) {
855         ArcAngleTheta_Radians=(double)ArcAngleTheta/RadiansValue;
856         RadialDistanceKM=SpiralConstantAValue*Math.exp((SpiralConstantBValue*ArcAngleTheta_Radians));
857         FinalArcAngleTheta=(double)ArcAngleTheta+(double)SpiralArcBestRotationAngleValue;
858         if(SearchIncrementLatitude<0.0) {
859            FinalArcAngleTheta=(double)(-1*ArcAngleTheta)+(double)SpiralArcBestRotationAngleValue;
860         }
861         FinalArcAngleThetaPlus180=FinalArcAngleTheta+180.0;
862         /* load array for external plotting of spiral band */
863         /* SpiralBandPoints_Global[0][TemporaryCounter]=SearchGuessLatitude; */
864         /*SpiralBandPoints_Global[1][TemporaryCounter]=SearchGuessLongitude; */
865      }
866
867      return new double[] { (double)SpiralArcDistance, SpiralArcLatitude, SpiralArcLongitude };
868
869   }
870   
871   /**
872    * Determine eye size or shear distance for a given scene.
873    *
874    * @param InputLatitude Center latitude of analysis grid
875    * @param InputLongitude Center longitude of analysis grid
876    * @param TemperatureThreshold Temperature threshold value to be used
877    * @param AnalysisTypeIDValue Analysis type
878    *                            (1-cdo size,2-eye size,3-shear distance)
879    *
880    * @return eye/cdo radius or shear distance
881    */
882   public static double adt_cdoshearcalc(double InputLatitude,
883                                         double InputLongitude,
884                                         double TemperatureThreshold,
885                                         int AnalysisTypeIDValue)
886   {
887      /* maximum distance constant value */
888      double ANGLEMAXDIFFERENCE=15.0;
889      double RadiusOrShear=-99.0;
890      double Value3=MANUAL_EYE_RADIUS+RING_WIDTH;
891      double PixelLatitudeArray[] = new double[40000];
892      double PixelLongitudeArray[] = new double[40000];
893      double PixelTemperatureArray[] = new double[40000];
894
895      int XInc,YInc,ZInc;
896      int PointCounter=0;
897      int ValidRadiiCounter=4;
898      double DistanceValue,AngleValue;
899      double SymmValue;
900      
901      double RadiiLength1=300.0;
902      double RadiiLength2=300.0;
903      double RadiiLength3=300.0;
904      double RadiiLength4=300.0;
905      double MaxDistanceValue=0.0;
906
907      /* allocate memory, if necessary */
908      if(IRImageXSize==-1) {
909         IRImageXSize = Data.GetCurrentImageXSize();
910         IRImageYSize = Data.GetCurrentImageYSize();
911         IRImageLatitudeArrayLocal = Data.GetCurrentImageLatitudeArray();
912         IRImageLongitudeArrayLocal = Data.GetCurrentImageLongitudeArray();
913         IRImageTemperatureArrayLocal = Data.GetCurrentImageTemperatureArray();
914      }
915
916      if(AnalysisTypeIDValue==1) {
917         /* CDO size determination - RETURNS RADIUS */
918         for(YInc=0;YInc<IRImageYSize;YInc++) {
919            for(XInc=0;XInc<IRImageXSize;XInc++) {
920               if(IRImageTemperatureArrayLocal[YInc][XInc]>TemperatureThreshold) {
921                  PixelLatitudeArray[PointCounter] = IRImageLatitudeArrayLocal[YInc][XInc];
922                  PixelLongitudeArray[PointCounter] = IRImageLongitudeArrayLocal[YInc][XInc];
923                  PixelTemperatureArray[PointCounter] = IRImageTemperatureArrayLocal[YInc][XInc];
924                  PointCounter++;
925               }
926            }
927         }
928        
929         /* System.out.printf("PointCounter=%d  numx*numy=%d\n",PointCounter,IRImageYSize*IRImageXSize); */
930         if(PointCounter<(IRImageYSize*IRImageXSize)) {
931            for(ZInc=0;ZInc<PointCounter;ZInc++) {
932               double LocalValue[] = Functions.distance_angle(InputLatitude,InputLongitude,
933                                                                  PixelLatitudeArray[ZInc],PixelLongitudeArray[ZInc],1);
934               DistanceValue = LocalValue[0];
935               AngleValue = LocalValue[1];
936               if(DistanceValue>MaxDistanceValue) MaxDistanceValue=DistanceValue;
937               /* determine size of CDO */
938               if(DistanceValue>MANUAL_EYE_RADIUS) {
939                  if((Math.abs(AngleValue-45.0)<=ANGLEMAXDIFFERENCE)&&
940                     (DistanceValue<RadiiLength1)) {
941                     RadiiLength1=DistanceValue;
942                  }
943                  if((Math.abs(AngleValue-135.0)<=ANGLEMAXDIFFERENCE)&&
944                     (DistanceValue<RadiiLength2)) {
945                     RadiiLength2=DistanceValue;
946                  }
947                  if((Math.abs(AngleValue-225.0)<=ANGLEMAXDIFFERENCE)&&
948                     (DistanceValue<RadiiLength3)) {
949                     RadiiLength3=DistanceValue;
950                  }
951                  if((Math.abs(AngleValue-315.0)<=ANGLEMAXDIFFERENCE)&&
952                     (DistanceValue<RadiiLength4)) {
953                     RadiiLength4=DistanceValue;
954                  }
955               }
956            }
957            
958            /* System.out.printf("RadiiLength1=%f RadiiLength2=%fRadiiLength3=%f RadiiLength4=%f\n",
959                     RadiiLength1,RadiiLength2,RadiiLength3,RadiiLength4); */
960            
961            if(RadiiLength1<Value3) {
962               ValidRadiiCounter--;
963            }
964            if(RadiiLength2<Value3) {
965               ValidRadiiCounter--;
966            }
967            if(RadiiLength3<Value3) {
968               ValidRadiiCounter--;
969            }
970            if(RadiiLength4<Value3) {
971               ValidRadiiCounter--;
972            }
973         }
974         else {
975            RadiiLength1=0.0;
976            RadiiLength2=0.0;
977            RadiiLength3=0.0;
978            RadiiLength4=0.0;
979         }
980         if(ValidRadiiCounter<3) {
981            RadiusOrShear=0.0;
982         }
983         else {
984            RadiiLength1=Math.min(RadiiLength1,MaxDistanceValue);
985            RadiiLength2=Math.min(RadiiLength2,MaxDistanceValue);
986            RadiiLength3=Math.min(RadiiLength3,MaxDistanceValue);
987            RadiiLength4=Math.min(RadiiLength4,MaxDistanceValue);
988            RadiusOrShear=(RadiiLength1+RadiiLength2+RadiiLength3+RadiiLength4)/4.0;
989            double Value1=RadiiLength1+RadiiLength3;
990            double Value2=RadiiLength2+RadiiLength4;
991            SymmValue=Value1/Value2;
992            SymmValue=Math.max(SymmValue,1.0/SymmValue);
993         }
994         /* System.out.printf("\nPointCounter=%5d RadiiLength1=%5.1f RadiiLength2=%5.1f RadiiLength3=%5.1f RadiiLength4=%5.1f\n",
995                   PointCounter, RadiiLength1,RadiiLength2,RadiiLength3,RadiiLength4); */
996      }
997    
998      if(AnalysisTypeIDValue==3) {
999         double ShearDistanceValue=-99.0;
1000         /*  need to implement entire odtauto.c library including remapping
1001         RetErr=adt_shearbw(TemperatureValue,LatitudeValue,LongitudeValue,
1002                             &ShearDistanceValue);
1003         */
1004         RadiusOrShear=ShearDistanceValue;
1005      }
1006
1007      return RadiusOrShear;
1008   }
1009}