001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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.adt; 030 031import static java.lang.Math.PI; 032import static java.lang.Math.abs; 033import static java.lang.Math.cos; 034import static java.lang.Math.log; 035import static java.lang.Math.max; 036import static java.lang.Math.sqrt; 037import static java.lang.Math.pow; 038 039import java.io.IOException; 040 041import javax.swing.JOptionPane; 042 043class Remap { 044 /** Block size (bytes) input file */ 045 int in_bfw; 046 047 /** Block size (bytes) output file */ 048 int out_bfw; 049 050 /** Number of splines/line */ 051 int nspl; 052 053 /** Number of splines/elem */ 054 int nspe; 055 056 /** Source blocksize */ 057 int slb; 058 059 /** Dest blocksize */ 060 int dlb; 061 062 /** Number of corners in line */ 063 int ncl; 064 065 /** Number of corners in elem */ 066 int nce; 067} 068 069/** TIFF header */ 070class TiffHeader { 071 /** Byte order */ 072 int order; 073 074 /** Version */ 075 int version; 076 077 /** Pointer */ 078 int point; 079} 080 081/** 082 * TIFF directory record. 083 */ 084class TiffRecord { 085 /** TIFF tag */ 086 int tag; 087 088 /** Data type */ 089 int type; 090 091 /** Length */ 092 int length; 093 094 /** Pointer or value */ 095 int voff; 096} 097 098class DisVars { 099 /** Output number of lines */ 100 double xrectl; 101 102 /** Output number of elems */ 103 double xrecte; 104} 105 106class TiffVars { 107 int nbits; 108 int photo; 109 int unit; 110 int in_lines; 111 int in_elems; 112 int out_lines; 113 int out_elems; 114} 115 116public class Auto { 117 118 private static int[][] MoatMaskFlagField = new int[200][200]; 119 120 private static int[][] BlackWhiteFieldArray = new int[200][200]; 121 122 private static double[][] IRData_Remap_Latitude = new double[200][200]; 123 private static double[][] IRData_Remap_Longitude = new double[200][200]; 124 125 private static double[][] IRData_Remap_Temperature = new double[200][200]; 126 127 private static int IRData_Remap_NumberRows; 128 129 private static int IRData_Remap_NumberColumns; 130 131 private static double[][] NSTempGradientArray = new double[200][200]; 132 133 private static double[][] EWTempGradientArray = new double[200][200]; 134 135 private static double[][] SpiralCenterAnalysisField = new double[50000][3]; 136 137 private static double[][] RingScoreAnalysisField = new double[750000][3]; 138 139 private static int[][] CircleFilterRowArray = new int[100][2000]; 140 141 private static int[][] CircleFilterColumnArray = new int[100][2000]; 142 143 /* I don't know this size for sure */ 144 /** Array containing line coordinates */ 145 private static double[] LineCoordinateArray = new double[5000]; 146 147 /* I don't know this size for sure */ 148 /** Array containing element coordinates */ 149 private static double[] ElementCoordinateArray = new double[5000]; 150 151 private static Remap remap_vars = new Remap(); 152 153 private static TiffVars tiff_vars = new TiffVars(); 154 155 private static double RING_WIDTH = 4.0; 156 157 /** Minimum block size (bytes) for domap */ 158 private static int MINBFW = 500000; 159 160 /** Minimum block size (lines) */ 161 private static int MINBLKSIZ = 10; 162 163 public Auto() { 164 IRData_Remap_NumberRows = 0; 165 IRData_Remap_NumberColumns = 0; 166 } 167 168 /** 169 * Determine storm position at time CurrentTime using NHC/JTWC forecast 170 * discussion products. 171 * 172 * Time and location information from these products are then interpolated 173 * to time in question to derive a estimated storm position. If position 174 * estimation cannot be calculated, a lat/lon position of -99.5/-999.5 will 175 * be returned. Inputs : None Outputs : Latitude_Return - estimated latitude 176 * position Longitude_Return - estimated longitude position 177 * PositioningMethodID_Return - method used to derive storm location Return 178 * : -43 : Error w/ forecast file open and BAD extrapolation -44 : Invalid 179 * forecast file and BAD extrapolation -45 : Error w/ forecast file read and 180 * BAD extrapolation -46 : Error w/ forecast interpolation and BAD 181 * extrapolation 42 : GOOD INTERPOLATION 43 : Error w/ forecast file open 182 * but GOOD EXTRAPOLATION 44 : Invalid forecast file but GOOD extrapolation 183 * 45 : Error w/ forecast file read but GOOD extrapolation 46 : Error w/ 184 * forecast interpolation but GOOD EXTRAPOLATION 0 : Subroutine Error 185 */ 186 public double[] AutoMode1(String ForecastFile, int ForecastFileType) throws IOException { 187 188 int RetID = 0; 189 int PositioningMethodID = 0; 190 int InterpolatedReturnFlag = 0; 191 double InterpolatedLatitude = -99.99; 192 double InterpolatedLongitude = -99.99; 193 double InterpolatedIntensity = -99.99; 194 boolean UseExtrapPositionTF = false; 195 196 /* Read Forecast File */ 197 double ThresholdTime = 24.0; 198 double[] ForecastFileOutput = Forecasts.ReadForecasts(ForecastFile, ForecastFileType, 199 ThresholdTime); 200 201 if (ForecastFileOutput == null) { 202 JOptionPane.showMessageDialog(null, 203 "Unable to process Forecast File, please ensure a valid file is present."); 204 return null; 205 } 206 207 InterpolatedReturnFlag = (int) ForecastFileOutput[0]; 208 InterpolatedLatitude = ForecastFileOutput[1]; 209 InterpolatedLongitude = ForecastFileOutput[2]; 210 InterpolatedIntensity = ForecastFileOutput[3]; 211 /* History.IRCurrentRecord.latitude = ForecastLatitude; */ 212 /* History.IRCurrentRecord.longitude = ForecastLongitude; */ 213 214 /* 215 * System.out.printf("InterpolatedReturnFlag=%d\n",InterpolatedReturnFlag 216 * ); 217 */ 218 if (InterpolatedReturnFlag != 0) { 219 PositioningMethodID = 6; 220 UseExtrapPositionTF = true; 221 /* 222 * -1 will give 45=invalid interpretation -2 will give 44=invalid 223 * file type -4 will give 42=error closing file -5 will give 224 * 41=error opening file 225 */ 226 RetID = 46 + InterpolatedReturnFlag; 227 } else { 228 /* Good interpolated values... use 'em */ 229 PositioningMethodID = 1; 230 UseExtrapPositionTF = false; 231 RetID = 43; 232 } 233 234 /* 235 * try to extrapolate storm location from previous storm locations in 236 * history file 237 */ 238 if (UseExtrapPositionTF) { 239 /* call slopecal to get y-intercept values for lat/lon values */ 240 InterpolatedLatitude = Functions.adt_slopecal(12.0, 3); 241 InterpolatedLongitude = Functions.adt_slopecal(12.0, 4); 242 if ((abs(InterpolatedLatitude) > 90.0) || (abs(InterpolatedLongitude) > 180.0)) { 243 /* invalid interp and extrap... negative error code returns */ 244 PositioningMethodID = 0; 245 RetID = -1 * RetID; 246 } else { 247 /* invalid interp but good extrap... positive error code returns */ 248 PositioningMethodID = 6; 249 RetID = 46; 250 } 251 } 252 253 return new double[] { (double) RetID, InterpolatedLatitude, InterpolatedLongitude, 254 InterpolatedIntensity, (double) PositioningMethodID }; 255 } 256 257 /** 258 * Additional automatic positioning of storm center location using official 259 * forecasts from NHC or JTWC as input. 260 * 261 * Storm location will be estimated using spiral fitting and ring fitting 262 * routines derived by Tony Wimmers in his MatLab routines (which have been 263 * converted). 264 * 265 * The final position will be determined utilizing empirically defined 266 * confidence factors for each method. The final storm position will be 267 * returned along with a position determination flag. 268 * 269 * @param InputLatitudePosition 270 * Storm center latitude. 271 * @param InputLongitudePosition 272 * Storm center longitude. 273 * 274 * Outputs : Latitude_Return - final storm center latitude 275 * position Longitude_Return - final storm center longitude 276 * position PositioningMethodID_Return - method used to derive 277 * storm location 0-error 1-interpolation of operational forecast 278 * 2-Laplacian analysis (not used anymore) 3-Warm Spot location 279 * 4-10^ log spiral analysis 5-Combo method of spiral and ring 280 * analyses 6-linear extrapolation from prior locations Return : 281 * Error flag = 0 282 */ 283 public static double[] AutoMode2(double InputLatitudePosition, double InputLongitudePosition) 284 throws IOException { 285 int XInc; 286 int YInc; 287 double SpiralCenterLatitude = -99.9; 288 double SpiralCenterLongitude = -99.9; 289 double SpiralCenterScore = -1.0; 290 double RingFitLatitude = -99.9; 291 double RingFitLongitude = -99.9; 292 double RingFitScore = -1.0; 293 double FinalAutoLatitude = -99.9; 294 double FinalAutoLongitude = -99.9; 295 double FinalAutoScore = -99.9; 296 int FinalAutoFixMethod = 1; 297 boolean DatelineCrossTF = false; 298 boolean DoRemappingTF = true; 299 300 /* 301 * NEED TO MULTIPLY LONGITUDES BY -1.0 SINCE ADT ROUTINES WERE DEVELOPED 302 * ON McIDAS-X, which uses West/East Longitudes of +1.0/-1.0. McV is 303 * reversed. 304 */ 305 InputLongitudePosition = -1.0 * InputLongitudePosition; // flip for ADT 306 // routines 307 for (YInc = 0; YInc < Data.IRData_NumberRows; YInc++) { 308 for (XInc = 0; XInc < Data.IRData_NumberColumns; XInc++) { 309 Data.IRData_Longitude[YInc][XInc] = (float) -1.0 310 * Data.IRData_Longitude[YInc][XInc]; 311 } 312 } 313 314 if (DoRemappingTF) { 315 System.out.printf("REMAPPING DATA\n"); 316 IRData_Remap_NumberRows = Data.IRData_NumberRows; 317 IRData_Remap_NumberColumns = Data.IRData_NumberColumns; 318 319 double LongitudeIncrement = Data.IRData_Longitude[0][0] - Data.IRData_Longitude[0][1]; 320 double LatitudeIncrement = Data.IRData_Latitude[0][0] - Data.IRData_Latitude[1][1]; 321 322 if (abs(LongitudeIncrement - LatitudeIncrement) < 0.001) { 323 System.out.printf("already remapped\n"); 324 /* data is already remapped */ 325 /* crosses dateline check */ 326 int XSizeMax = Data.IRData_NumberColumns - 1; 327 int YSizeMax = Data.IRData_NumberRows - 1; 328 double NWCornerLongitude = Data.IRData_Longitude[0][0]; 329 double NECornerLongitude = Data.IRData_Longitude[0][XSizeMax]; 330 double SWCornerLongitude = Data.IRData_Longitude[YSizeMax][0]; 331 double SECornerLongitude = Data.IRData_Longitude[YSizeMax][XSizeMax]; 332 /* 333 * if((NWCornerLongitude<NECornerLongitude)||(SWCornerLongitude< 334 * SECornerLongitude)) { DatelineCrossTF = true; } 335 */ 336 if ((NWCornerLongitude > NECornerLongitude) 337 || (SWCornerLongitude > SECornerLongitude)) { 338 DatelineCrossTF = true; 339 NWCornerLongitude = NWCornerLongitude + 360.0; 340 341 } 342 for (YInc = 0; YInc < Data.IRData_NumberRows; YInc++) { 343 for (XInc = 0; XInc < Data.IRData_NumberColumns; XInc++) { 344 IRData_Remap_Longitude[YInc][XInc] = Data.IRData_Longitude[YInc][XInc]; 345 /* check for dateline crossing */ 346 if (DatelineCrossTF && (IRData_Remap_Longitude[YInc][XInc] < 0.0)) { 347 IRData_Remap_Latitude[YInc][XInc] = Data.IRData_Latitude[YInc][XInc] + 360.0; 348 } 349 IRData_Remap_Latitude[YInc][XInc] = Data.IRData_Latitude[YInc][XInc]; 350 IRData_Remap_Temperature[YInc][XInc] = Data.IRData_Temperature[YInc][XInc]; 351 } 352 } 353 IRData_Remap_NumberColumns = Data.IRData_NumberColumns; 354 IRData_Remap_NumberRows = Data.IRData_NumberRows; 355 } else { 356 /* remap data to rectilinear projection */ 357 RemapData(); 358 System.out.printf("COMPLETED REMAPPING DATA\n"); 359 } 360 361 /* perform spiral analysis to determine storm center location */ 362 double SpiralReturn[] = SpiralCenterLowRes(InputLatitudePosition, 363 InputLongitudePosition); 364 SpiralCenterLatitude = SpiralReturn[0]; 365 SpiralCenterLongitude = SpiralReturn[1]; 366 SpiralCenterScore = SpiralReturn[2]; 367 368 /* 369 * System.out.printf("Spiral Score : lat=%f lon=%f score=%f\n", 370 * SpiralCenterLatitude, SpiralCenterLongitude,SpiralCenterScore); 371 */ 372 373 /* 374 * redefine first guess for ring analysis as input storm location 375 * point 376 */ 377 double RingFitFirstGuessLatitude = SpiralCenterLatitude; 378 double RingFitFirstGuessLongitude = SpiralCenterLongitude; 379 380 /* calculate Moat Mask for false eye check */ 381 double MoatMaskTempThreshold = 237.0; 382 double MoatMaskMaxRadiusDegree = 0.50; 383 MoatMaskCalc(MoatMaskTempThreshold, MoatMaskMaxRadiusDegree, 1); 384 385 /* perform ring analysis to determine storm center location */ 386 double RingReturn[] = RingFit(RingFitFirstGuessLatitude, RingFitFirstGuessLongitude); 387 RingFitLatitude = RingReturn[0]; 388 RingFitLongitude = RingReturn[1]; 389 RingFitScore = RingReturn[2]; 390 391 /* 392 * System.out.printf("Ring Score : lat=%f lon=%f score=%f \n", 393 * RingFitLatitude,RingFitLongitude,RingFitScore); 394 */ 395 /* 396 * System.out.printf( 397 * "fglat=%f fglon=%f SpiralCenterLatitude=%f SpiralCenterLongitude=%f rglat=%f rglon=%f\n" 398 * , InputLatitudePosition,InputLongitudePosition, 399 * SpiralCenterLatitude,SpiralCenterLongitude, 400 * RingFitLatitude,RingFitLongitude); 401 */ 402 403 /* caluculate confidence factor for combined spiral/ring analyses */ 404 double ScoresReturn[] = CalcScores(InputLatitudePosition, InputLongitudePosition, 405 SpiralCenterLatitude, SpiralCenterLongitude, SpiralCenterScore, 406 RingFitLatitude, RingFitLongitude, RingFitScore); 407 FinalAutoLatitude = ScoresReturn[0]; 408 FinalAutoLongitude = ScoresReturn[1]; 409 FinalAutoScore = ScoresReturn[2]; 410 FinalAutoFixMethod = (int) ScoresReturn[3]; 411 /* 412 * System.out.printf("SPIRAL CENTER : lat=%f lon=%f SCORE=%f \n", 413 * SpiralCenterLatitude,SpiralCenterLongitude,SpiralCenterScore); 414 * System.out.printf("RING CENTER : lat=%f lon=%f SCORE=%f \n", 415 * RingFitLatitude,RingFitLongitude,RingFitScore); 416 * System.out.printf("FINAL CENTER : lat=%f lon=%f SCORE=%f \n", 417 * FinalAutoLatitude,FinalAutoLongitude,FinalAutoScore); 418 */ 419 } else { 420 SpiralCenterLatitude = -99.9; 421 SpiralCenterLongitude = -99.9; 422 SpiralCenterScore = -1.0; 423 RingFitLatitude = -99.9; 424 RingFitLatitude = -99.9; 425 RingFitScore = -1.0; 426 FinalAutoLatitude = -99.9; 427 FinalAutoLongitude = -99.9; 428 FinalAutoScore = -99.9; 429 FinalAutoFixMethod = 1; 430 } 431 432 int PositioningMethodID = History.IRCurrentRecord.autopos; 433 434 double LocationReturn[] = PickFinalLocation(PositioningMethodID, InputLatitudePosition, 435 InputLongitudePosition, FinalAutoLatitude, FinalAutoLongitude, FinalAutoScore, 436 FinalAutoFixMethod); 437 438 double FinalLatitude = LocationReturn[0]; 439 double FinalLongitude = LocationReturn[1]; 440 PositioningMethodID = (int) LocationReturn[3]; 441 442 if (FinalLongitude > 180.0) { 443 FinalLongitude = FinalLongitude - 360.0; 444 } 445 446 /* 447 * System.out.printf("TAC CENTER : lat=%f lon=%f \n", 448 * InputLatitudePosition,InputLongitudePosition); 449 */ 450 /* 451 * System.out.printf( 452 * "AUTO CENTER : lat=%f lon=%f SCORE=%f METHOD=%d\n", 453 * FinalAutoLatitude,FinalAutoLongitude, 454 * FinalAutoScore,FinalAutoFixMethod); 455 */ 456 /* 457 * System.out.printf( 458 * "FINAL LOCATION: lat=%f lon=%f SCORE=%f METHOD=%d\n", 459 * FinalLatitude,FinalLongitude, FinalScoreValue,PositioningMethodID); 460 */ 461 462 /* 463 * need to flip final Longitude value back to McV format by multiplying 464 * by -1.0 465 */ 466 FinalLongitude = -1.0 * FinalLongitude; 467 468 return new double[] { FinalLatitude, FinalLongitude, (double) PositioningMethodID }; 469 } 470 471 private static double[] SpiralCenterLowRes(double InputLatitude, double InputLongitude) { 472 473 double[][] IRData_NormCoord_Latitude = new double[200][200]; 474 double[][] IRData_NormCoord_Longitude = new double[200][200]; 475 double[][] IRData_NormCoord_Temperature = new double[200][200]; 476 477 int XInc, YInc; 478 int IRData_NormCoord_NumberRows; 479 int IRData_NormCoord_NumberColumns; 480 int NumPoints; 481 int RingWidthLocal = (int) RING_WIDTH; 482 483 double XOff, YOff; 484 double SearchRadius = 0.0; 485 double CrossScoreSum = 0.0; 486 double ProxyValueX = 0.0; 487 double ProxyValueY = 0.0; 488 double DenominatorValue = 0.0; 489 double SpiralValueX = 0.0; 490 double SpiralValueY = 0.0; 491 double RawCrossScore = 0.0; 492 double CrossScoreClean = 0.0; 493 double SpiralMeanCrossScore = 0.0; 494 double SpiralMeanCrossMaxScore = 0.0; 495 double SpiralMeanCrossMaxYLocation = 0.0; 496 double SpiralMeanCrossMaxXLocation = 0.0; 497 498 double SpiralCenterLatitude = -99.99; 499 double SpiralCenterLongitude = -999.99; 500 double SpiralCenterScore = 0.0; 501 502 double Alpha = 5.0 * PI / 180.0; 503 double OutsideFactor = 0.62; 504 505 double OuterSearchRadiusDegree = 1.75; 506 double CourseGridSpacingDegree = 0.2; 507 double FineGridSpacingDegree = 0.1; 508 double FilterDiscSize = pow(OuterSearchRadiusDegree + (2.0 * FineGridSpacingDegree), 2); 509 double AlphaPOWP1 = 1.0 + pow(Alpha, 2); 510 511 int ImageResolution = (int) Data.GetCurrentImageResolution(); 512 int IncAddVal = (ImageResolution > RingWidthLocal) ? 1 513 : (RingWidthLocal - ImageResolution + 1); 514 515 double SignFactor = abs(InputLatitude) / InputLatitude; 516 517 YInc = (IRData_Remap_NumberRows) - 1; 518 if ((InputLongitude < 0.0) 519 && ((IRData_Remap_Longitude[0][0] > 180.0) || (IRData_Remap_Longitude[YInc][0] > 180.0))) { 520 /* 521 * System.out.printf("DATELINE CROSS... changing InputLongitude from %f" 522 * ,InputLongitude); 523 */ 524 InputLongitude = InputLongitude + 360.0; 525 } 526 527 for (YInc = 0; YInc < IRData_Remap_NumberRows; YInc++) { 528 for (XInc = 0; XInc < IRData_Remap_NumberColumns; XInc++) { 529 /* compute normalized coordinate system arrays */ 530 IRData_NormCoord_Longitude[YInc][XInc] = (IRData_Remap_Longitude[YInc][XInc] - InputLongitude) 531 * (cos(PI * InputLatitude / 180.0)); 532 IRData_NormCoord_Latitude[YInc][XInc] = IRData_Remap_Latitude[YInc][XInc] 533 - InputLatitude; 534 IRData_NormCoord_Temperature[YInc][XInc] = IRData_Remap_Temperature[YInc][XInc]; 535 /* 536 * System.out.printf( 537 * "YInc=%d XInc=%d lat=%f lon=%f lat=%f lon=%f temp=%f\n", 538 * YInc,XInc, IRData_Remap_Latitude[YInc][XInc], 539 * IRData_Remap_Longitude[YInc][XInc], 540 * IRData_NormCoord_Latitude[YInc][XInc], 541 * IRData_NormCoord_Longitude[YInc][XInc], 542 * IRData_Remap_Temperature[YInc][XInc]); 543 */ 544 } 545 } 546 IRData_NormCoord_NumberColumns = IRData_Remap_NumberColumns; 547 IRData_NormCoord_NumberRows = IRData_Remap_NumberRows; 548 549 /* determine lat/lon grid increment */ 550 /* W to E gradient */ 551 double LongitudeIncrement = abs(IRData_NormCoord_Longitude[0][0] 552 - IRData_NormCoord_Longitude[0][1]); 553 /* N to S gradient */ 554 double LatitudeIncrement = abs(IRData_NormCoord_Latitude[0][0] 555 - IRData_NormCoord_Latitude[1][0]); 556 /* 557 * This is to determine longitude multiplier factor... original routines 558 * were developed using negative, but McIDAS is positive in WH. So if 559 * LongitudeMultFactor is negative, we know (assume) we are using 560 * non-McIDAS input imagery/values, otherwise make LongitudeMultFactor 561 * positive. This all assumes that image is loaded from NW to SE 562 */ 563 double LongitudeMultFactor = IRData_NormCoord_Longitude[0][0] 564 - IRData_NormCoord_Longitude[0][1]; 565 LongitudeMultFactor = (LongitudeMultFactor < 0.0) ? 1.0 : -1.0; 566 /* 567 * System.out.printf( 568 * "LatitudeIncrement=%f LongitudeIncrement=%f LongitudeMultFactor=%f\n" 569 * , LatitudeIncrement, LongitudeIncrement,LongitudeMultFactor); 570 */ 571 572 /* calculate gradient field */ 573 Gradient(IRData_NormCoord_Temperature, IRData_NormCoord_NumberColumns, 574 IRData_NormCoord_NumberRows, LongitudeIncrement, LatitudeIncrement); 575 576 for (YInc = 0; YInc < IRData_NormCoord_NumberRows - 1; YInc++) { 577 for (XInc = 0; XInc < IRData_NormCoord_NumberColumns - 1; XInc++) { 578 /* 579 * System.out.printf( 580 * "YInc=%d XInc=%d remap:lat=%f lon=%f normcoord:lat=%f lon=%f NSTempGradientArray=%f EWTempGrad=%f\n" 581 * , YInc,XInc, 582 * IRData_Remap_Latitude[YInc][XInc],IRData_Remap_Longitude 583 * [YInc][XInc], 584 * IRData_NormCoord_Latitude[YInc][XInc],IRData_NormCoord_Longitude 585 * [YInc][XInc], 586 * NSTempGradientArray[YInc][XInc],EWTempGradientArray 587 * [YInc][XInc]); 588 */ 589 590 double GradientOriginalMag = sqrt(pow(NSTempGradientArray[YInc][XInc], 2) 591 + pow(EWTempGradientArray[YInc][XInc], 2)); 592 double GradientLOGMag = log(1.0 + GradientOriginalMag); 593 double GradientLOGReduction = 0.0; 594 if (GradientLOGMag != 0.0) { 595 GradientLOGReduction = GradientLOGMag / GradientOriginalMag; 596 } 597 NSTempGradientArray[YInc][XInc] = GradientLOGReduction 598 * NSTempGradientArray[YInc][XInc]; 599 EWTempGradientArray[YInc][XInc] = GradientLOGReduction 600 * EWTempGradientArray[YInc][XInc]; 601 } 602 } 603 604 /* COURSE GRID */ 605 /* calculate cross product score at each grid point */ 606 /* XInc/YInc are "starting point" coordinates */ 607 SpiralMeanCrossMaxScore = -99.0; 608 double SearchRadiusMaximum = pow(OuterSearchRadiusDegree 609 + ((2.0 * CourseGridSpacingDegree) / 3.0), 2); 610 for (XOff = -OuterSearchRadiusDegree; XOff <= OuterSearchRadiusDegree; XOff = XOff 611 + CourseGridSpacingDegree) { 612 for (YOff = -OuterSearchRadiusDegree; YOff <= OuterSearchRadiusDegree; YOff = YOff 613 + CourseGridSpacingDegree) { 614 /* XOff/YOff are offset coordinates from "starting point" */ 615 SearchRadius = pow(XOff, 2) + pow(YOff, 2); 616 if (SearchRadius <= SearchRadiusMaximum) { 617 CrossScoreSum = 0.0; 618 NumPoints = 0; 619 for (YInc = 1; YInc < IRData_NormCoord_NumberRows - 2; YInc = YInc + IncAddVal) { 620 for (XInc = 1; XInc < IRData_NormCoord_NumberColumns - 2; XInc = XInc 621 + IncAddVal) { 622 SearchRadius = pow(IRData_NormCoord_Longitude[YInc][XInc], 2) 623 + pow(IRData_NormCoord_Latitude[YInc][XInc], 2); 624 if (SearchRadius < FilterDiscSize) { 625 ProxyValueX = LongitudeMultFactor 626 * IRData_NormCoord_Longitude[YInc][XInc] - XOff; 627 ProxyValueY = IRData_NormCoord_Latitude[YInc][XInc] - YOff; 628 DenominatorValue = sqrt((AlphaPOWP1) 629 * (pow(ProxyValueX, 2) + pow(ProxyValueY, 2))); 630 SpiralValueX = ((Alpha * ProxyValueX) + (SignFactor * ProxyValueY)) 631 / DenominatorValue; 632 SpiralValueY = ((Alpha * ProxyValueY) - (SignFactor * ProxyValueX)) 633 / DenominatorValue; 634 RawCrossScore = (SpiralValueX * NSTempGradientArray[YInc][XInc]) 635 - (SpiralValueY * EWTempGradientArray[YInc][XInc]); 636 CrossScoreClean = max(0.0, -RawCrossScore) 637 + (OutsideFactor * max(0.0, RawCrossScore)); 638 CrossScoreSum = CrossScoreSum + CrossScoreClean; 639 /* 640 * System.out.printf( 641 * "%d %d : lat=%f lon=%f xoff=%f yoff=%f ", 642 * "ProxyValueX=%f ProxyValueY=%f ", 643 * "SpiralValueX=%f SpiralValueY=%f ", 644 * "rawScore=%f clean=%f\n", 645 * IRData_Remap_Latitude[YInc][XInc], 646 * IRData_Remap_Longitude[YInc][XInc], 647 * XOff,YOff,ProxyValueX,ProxyValueY, 648 * SpiralValueX,SpiralValueY, 649 * RawCrossScore,CrossScoreClean); 650 */ 651 NumPoints++; 652 } 653 } 654 } 655 /* calculate mean of all values in CrossScore array */ 656 SpiralMeanCrossScore = CrossScoreSum / (double) NumPoints; 657 /* store location of maximum score position */ 658 if (SpiralMeanCrossScore > SpiralMeanCrossMaxScore) { 659 SpiralMeanCrossMaxScore = SpiralMeanCrossScore; 660 SpiralMeanCrossMaxYLocation = YOff; 661 SpiralMeanCrossMaxXLocation = XOff; 662 } 663 } 664 } 665 } 666 667 /* 668 * System.out.printf("course grid : y=%f x=%f max=%f\n", 669 * SpiralMeanCrossMaxYLocation,SpiralMeanCrossMaxXLocation, 670 * SpiralMeanCrossMaxScore); 671 */ 672 673 /* FINE GRID */ 674 int SpiralCount = 1; 675 double FineGridXMinimum = SpiralMeanCrossMaxXLocation - CourseGridSpacingDegree; 676 double FineGridXMaximum = SpiralMeanCrossMaxXLocation + CourseGridSpacingDegree; 677 double FineGridYMimimum = SpiralMeanCrossMaxYLocation - CourseGridSpacingDegree; 678 double FineGridYMaximum = SpiralMeanCrossMaxYLocation + CourseGridSpacingDegree; 679 SpiralMeanCrossMaxScore = -99.0; 680 for (XOff = FineGridXMinimum; XOff <= FineGridXMaximum; XOff = XOff + FineGridSpacingDegree) { 681 for (YOff = FineGridYMimimum; YOff <= FineGridYMaximum; YOff = YOff 682 + FineGridSpacingDegree) { 683 /* XOff/YOff are offset coordinates from "starting point" */ 684 CrossScoreSum = 0.0; 685 NumPoints = 0; 686 for (YInc = 1; YInc < IRData_NormCoord_NumberRows - 2; YInc++) { 687 for (XInc = 1; XInc < IRData_NormCoord_NumberColumns - 2; XInc++) { 688 SearchRadius = Math.pow(IRData_NormCoord_Longitude[YInc][XInc], 2) 689 + Math.pow(IRData_NormCoord_Latitude[YInc][XInc], 2); 690 if (SearchRadius < FilterDiscSize) { 691 ProxyValueX = LongitudeMultFactor 692 * IRData_NormCoord_Longitude[YInc][XInc] - XOff; 693 ProxyValueY = IRData_NormCoord_Latitude[YInc][XInc] - YOff; 694 DenominatorValue = Math.sqrt((AlphaPOWP1) 695 * (Math.pow(ProxyValueX, 2) + Math.pow(ProxyValueY, 2))); 696 SpiralValueX = (Alpha * ProxyValueX + (SignFactor * ProxyValueY)) 697 / DenominatorValue; 698 SpiralValueY = (Alpha * ProxyValueY - (SignFactor * ProxyValueX)) 699 / DenominatorValue; 700 RawCrossScore = (SpiralValueX * NSTempGradientArray[YInc][XInc]) 701 - (SpiralValueY * EWTempGradientArray[YInc][XInc]); 702 CrossScoreClean = Math.max(0.0, -RawCrossScore) 703 + (OutsideFactor * Math.max(0.0, RawCrossScore)); 704 CrossScoreSum = CrossScoreSum + CrossScoreClean; 705 NumPoints++; 706 } 707 } 708 } 709 /* calculate mean of all values in CrossScore array */ 710 SpiralMeanCrossScore = CrossScoreSum / (double) NumPoints; 711 /* store location of maximum score position */ 712 if (SpiralMeanCrossScore > SpiralMeanCrossMaxScore) { 713 SpiralMeanCrossMaxScore = SpiralMeanCrossScore; 714 SpiralMeanCrossMaxYLocation = YOff; 715 SpiralMeanCrossMaxXLocation = XOff; 716 } 717 SpiralCenterAnalysisField[SpiralCount][0] = SpiralMeanCrossScore; 718 SpiralCenterAnalysisField[SpiralCount][1] = (double) YOff; 719 SpiralCenterAnalysisField[SpiralCount][2] = (double) XOff; 720 SpiralCenterAnalysisField[0][0] = (double) SpiralCount; 721 SpiralCount++; 722 } 723 } 724 725 /* 726 * System.out.printf("fine grid : y=%f x=%f max=%f\n", 727 * SpiralMeanCrossMaxYLocation 728 * ,SpiralMeanCrossMaxXLocation,SpiralMeanCrossMaxScore); 729 */ 730 731 SpiralCenterAnalysisField[0][1] = 0.0; 732 SpiralCenterAnalysisField[0][2] = 0.0; 733 734 /* determine lat/lon point from x/y coordinates */ 735 SpiralCenterLatitude = SpiralMeanCrossMaxYLocation + InputLatitude; 736 SpiralCenterLongitude = ((LongitudeMultFactor * SpiralMeanCrossMaxXLocation) / (Math.cos(PI 737 * InputLatitude / 180.0))) 738 + InputLongitude; 739 SpiralCenterScore = SpiralMeanCrossMaxScore; 740 for (YInc = 1; YInc <= (int) SpiralCenterAnalysisField[0][0]; YInc++) { 741 SpiralCenterAnalysisField[YInc][1] = SpiralCenterAnalysisField[YInc][1] + InputLatitude; 742 SpiralCenterAnalysisField[YInc][2] = ((LongitudeMultFactor * SpiralCenterAnalysisField[YInc][2]) / (Math 743 .cos(PI * InputLatitude / 180.0))) + InputLongitude; 744 } 745 746 return new double[] { SpiralCenterLatitude, SpiralCenterLongitude, SpiralCenterScore }; 747 } 748 749 private static void Gradient(double TemperatureInputArray[][], int ElementXNumber, 750 int LineYNumber, double LongitudeIncrement, double LatitudeIncrement) { 751 752 int XInc, YInc; 753 754 /* initialize arrays */ 755 for (YInc = 0; YInc < LineYNumber - 1; YInc++) { 756 for (XInc = 0; XInc < ElementXNumber - 1; XInc++) { 757 NSTempGradientArray[YInc][XInc] = 0.0; 758 EWTempGradientArray[YInc][XInc] = 0.0; 759 } 760 } 761 762 for (YInc = 1; YInc < LineYNumber - 1; YInc++) { 763 for (XInc = 1; XInc < ElementXNumber - 1; XInc++) { 764 /* determine N-S gradient at point */ 765 NSTempGradientArray[YInc][XInc] = (TemperatureInputArray[YInc - 1][XInc] - TemperatureInputArray[YInc + 1][XInc]) 766 / (2.0 * LatitudeIncrement); 767 /* determine E-W gradient at point */ 768 EWTempGradientArray[YInc][XInc] = (TemperatureInputArray[YInc][XInc + 1] - TemperatureInputArray[YInc][XInc - 1]) 769 / (2.0 * LongitudeIncrement); 770 } 771 } 772 773 } 774 775 private static double[] RingFit(double RingFitFirstGuessLatitude, 776 double RingFitFirstGuessLongitude) { 777 778 int XInc, YInc, ZInc; 779 int CircleFilterRadii; 780 int CircleFilterPoints; 781 782 int RingWidthLocal = (int) RING_WIDTH; 783 int XLocation = 0; 784 int YLocation = 0; 785 int CircleFilterXLocation = 0; 786 int CircleFilterYLocation = 0; 787 788 double[][] GradientFieldXDirection = new double[200][200]; 789 double[][] GradientFieldYDirection = new double[200][200]; 790 791 double RingFitSearchRadiusDegree = 0.75; 792 double RingFitMinRadiusDegree = 0.06; 793 double RingFitMaxRadiusDegree = 0.40; 794 double CircleFilterDistance = 0.0; 795 796 double DotScoreMaximum = -99999.0; 797 double DotProductXDirection = -999.9; 798 double DotProductYDirection = -999.9; 799 double DotProductXYValue = -999.9; 800 double SignFactor = 0.0; 801 double DotScoreValue = 0.0; 802 double DotScoreValueSum = 0.0; 803 double DotScoreFinal = 0.0; 804 double NANAdjustmentValue = 0.0; 805 806 int ImageResolution = (int) Data.GetCurrentImageResolution(); 807 int IncAddVal = (ImageResolution > RingWidthLocal) ? 1 808 : (RingWidthLocal - ImageResolution + 1); 809 810 /* derive values */ 811 double DegreesPerPixel = Math 812 .abs(IRData_Remap_Latitude[0][0] - IRData_Remap_Latitude[1][0]); 813 int RingFitSearchRadiusPixel = (int) Math 814 .round(RingFitSearchRadiusDegree / DegreesPerPixel); 815 int RingFitMinRadiusPix = (int) Math.max(2.0, 816 Math.round(RingFitMinRadiusDegree / DegreesPerPixel)); 817 int MaximumRadiusSizePixels = (int) Math.round(RingFitMaxRadiusDegree / DegreesPerPixel); 818 819 double LongitudeIncrement = 1.0; 820 double LatitudeIncrement = -1.0; 821 822 /* 823 * System.out.printf("RingFit: %d %f %d %d %d\n",IncAddVal,DegreesPerPixel 824 * , RingFitSearchRadiusPixel,RingFitMinRadiusPix, 825 * MaximumRadiusSizePixels); 826 */ 827 /* 828 * for(YInc=0;YInc<IRData_Remap_NumberRows-1;YInc++) { 829 * for(XInc=0;XInc<IRData_Remap_NumberColumns-1;XInc++) { 830 * System.out.printf 831 * ("Y=%d X=%d lat=%f lon=%f\n",YInc,XInc,IRData_Remap_Latitude 832 * [YInc][XInc],IRData_Remap_Longitude[YInc][XInc]); } } 833 */ 834 835 /* NEED TO PASS BACK BOTH 2D ARRAYS FROM GRADIENT AND CIRCLEFILT */ 836 /* calculate gradient field */ 837 Gradient(IRData_Remap_Temperature, IRData_Remap_NumberColumns, IRData_Remap_NumberRows, 838 LongitudeIncrement, LatitudeIncrement); 839 840 for (YInc = 0; YInc < IRData_Remap_NumberRows - 1; YInc++) { 841 for (XInc = 0; XInc < IRData_Remap_NumberColumns - 1; XInc++) { 842 GradientFieldYDirection[YInc][XInc] = NSTempGradientArray[YInc][XInc]; 843 GradientFieldXDirection[YInc][XInc] = EWTempGradientArray[YInc][XInc]; 844 /* 845 * System.out.printf("GRADIENT Y=%d X=%d Xdir=%f Ydir=%f ",YInc 846 * , 847 * XInc,GradientFieldXDirection[YInc][XInc],GradientFieldYDirection 848 * [YInc][XInc]); 849 */ 850 /* 851 * System.out.printf(" lat=%f lon=%f\n",IRData_Remap_Latitude[YInc 852 * ][XInc],IRData_Remap_Longitude[YInc][XInc]); 853 */ 854 } 855 } 856 /* 857 * System.out.printf( 858 * "RingFit : RingFitFirstGuessLatitude=%f RingFitFirstGuessLongitude=%f\n" 859 * , RingFitFirstGuessLatitude,RingFitFirstGuessLongitude); 860 */ 861 862 /* make matricies of row and column numbers */ 863 int Lalo2IndsReturn[] = Lalo2IndsFloat(RingFitFirstGuessLatitude, 864 RingFitFirstGuessLongitude, IRData_Remap_Latitude, IRData_Remap_Longitude, 865 IRData_Remap_NumberColumns, IRData_Remap_NumberRows); 866 867 int FirstGuessXLocation = Lalo2IndsReturn[0]; 868 int FirstGuessYLocation = Lalo2IndsReturn[1]; 869 870 /* 871 * System.out.printf( 872 * "RingFit : FirstGuessXLocation=%d FirstGuessYLocation=%d\n", 873 * FirstGuessXLocation,FirstGuessYLocation); 874 */ 875 876 /* initialize circle/ring filter arrays */ 877 /* radius in pixels */ 878 879 for (CircleFilterRadii = 0; CircleFilterRadii < 100; CircleFilterRadii++) { 880 /* number of points on circle at radius */ 881 for (CircleFilterPoints = 0; CircleFilterPoints < 2000; CircleFilterPoints++) { 882 CircleFilterRowArray[CircleFilterRadii][CircleFilterPoints] = 0; 883 CircleFilterColumnArray[CircleFilterRadii][CircleFilterPoints] = 0; 884 } 885 } 886 887 /* 888 * determine digital pixel coordinates for ring analysis for different 889 * radii sizes 890 */ 891 for (CircleFilterRadii = RingFitMinRadiusPix; CircleFilterRadii <= MaximumRadiusSizePixels; CircleFilterRadii++) { 892 CircleFilt(CircleFilterRadii); 893 } 894 895 /* search image box */ 896 ZInc = 1; 897 /* develop the accumulator */ 898 for (CircleFilterRadii = RingFitMinRadiusPix; CircleFilterRadii < MaximumRadiusSizePixels; CircleFilterRadii++) { 899 int CircleFilterPointCount = CircleFilterRowArray[CircleFilterRadii][0]; 900 /* determine each main point in analysis disc */ 901 for (XInc = 1; XInc < IRData_Remap_NumberColumns - 1; XInc = XInc + IncAddVal) { 902 for (YInc = 1; YInc < IRData_Remap_NumberRows - 1; YInc = YInc + IncAddVal) { 903 /* 904 * System.out.printf("XInc=%d YInc=%d %d %d: %d\n",XInc,YInc 905 * , FirstGuessXLocation,FirstGuessYLocation, 906 * RingFitSearchRadiusPixel); 907 */ 908 909 CircleFilterDistance = (double) ((XInc - FirstGuessXLocation) * (XInc - FirstGuessXLocation)) 910 + ((YInc - FirstGuessYLocation) * (YInc - FirstGuessYLocation)); 911 /* 912 * System.out.printf( 913 * "XInc=%d YInc=%d CircleFilterDistance=%f RingFitSearchRadiusPixel=%d\n" 914 * , 915 * XInc,YInc,CircleFilterDistance,RingFitSearchRadiusPixel); 916 */ 917 if (CircleFilterDistance <= (double) (RingFitSearchRadiusPixel * RingFitSearchRadiusPixel)) { 918 /* 919 * if main point (YInc,XInc) is in disc, calculate 920 * dotproduct for each subpoint on ring around main 921 * point 922 */ 923 DotScoreValueSum = 0.0; 924 int NANCount = 0; 925 boolean FoundMoatRegionTF = false; 926 /* 927 * System.out.printf( 928 * "XInc=%d YInc=%d CircleFilterPointCount=%d %d\n", 929 * XInc,YInc,CircleFilterPointCount,CircleFilterRadii); 930 */ 931 for (CircleFilterPoints = 1; CircleFilterPoints <= CircleFilterPointCount; CircleFilterPoints++) { 932 /* 933 * System.out.printf( 934 * "CircleFilterPoints=%d CircleFilterRadii=%d XInc=%d YInc=%d\n" 935 * , 936 * CircleFilterPoints,CircleFilterRadii,XInc,YInc); 937 */ 938 CircleFilterXLocation = XInc 939 + CircleFilterColumnArray[CircleFilterRadii][CircleFilterPoints]; 940 CircleFilterYLocation = YInc 941 + CircleFilterRowArray[CircleFilterRadii][CircleFilterPoints]; 942 /* 943 * System.out.printf("%d : %d %d -- %d : %d %d ", 944 * CircleFilterYLocation,YInc, 945 * CircleFilterRowArray[CircleFilterRadii 946 * ][CircleFilterPoints], 947 * CircleFilterXLocation,XInc, 948 * CircleFilterColumnArray 949 * [CircleFilterRadii][CircleFilterPoints]); 950 */ 951 if ((CircleFilterXLocation < 1) || (CircleFilterYLocation < 1)) { 952 DotProductXDirection = -999.9; 953 DotProductYDirection = -999.9; 954 } else { 955 /* 956 * System.out.printf( 957 * "I=%d x=%d J=%d y=%d : %b %b\n", 958 * CircleFilterXLocation 959 * ,IRData_Remap_NumberColumns, 960 * CircleFilterYLocation 961 * ,IRData_Remap_NumberRows, 962 * (CircleFilterXLocation 963 * >=IRData_Remap_NumberColumns), 964 * (CircleFilterYLocation 965 * >=IRData_Remap_NumberRows)); 966 */ 967 if ((CircleFilterXLocation >= (IRData_Remap_NumberColumns - 1)) 968 || (CircleFilterYLocation >= (IRData_Remap_NumberRows - 1))) { 969 DotProductXDirection = -999.9; 970 DotProductYDirection = -999.9; 971 } else { 972 if (MoatMaskFlagField[CircleFilterYLocation][CircleFilterXLocation] == 1) { 973 FoundMoatRegionTF = true; 974 } 975 /* 976 * System.out.printf( 977 * " mask=%d FoundMoatRegionTF=%b\n" 978 * ,MoatMaskFlagField 979 * [CircleFilterYLocation][ 980 * CircleFilterXLocation 981 * ],FoundMoatRegionTF); 982 */ 983 if (FoundMoatRegionTF) { 984 DotProductXDirection = -999.9; 985 DotProductYDirection = -999.9; 986 } else { 987 DotProductXDirection = ((double) CircleFilterRowArray[CircleFilterRadii][CircleFilterPoints] / (double) CircleFilterRadii) 988 * GradientFieldYDirection[CircleFilterYLocation][CircleFilterXLocation]; 989 /* 990 * System.out.printf( 991 * " XX | %d %d j=%d i=%d j=%d i=%d GradientFieldYDirection=%f GradientFieldXDirection=%f | \n" 992 * , 993 * CircleFilterPoints,CircleFilterRadii, 994 * CircleFilterRowArray 995 * [CircleFilterRadii 996 * ][CircleFilterPoints], 997 * CircleFilterColumnArray 998 * [CircleFilterRadii 999 * ][CircleFilterPoints], 1000 * CircleFilterYLocation, 1001 * CircleFilterXLocation, 1002 * GradientFieldYDirection 1003 * [CircleFilterYLocation 1004 * ][CircleFilterXLocation], 1005 * GradientFieldXDirection 1006 * [CircleFilterYLocation 1007 * ][CircleFilterXLocation]); 1008 */ 1009 DotProductYDirection = ((double) CircleFilterColumnArray[CircleFilterRadii][CircleFilterPoints] / (double) CircleFilterRadii) 1010 * GradientFieldXDirection[CircleFilterYLocation][CircleFilterXLocation]; 1011 } 1012 } 1013 } 1014 if ((DotProductXDirection < -999.0) || (DotProductYDirection < -999.0)) { 1015 NANCount++; 1016 } else { 1017 DotProductXYValue = DotProductXDirection + DotProductYDirection; 1018 if (DotProductXYValue == 0.0) { 1019 SignFactor = 0.0; 1020 } else { 1021 /* return -1/+1 for -/+ value */ 1022 SignFactor = Math.abs(DotProductXYValue) / DotProductXYValue; 1023 } 1024 DotScoreValue = SignFactor 1025 * (Math.log(1.0 + Math.abs(DotProductXYValue))); 1026 DotScoreValueSum = DotScoreValueSum + DotScoreValue; 1027 } 1028 /* 1029 * System.out.printf( 1030 * "dot product X=%f Y=%f XY=%f value=%f sum=%f\n" 1031 * ,DotProductXDirection, 1032 * DotProductYDirection,DotProductXYValue 1033 * ,DotScoreValue,DotScoreValueSum); 1034 */ 1035 } /* if indisk */ 1036 /* 1037 * System.out.printf("dot product Final Sum=%f \n", 1038 * DotScoreValueSum); 1039 */ 1040 /* 1041 * check for missing data and adjust DotScoreFinal 1042 * accordingly 1043 */ 1044 /* 1045 * System.out.printf( 1046 * "Y=%d X=%d foundmoat=%b nancount=%f xyz=%f\n" 1047 * ,YInc,XInc 1048 * ,FoundMoatRegionTF,(double)NANCount,0.575*(double 1049 * )CircleFilterPointCount); 1050 */ 1051 if (FoundMoatRegionTF 1052 || ((double) NANCount) > (0.575 * (double) CircleFilterPointCount)) { 1053 DotScoreFinal = 0.0; 1054 } else { 1055 NANAdjustmentValue = (double) CircleFilterPointCount 1056 / (double) (CircleFilterPointCount - NANCount); 1057 DotScoreFinal = -NANAdjustmentValue * DotScoreValueSum 1058 / Math.sqrt((double) CircleFilterPointCount); 1059 } 1060 /* 1061 * System.out.printf("XX final=%f maximum=%f ",DotScoreFinal 1062 * ,DotScoreMaximum); 1063 */ 1064 /* 1065 * System.out.printf( 1066 * " circlefilterpointcount=%d sqrt=%f " 1067 * ,CircleFilterPointCount 1068 * ,Math.sqrt((double)CircleFilterPointCount)); 1069 */ 1070 if (DotScoreFinal > DotScoreMaximum) { 1071 DotScoreMaximum = DotScoreFinal; 1072 XLocation = XInc; 1073 YLocation = YInc; 1074 /* 1075 * System.out.printf(" xloc=%d yloc=%d MaxRadSize=%d" 1076 * ,XInc,YInc,MaximumRadiusSize); 1077 */ 1078 } 1079 /* System.out.printf("\n"); */ 1080 RingScoreAnalysisField[ZInc][0] = DotScoreFinal; 1081 RingScoreAnalysisField[ZInc][1] = IRData_Remap_Latitude[YInc][XInc]; 1082 RingScoreAnalysisField[ZInc][2] = IRData_Remap_Longitude[YInc][XInc]; 1083 RingScoreAnalysisField[0][0] = (double) ZInc; 1084 /* 1085 * System.out.printf("ZZZZ 0=%f 1=%f 2=%f x=%f\n", 1086 * RingScoreAnalysisField 1087 * [ZInc][0],RingScoreAnalysisField[ZInc][1], 1088 * RingScoreAnalysisField 1089 * [ZInc][2],RingScoreAnalysisField[0][0]); 1090 */ 1091 ZInc++; 1092 } 1093 } /* XInc */ 1094 } /* YInc */ 1095 } /* CircleFilterRadii */ 1096 1097 RingScoreAnalysisField[0][1] = 0.0; 1098 RingScoreAnalysisField[0][2] = 0.0; 1099 1100 /* make matricies of row and column numbers */ 1101 /* System.out.printf("inds2lalo: x=%d y=%d \n",XLocation,YLocation); */ 1102 double Inds2LaloReturn[] = Inds2LaloFloat(XLocation, YLocation, IRData_Remap_Latitude, 1103 IRData_Remap_Longitude, IRData_Remap_NumberColumns, IRData_Remap_NumberRows); 1104 double MaxScoreLatitude = Inds2LaloReturn[0]; 1105 double MaxScoreLongitude = Inds2LaloReturn[1]; 1106 1107 double RingFitLatitude = MaxScoreLatitude; 1108 double RingFitLongitude = MaxScoreLongitude; 1109 double RingFitMaxScore = DotScoreMaximum; 1110 1111 return new double[] { RingFitLatitude, RingFitLongitude, RingFitMaxScore }; 1112 } 1113 1114 private static int[] Lalo2IndsFloat(double LatitudeInput, double LongitudeInput, 1115 double LatitudeArrayInput[][], double LongitudeArrayInput[][], int ElementXNumber, 1116 int LineYNumber) { 1117 1118 double LatitudeMinimum = LatitudeArrayInput[LineYNumber - 1][0]; 1119 double LatitudeMaximum = LatitudeArrayInput[0][0]; 1120 double LongitudeMinimum = LongitudeArrayInput[0][ElementXNumber - 1]; 1121 double LongitudeMaximum = LongitudeArrayInput[0][0]; 1122 1123 int YAxisPositionReturn = (int) ((((double) LineYNumber - 1.0) / (LatitudeMaximum - LatitudeMinimum)) * (LatitudeMaximum - LatitudeInput)); 1124 int XAxisPositionReturn = (int) ((((double) ElementXNumber - 1.0) / (LongitudeMaximum - LongitudeMinimum)) * (LongitudeMaximum - LongitudeInput)); 1125 1126 return new int[] { XAxisPositionReturn, YAxisPositionReturn }; 1127 1128 } 1129 1130 private static double[] Inds2LaloFloat(int XAxisPosition, int YAxisPosition, 1131 double LatitudeArrayInput[][], double LongitudeArrayInput[][], int ElementXNumber, 1132 int LineYNumber) { 1133 1134 double LatitudeMinimum = LatitudeArrayInput[LineYNumber - 1][0]; 1135 double LatitudeMaximum = LatitudeArrayInput[0][0]; 1136 double LongitudeMinimum = LongitudeArrayInput[0][ElementXNumber - 1]; 1137 double LongitudeMaximum = LongitudeArrayInput[0][0]; 1138 1139 double LongitudeReturn = LongitudeMaximum 1140 - ((((double) XAxisPosition) / ((double) ElementXNumber - 1.0)) * (LongitudeMaximum - LongitudeMinimum)); 1141 double LatitudeReturn = LatitudeMaximum 1142 - ((((double) YAxisPosition) / ((double) LineYNumber - 1.0)) * (LatitudeMaximum - LatitudeMinimum)); 1143 1144 return new double[] { LatitudeReturn, LongitudeReturn }; 1145 1146 } 1147 1148 private static void CircleFilt(int RingRadiusInput) { 1149 1150 int XInc, YInc; 1151 int PointCount = 1; 1152 int RadiusPlus1 = RingRadiusInput + 1; 1153 1154 double ThresholdDifference = 0.5 * (double) (((RingRadiusInput + 1) * (RingRadiusInput + 1)) - (RingRadiusInput * RingRadiusInput)); 1155 for (XInc = -RadiusPlus1; XInc <= RadiusPlus1; XInc++) { 1156 for (YInc = -RadiusPlus1; YInc <= RadiusPlus1; YInc++) { 1157 double DifferenceValue = (double) ((YInc * YInc) + (XInc * XInc) - (RingRadiusInput * RingRadiusInput)); 1158 if (Math.abs(DifferenceValue) <= ThresholdDifference) { 1159 CircleFilterRowArray[RingRadiusInput][PointCount] = YInc; 1160 CircleFilterColumnArray[RingRadiusInput][PointCount] = XInc; 1161 PointCount++; 1162 } 1163 } 1164 } 1165 1166 /* number of points on given radius size */ 1167 CircleFilterRowArray[RingRadiusInput][0] = PointCount - 1; 1168 CircleFilterColumnArray[RingRadiusInput][0] = PointCount - 1; 1169 1170 } 1171 1172 private static void MoatMaskCalc(double MoatMaskTempThreshold, double RingFitMaxRadiusDegree, 1173 int MoatSignCheckFlag) { 1174 1175 int ArrayInc, XInc, YInc; 1176 int NumberColumns = IRData_Remap_NumberColumns; 1177 int NumberRows = IRData_Remap_NumberRows; 1178 1179 /* initialize arrays */ 1180 for (YInc = 0; YInc < NumberRows; YInc++) { 1181 for (XInc = 0; XInc < NumberColumns; XInc++) { 1182 MoatMaskFlagField[YInc][XInc] = 0; 1183 BlackWhiteFieldArray[YInc][XInc] = 0; 1184 } 1185 } 1186 1187 MeshGrid(MoatMaskTempThreshold, MoatSignCheckFlag); 1188 int NumberOfObjects = BWImage(8, NumberRows, NumberColumns); 1189 1190 for (ArrayInc = 1; ArrayInc <= NumberOfObjects; ArrayInc++) { 1191 double LatitudeMaximum = -90.0; 1192 double LatitudeMinimum = 90.0; 1193 double LongitudeMaximum = -180.0; 1194 double LongitudeMinimum = 180.0; 1195 for (YInc = 0; YInc < NumberRows; YInc++) { 1196 for (XInc = 0; XInc < NumberColumns; XInc++) { 1197 if (MoatMaskFlagField[YInc][XInc] == ArrayInc) { 1198 double LatitudeValue = IRData_Remap_Latitude[YInc][XInc]; 1199 double LongitudeValue = IRData_Remap_Longitude[YInc][XInc]; 1200 if (LatitudeValue > LatitudeMaximum) { 1201 LatitudeMaximum = LatitudeValue; 1202 } 1203 if (LongitudeValue > LongitudeMaximum) { 1204 LongitudeMaximum = LongitudeValue; 1205 } 1206 if (LatitudeValue < LatitudeMinimum) { 1207 LatitudeMinimum = LatitudeValue; 1208 } 1209 if (LongitudeValue < LongitudeMinimum) { 1210 LongitudeMinimum = LongitudeValue; 1211 } 1212 } 1213 } 1214 } 1215 double AverageLatitude = .5 * (LatitudeMinimum + LatitudeMaximum); 1216 double FeatureLength = Math.sqrt(Math.pow((LatitudeMaximum - LatitudeMinimum), 2) 1217 + Math.pow( 1218 (LongitudeMaximum - LongitudeMinimum) 1219 / Math.cos((PI * AverageLatitude) / 180.0), 2)); 1220 int MoatFlagID = (FeatureLength > (RingFitMaxRadiusDegree * 2.0)) ? 1 : 0; 1221 for (YInc = 0; YInc < NumberRows; YInc++) { 1222 for (XInc = 0; XInc < NumberColumns; XInc++) { 1223 if (MoatMaskFlagField[YInc][XInc] == ArrayInc) { 1224 MoatMaskFlagField[YInc][XInc] = MoatFlagID; 1225 } 1226 } 1227 } 1228 } 1229 1230 } 1231 1232 private static void MeshGrid(double TemperatureThresholdValue, int MoatSignCheckFlag) { 1233 1234 int XInc, YInc; 1235 1236 for (XInc = 0; XInc < IRData_Remap_NumberColumns; XInc++) { 1237 for (YInc = 0; YInc < IRData_Remap_NumberRows; YInc++) { 1238 if (MoatSignCheckFlag == 1) { 1239 BlackWhiteFieldArray[YInc][XInc] = (IRData_Remap_Temperature[YInc][XInc] > TemperatureThresholdValue) ? 1 1240 : 0; 1241 } else { 1242 BlackWhiteFieldArray[YInc][XInc] = (IRData_Remap_Temperature[YInc][XInc] < TemperatureThresholdValue) ? 1 1243 : 0; 1244 } 1245 } 1246 } 1247 1248 } 1249 1250 private static int BWImage(int ConnectednessValue, int NumberRows, int NumberColumns) { 1251 /* 1252 * blackwhitefieldarray = BooleanValueArray; moatmaskflagfield = 1253 * LabelImageArray 1254 */ 1255 1256 int IncVal, XInc, YInc; 1257 int B_Value, C_Value, D_Value, E_Value; 1258 int TableElements = 0; 1259 int LabelValue = 0; 1260 int[] LabelSetArray = new int[NumberRows * NumberColumns]; 1261 1262 LabelSetArray[0] = 0; 1263 1264 for (YInc = 0; YInc < NumberRows; YInc++) { 1265 for (XInc = 0; XInc < NumberColumns; XInc++) { 1266 if (BlackWhiteFieldArray[YInc][XInc] == 1) { 1267 /* if A is an object */ 1268 /* 1269 * get the neighboring pixels B_Value, C_Value, D_Value, and 1270 * E_Value 1271 */ 1272 B_Value = 0; 1273 C_Value = 0; 1274 D_Value = 0; 1275 E_Value = 0; 1276 if (XInc > 0) { 1277 B_Value = Find(LabelSetArray, MoatMaskFlagField[YInc][XInc - 1]); 1278 } 1279 if (YInc > 0) { 1280 C_Value = Find(LabelSetArray, MoatMaskFlagField[YInc - 1][XInc]); 1281 } 1282 if ((YInc > 0) && (XInc > 0)) { 1283 D_Value = Find(LabelSetArray, MoatMaskFlagField[YInc - 1][XInc - 1]); 1284 } 1285 if ((YInc > 0) && (XInc > (NumberColumns - 1))) { 1286 E_Value = Find(LabelSetArray, MoatMaskFlagField[YInc - 1][XInc + 1]); 1287 } 1288 if (ConnectednessValue == 4) { 1289 /* apply 4 connectedness */ 1290 if ((B_Value != 0) && (C_Value != 0)) { 1291 /* B_Value and C_Value are labeled */ 1292 if (B_Value == C_Value) { 1293 MoatMaskFlagField[YInc][XInc] = B_Value; 1294 } else { 1295 LabelSetArray[C_Value] = B_Value; 1296 MoatMaskFlagField[YInc][XInc] = B_Value; 1297 } 1298 } else if (B_Value != 0) { 1299 /* B_Value is object but C_Value is not */ 1300 MoatMaskFlagField[YInc][XInc] = B_Value; 1301 } else if (C_Value != 0) { 1302 /* C_Value is object but B_Value is not */ 1303 MoatMaskFlagField[YInc][XInc] = C_Value; 1304 } else { 1305 /* B_Value, C_Value, D_Value not object - new object */ 1306 /* label and put into table */ 1307 TableElements++; 1308 LabelSetArray[TableElements] = TableElements; 1309 MoatMaskFlagField[YInc][XInc] = LabelSetArray[TableElements]; 1310 } 1311 } else if (ConnectednessValue == 6) { 1312 /* apply 6 connected ness */ 1313 if (D_Value != 0) { 1314 /* D_Value object, copy label and move on */ 1315 MoatMaskFlagField[YInc][XInc] = D_Value; 1316 } else if ((B_Value != 0) && (C_Value != 0)) { 1317 /* B_Value and C_Value are labeled */ 1318 if (B_Value == C_Value) { 1319 MoatMaskFlagField[YInc][XInc] = B_Value; 1320 } else { 1321 LabelValue = Math.min(B_Value, C_Value); 1322 LabelSetArray[B_Value] = LabelValue; 1323 LabelSetArray[C_Value] = LabelValue; 1324 MoatMaskFlagField[YInc][XInc] = LabelValue; 1325 } 1326 } else if (B_Value != 0) { 1327 /* B_Value is object but C_Value is not */ 1328 MoatMaskFlagField[YInc][XInc] = B_Value; 1329 } else if (C_Value != 0) { 1330 /* C_Value is object but B_Value is not */ 1331 MoatMaskFlagField[YInc][XInc] = C_Value; 1332 } else { 1333 /* B_Value, C_Value, D_Value not object - new object */ 1334 /* label and put into table */ 1335 TableElements++; 1336 LabelSetArray[TableElements] = TableElements; 1337 MoatMaskFlagField[YInc][XInc] = LabelSetArray[TableElements]; 1338 } 1339 } else if (ConnectednessValue == 8) { 1340 /* apply 8 connectedness */ 1341 if ((B_Value != 0) || (C_Value != 0) || (D_Value != 0) || (E_Value != 0)) { 1342 LabelValue = B_Value; 1343 if (B_Value != 0) { 1344 LabelValue = B_Value; 1345 } else if (C_Value != 0) { 1346 LabelValue = C_Value; 1347 } else if (D_Value != 0) { 1348 LabelValue = D_Value; 1349 } else { 1350 LabelValue = E_Value; 1351 } 1352 MoatMaskFlagField[YInc][XInc] = LabelValue; 1353 if ((B_Value != 0) && (B_Value != LabelValue)) { 1354 LabelSetArray[B_Value] = LabelValue; 1355 } 1356 if ((C_Value != 0) && (C_Value != LabelValue)) { 1357 LabelSetArray[C_Value] = LabelValue; 1358 } 1359 if ((D_Value != 0) && (D_Value != LabelValue)) { 1360 LabelSetArray[D_Value] = LabelValue; 1361 } 1362 if ((E_Value != 0) && (E_Value != LabelValue)) { 1363 LabelSetArray[E_Value] = LabelValue; 1364 } 1365 } else { 1366 /* label and put into table */ 1367 TableElements++; 1368 LabelSetArray[TableElements] = TableElements; 1369 MoatMaskFlagField[YInc][XInc] = LabelSetArray[TableElements]; 1370 } 1371 } 1372 } else { 1373 /* A is not an object so leave it */ 1374 MoatMaskFlagField[YInc][XInc] = 0; 1375 } 1376 } 1377 } 1378 1379 /* consolidate component table */ 1380 for (IncVal = 0; IncVal <= TableElements; IncVal++) { 1381 LabelSetArray[IncVal] = Find(LabelSetArray, IncVal); 1382 } 1383 1384 /* run image through the look-up table */ 1385 for (YInc = 0; YInc < NumberRows; YInc++) { 1386 for (XInc = 0; XInc < NumberColumns; XInc++) { 1387 MoatMaskFlagField[YInc][XInc] = LabelSetArray[MoatMaskFlagField[YInc][XInc]]; 1388 } 1389 } 1390 1391 /* count up the objects in the image */ 1392 for (IncVal = 0; IncVal <= TableElements; IncVal++) { 1393 LabelSetArray[IncVal] = 0; 1394 } 1395 1396 for (YInc = 0; YInc < NumberRows; YInc++) { 1397 for (XInc = 0; XInc < NumberColumns; XInc++) { 1398 LabelSetArray[MoatMaskFlagField[YInc][XInc]]++; 1399 } 1400 } 1401 1402 /* number the objects from 1 through n objects */ 1403 int NumberObjects = 0; 1404 LabelSetArray[0] = 0; 1405 for (IncVal = 1; IncVal <= TableElements; IncVal++) { 1406 if (LabelSetArray[IncVal] > 0) { 1407 LabelSetArray[IncVal] = ++NumberObjects; 1408 } 1409 } 1410 1411 /* run through the look-up table again */ 1412 for (YInc = 0; YInc < NumberRows; YInc++) { 1413 for (XInc = 0; XInc < NumberColumns; XInc++) { 1414 MoatMaskFlagField[YInc][XInc] = LabelSetArray[MoatMaskFlagField[YInc][XInc]]; 1415 } 1416 } 1417 1418 return NumberObjects; 1419 1420 } 1421 1422 private static int Find(int InputArray[], int InputValue) { 1423 int IncVal = InputValue; 1424 1425 while (InputArray[IncVal] != IncVal) { 1426 IncVal = InputArray[IncVal]; 1427 } 1428 1429 return IncVal; 1430 } 1431 1432 /** 1433 * This routine will determine the confidence scores for the spiral fitting 1434 * and ring fitting routines and calculate the best possible position for 1435 * the storm center based upon a combination of the two methods, if 1436 * available. 1437 * 1438 * If the ring fitting routine does not determine a good candidate position, 1439 * the spiral fitting routine will be used alone. If the spiral fitting 1440 * routine candidate point is not "good", the forecast point will be 1441 * selected. 1442 * 1443 * @param FirstGuessLatitude 1444 * First Guess latitude. 1445 * @param FirstGuessLongitude 1446 * First Guess longitude. 1447 * @param SpiralCenterLatitude 1448 * Spiral Analysis latitude at max location. 1449 * @param SpiralCenterLongitude 1450 * Spiral Analysis longitude at max location. 1451 * @param SpiralCenterScoreValue 1452 * Spiral Analysis Score value. 1453 * @param RingFitLatitude 1454 * Ring Analysis latitude at max score location. 1455 * @param RingFitLongitude 1456 * Ring Analysis longitude at max score location. 1457 * @param RingFitScoreValue 1458 * Ring Analysis Score value. 1459 * 1460 * @return Array of four double values. The values represent: latitude of 1461 * final selected location, longitude of final selected location, 1462 * confidence score of final selected location, and the 1463 * {@literal "method"} used to determine the final selected 1464 * location. Possible values for the method: 1 for first guess, 2 1465 * for enhanced spiral analysis, and 5 for combo ring/spiral 1466 * analysis. 1467 */ 1468 private static double[] CalcScores(double FirstGuessLatitude, double FirstGuessLongitude, 1469 double SpiralCenterLatitude, double SpiralCenterLongitude, 1470 double SpiralCenterScoreValue, double RingFitLatitude, double RingFitLongitude, 1471 double RingFitScoreValue) { 1472 int YInc; 1473 int FinalLocationSelectionMethodReturn = 0; 1474 int NumberOfSpirals = (int) SpiralCenterAnalysisField[0][0] + 1; 1475 1476 double[] DistancePenaltyArray = new double[NumberOfSpirals]; 1477 double[] InitialSpiralScoreArray = new double[NumberOfSpirals]; 1478 double[] DistanceFromSpiralCenterArray = new double[NumberOfSpirals]; 1479 double[] DistanceBonusArray = new double[NumberOfSpirals]; 1480 double[] EnhancedSpiralScoreArray = new double[NumberOfSpirals]; 1481 double[] FinalSpiralScoreArray = new double[NumberOfSpirals]; 1482 1483 double FinalLatitudeReturn = -99.99; 1484 double FinalLongitudeReturn = -999.99; 1485 double FinalScoreReturn = 0.0; 1486 double DistanceValue; 1487 double MaximumForecastErrorDegree = 1.0; /* 1488 * max dist between fcst and 1489 * final 1490 */ 1491 double ExpectedMaximumForecastErrorDegree = MaximumForecastErrorDegree; /* 1492 * expected 1493 * error 1494 */ 1495 1496 /* max displacement */ 1497 double MaximumAllowableDisplacement = ExpectedMaximumForecastErrorDegree * 1.15; 1498 1499 /* Spiral Center analysis weight */ 1500 double SPIRALWEIGHT = 10.0; 1501 1502 /* RF distance penalty */ 1503 double DISTPENALTYWEIGHT = (0.5 / ExpectedMaximumForecastErrorDegree); 1504 1505 /* Ring Fit bonus value */ 1506 double PROXIMITYBONUS = 4.5; 1507 1508 /* RF bonus value threshold dist deg */ 1509 double PROXIMITYTHRESH = 0.25; 1510 1511 /* combination score threshold value */ 1512 double COMBOSCORETHRESH = 15.0; 1513 1514 /* convert distance in km to degrees */ 1515 double KMperDegree = 111.0; 1516 1517 double SpiralCenterIndexMaximum = -999.99; 1518 double SpiralCenterMaximumLatitude = -99.99; 1519 double SpiralCenterMaximumLongitude = -999.99; 1520 double SpiralMaximumDistanceFromGuess = 999.99; 1521 double IntermediateRingScore = 0.0; 1522 double FinalSpiralScoreValue = 0.0; 1523 double MaximumSpiralScoreValue = -99.99; 1524 double MaximumSpiralScoreLatitude = -99.99; 1525 double MaximumSpiralScoreLongitude = -999.99; 1526 1527 /* Spiral Score Calculations */ 1528 double LocalValue[] = Functions.distance_angle(FirstGuessLatitude, FirstGuessLongitude, 1529 SpiralCenterLatitude, SpiralCenterLongitude, 1); 1530 DistanceValue = LocalValue[0]; 1531 double InitialSpiralScoreArrayScore = SpiralCenterScoreValue; 1532 1533 for (YInc = 1; YInc < NumberOfSpirals; YInc++) { 1534 double LocalValue1[] = Functions.distance_angle(FirstGuessLatitude, 1535 FirstGuessLongitude, SpiralCenterAnalysisField[YInc][1], 1536 SpiralCenterAnalysisField[YInc][2], 1); 1537 DistanceValue = LocalValue1[0]; 1538 DistancePenaltyArray[YInc] = -DISTPENALTYWEIGHT * (DistanceValue / KMperDegree); 1539 InitialSpiralScoreArray[YInc] = SPIRALWEIGHT 1540 * (SpiralCenterAnalysisField[YInc][0] - InitialSpiralScoreArrayScore); 1541 double LocalValue2[] = Functions.distance_angle(SpiralCenterLatitude, 1542 SpiralCenterLongitude, SpiralCenterAnalysisField[YInc][1], 1543 SpiralCenterAnalysisField[YInc][2], 1); 1544 DistanceValue = LocalValue2[0]; 1545 DistanceFromSpiralCenterArray[YInc] = DistanceValue / KMperDegree; 1546 if (DistanceFromSpiralCenterArray[YInc] <= PROXIMITYTHRESH) { 1547 DistanceBonusArray[YInc] = PROXIMITYBONUS; 1548 } else { 1549 DistanceBonusArray[YInc] = 0.0; 1550 } 1551 EnhancedSpiralScoreArray[YInc] = InitialSpiralScoreArray[YInc] 1552 + DistancePenaltyArray[YInc]; 1553 /* 1554 * System.out.printf( 1555 * "SpiralCenterAnalysisField : YInc: %d Lat: %f Lon: %f Value: %f " 1556 * ,YInc,SpiralCenterAnalysisField[YInc][1], 1557 * SpiralCenterAnalysisField 1558 * [YInc][2],SpiralCenterAnalysisField[YInc][0]); 1559 */ 1560 /* 1561 * System.out.printf( 1562 * " distPentaly=%f DistanceFromSpiralCenterArray=%f DistanceBonusArray=%f max=%f\n" 1563 * , DistancePenaltyArray[YInc],DistanceFromSpiralCenterArray[YInc], 1564 * DistanceBonusArray[YInc],SpiralCenterIndexMaximum); 1565 */ 1566 if (EnhancedSpiralScoreArray[YInc] > SpiralCenterIndexMaximum) { 1567 SpiralCenterIndexMaximum = EnhancedSpiralScoreArray[YInc]; 1568 SpiralCenterMaximumLatitude = SpiralCenterAnalysisField[YInc][1]; 1569 SpiralCenterMaximumLongitude = SpiralCenterAnalysisField[YInc][2]; 1570 } 1571 FinalSpiralScoreArray[YInc] = InitialSpiralScoreArray[YInc] 1572 + DistancePenaltyArray[YInc] + DistanceBonusArray[YInc]; 1573 } 1574 /* 1575 * System.out.printf( 1576 * "FirstGuessLatitude=%f FirstGuessLongitude=%f SpiralCenterMaximumLatitude=%f SpiralCenterMaximumLongitude=%f\n" 1577 * , FirstGuessLatitude,FirstGuessLongitude,SpiralCenterMaximumLatitude, 1578 * SpiralCenterMaximumLongitude); 1579 */ 1580 double LocalValue3[] = Functions.distance_angle(FirstGuessLatitude, FirstGuessLongitude, 1581 SpiralCenterMaximumLatitude, SpiralCenterMaximumLongitude, 1); 1582 DistanceValue = LocalValue3[0]; 1583 SpiralMaximumDistanceFromGuess = DistanceValue / KMperDegree; 1584 /* 1585 * System.out.printf( 1586 * "SpiralMaximumDistanceFromGuess=%f MaximumAllowableDisplacement=%f\n" 1587 * , SpiralMaximumDistanceFromGuess,MaximumAllowableDisplacement); 1588 */ 1589 if (SpiralMaximumDistanceFromGuess <= MaximumAllowableDisplacement) { 1590 /* Ring Score Calculations */ 1591 double LocalValue4[] = Functions.distance_angle(FirstGuessLatitude, 1592 FirstGuessLongitude, RingFitLatitude, RingFitLongitude, 1); 1593 DistanceValue = LocalValue4[0]; 1594 for (YInc = 1; YInc < NumberOfSpirals; YInc++) { 1595 double[] RingScoreReturn = FindRingScore(SpiralCenterAnalysisField[YInc][1], 1596 SpiralCenterAnalysisField[YInc][2], RingScoreAnalysisField); 1597 int RetErr = (int) RingScoreReturn[0]; 1598 IntermediateRingScore = RingScoreReturn[1]; 1599 if (RetErr == 1) { 1600 FinalSpiralScoreValue = FinalSpiralScoreArray[YInc] + IntermediateRingScore; 1601 /* 1602 * System.out.printf( 1603 * " FOUND NumberOfSpirals=%d lat=%f lon=%f ringScore=%f FinalSpiralScoreValue=%f MaximumSpiralScoreValue=%f\n" 1604 * , YInc,SpiralCenterAnalysisField[YInc][1], 1605 * SpiralCenterAnalysisField[YInc][2], 1606 * IntermediateRingScore, 1607 * FinalSpiralScoreValue,MaximumSpiralScoreValue); 1608 */ 1609 if (FinalSpiralScoreValue > MaximumSpiralScoreValue) { 1610 MaximumSpiralScoreValue = FinalSpiralScoreValue; 1611 MaximumSpiralScoreLatitude = SpiralCenterAnalysisField[YInc][1]; 1612 MaximumSpiralScoreLongitude = SpiralCenterAnalysisField[YInc][2]; 1613 } 1614 } 1615 } 1616 /* 1617 * System.out.printf( 1618 * "MaximumSpiralScoreValue=%f RingPart=%f SpiralCenterIndexMaximum=%f\n" 1619 * , MaximumSpiralScoreValue,IntermediateRingScore, 1620 * SpiralCenterIndexMaximum); 1621 */ 1622 if (MaximumSpiralScoreValue >= COMBOSCORETHRESH) { 1623 /* use Combo Method */ 1624 FinalScoreReturn = MaximumSpiralScoreValue; 1625 FinalLatitudeReturn = MaximumSpiralScoreLatitude; 1626 FinalLongitudeReturn = MaximumSpiralScoreLongitude; 1627 FinalLocationSelectionMethodReturn = 5; 1628 } else { 1629 /* use ESP method */ 1630 FinalScoreReturn = 1.0 + SpiralCenterIndexMaximum; 1631 FinalLatitudeReturn = SpiralCenterMaximumLatitude; 1632 FinalLongitudeReturn = SpiralCenterMaximumLongitude; 1633 FinalLocationSelectionMethodReturn = 4; 1634 } 1635 } else { 1636 /* use Forecast Position */ 1637 FinalScoreReturn = 0.0; 1638 FinalLatitudeReturn = FirstGuessLatitude; 1639 FinalLongitudeReturn = FirstGuessLongitude; 1640 FinalLocationSelectionMethodReturn = 1; 1641 } 1642 1643 return new double[] { FinalLatitudeReturn, FinalLongitudeReturn, FinalScoreReturn, 1644 (double) FinalLocationSelectionMethodReturn }; 1645 } 1646 1647 /** 1648 * Find Ring score at selected location (spiral analysis location) 1649 * 1650 * @param FirstGuessLatitude 1651 * Latitude of search location. 1652 * @param FirstGuessLongitude 1653 * Longitude of search location. 1654 * @param RingScoreAnalysisField 1655 * - Array/Grid of Ring Analysis scores. 1656 * 1657 * @return Array of two doubles. The first value will be either -1 (if 1658 * nothing was found) or 1 (if found). The second value is the value 1659 * at search location in ring analysis grid (if the first value is 1660 * 1). 1661 */ 1662 private static double[] FindRingScore(double FirstGuessLatitude, double FirstGuessLongitude, 1663 double RingScoreAnalysisField[][]) { 1664 int YInc = 1; 1665 int Ret_ID = -1; 1666 double MaxRingDistance = RingScoreAnalysisField[0][0]; 1667 double RingFixScoreReturn = -99.9; 1668 1669 double LatitudeIncrement = Math.abs(IRData_Remap_Latitude[0][0] 1670 - IRData_Remap_Latitude[1][0]) / 2.0; 1671 double LongitudeIncrement = Math.abs(IRData_Remap_Longitude[0][1] 1672 - IRData_Remap_Longitude[0][0]) / 2.0; 1673 while (YInc <= MaxRingDistance) { 1674 if ((Math.abs(RingScoreAnalysisField[YInc][1] - FirstGuessLatitude) <= LatitudeIncrement) 1675 && (Math.abs(RingScoreAnalysisField[YInc][2] - FirstGuessLongitude) <= LongitudeIncrement)) { 1676 if (RingScoreAnalysisField[YInc][0] > RingFixScoreReturn) { 1677 RingFixScoreReturn = RingScoreAnalysisField[YInc][0]; 1678 } 1679 Ret_ID = 1; 1680 } 1681 YInc++; 1682 } 1683 1684 return new double[] { (double) Ret_ID, RingFixScoreReturn }; 1685 } 1686 1687 /** 1688 * Determine method location scheme to use by examining various 1689 * empirically-defined confidence factors. 1690 * 1691 * Confidence factors will be derived, with the "most confident" value used 1692 * as the final automatically determined storm position. 1693 * 1694 * @param ForecastLatitude 1695 * NHC/JTWC interpolated latitude position. 1696 * 1697 * @param ForecastLongitude 1698 * NHC/JTWC interpolated longitude position. 1699 * 1700 * @param RingSpiralLatitude 1701 * Ring/Spiral Analysis latitude position. 1702 * 1703 * @param RingSpiralLongitude 1704 * Ring/Spiral Analysis longitude position. 1705 * 1706 * @param RingSpiralScore 1707 * Ring/Spiral Analysis confidence factor score. 1708 * 1709 * @param RingSpiralSelectionIDValue 1710 * Ring/Spiral Analysis position derivation method. 1711 * 1712 * @return Array of three doubles. First value is latitude to be used, 1713 * second value is longitude to be used, and the third value is the 1714 * method used to determine storm position values. 1715 */ 1716 private static double[] PickFinalLocation(int InputPositioningID, double ForecastLatitude, 1717 double ForecastLongitude, double RingSpiralLatitude, double RingSpiralLongitude, 1718 double RingSpiralScore, int RingSpiralSelectionIDValue) { 1719 1720 int PositioningMethodID = 0; 1721 int HistoryRecEyeScene; 1722 int HistoryRecCloudScene; 1723 double FinalLatitude = -99.99; 1724 double FinalLongitude = -99.99; 1725 double FinalScoreValue = 0.0; 1726 double HistoryRecFinalTno = 0.0; 1727 double MaximumHistoryRecCI = 0.0; 1728 double HistoryRecRawTno = 0.0; 1729 double HistoryRecCI = 0.0; 1730 boolean ForceAutoFixUseTF_forTesting = false; 1731 boolean FoundEyeSceneTF = false; 1732 1733 int CurDate = History.IRCurrentRecord.date; 1734 int CurTime = History.IRCurrentRecord.time; 1735 int CurCloudScene = History.IRCurrentRecord.cloudscene; 1736 int CurEyeScene = History.IRCurrentRecord.eyescene; 1737 double CurrentTime = Functions.calctime(CurDate, CurTime); 1738 1739 int NumRecsHistory = History.HistoryNumberOfRecords(); 1740 double InitStrengthValue = Env.InitRawTValue; 1741 boolean LandFlagTF = Env.LandFlagTF; 1742 1743 int EyeSceneCount = 0; 1744 1745 if ((Main.HistoryFileName != null) || (ForceAutoFixUseTF_forTesting)) { 1746 HistoryRecFinalTno = 9.0; 1747 MaximumHistoryRecCI = 9.0; 1748 HistoryRecRawTno = 9.0; 1749 } else if (NumRecsHistory == 0) { 1750 HistoryRecFinalTno = InitStrengthValue; 1751 MaximumHistoryRecCI = InitStrengthValue; 1752 HistoryRecRawTno = InitStrengthValue; 1753 } else { 1754 EyeSceneCount = 0; 1755 HistoryRecFinalTno = History.IRCurrentRecord.Traw; 1756 HistoryRecRawTno = History.IRCurrentRecord.Traw; 1757 MaximumHistoryRecCI = History.IRCurrentRecord.Traw; 1758 int XInc = 0; 1759 while (XInc < NumRecsHistory) { 1760 int RecDate = History.HistoryFile[XInc].date; 1761 int RecTime = History.HistoryFile[XInc].time; 1762 int RecLand = History.HistoryFile[XInc].land; 1763 double RecTnoRaw = History.HistoryFile[XInc].Traw; 1764 double HistoryRecTime = Functions.calctime(RecDate, RecTime); 1765 boolean LandCheckTF = true; 1766 if (((LandFlagTF) && (RecLand == 1)) || (RecTnoRaw < 1.0)) { 1767 LandCheckTF = false; 1768 } 1769 if ((HistoryRecTime < CurrentTime) && (LandCheckTF)) { 1770 HistoryRecCI = History.HistoryFile[XInc].CI; 1771 HistoryRecFinalTno = History.HistoryFile[XInc].Tfinal; 1772 HistoryRecRawTno = History.HistoryFile[XInc].Traw; 1773 HistoryRecEyeScene = History.HistoryFile[XInc].eyescene; 1774 HistoryRecCloudScene = History.HistoryFile[XInc].cloudscene; 1775 if (HistoryRecCI > MaximumHistoryRecCI) { 1776 MaximumHistoryRecCI = HistoryRecCI; 1777 } 1778 if ((HistoryRecEyeScene < 3) 1779 || ((HistoryRecCloudScene == 1) && (HistoryRecEyeScene == 3))) { 1780 EyeSceneCount = EyeSceneCount + 1; 1781 /* checking for eye or embedded center scene types */ 1782 if (EyeSceneCount == 3) { 1783 FoundEyeSceneTF = true; 1784 } 1785 } else { 1786 EyeSceneCount = 0; 1787 } 1788 } 1789 XInc++; 1790 } 1791 if (((CurEyeScene < 3) || ((CurCloudScene == 1) && (CurEyeScene == 3))) 1792 && (EyeSceneCount == 2)) { 1793 FoundEyeSceneTF = true; 1794 } 1795 } 1796 1797 /* System.out.printf("%d %d : ",CurDate,CurTime); */ 1798 /* 1799 * System.out.printf("RingSpiralScore=%f HistoryRecFinalTno=%f\n", 1800 * RingSpiralScore,HistoryRecFinalTno); 1801 */ 1802 /* 1803 * System.out.printf("HistoryRecRawTno=%f MaximumHistoryRecCI=%f\n", 1804 * HistoryRecRawTno,MaximumHistoryRecCI); 1805 */ 1806 1807 /* 1808 * check score for developing systems (MaximumHistoryRecCI<5.0) starting 1809 * at 3.0 or check score for weakeining systems 1810 * (MaximumHistoryRecCI>=5.0) only above 3.5 1811 */ 1812 if (((HistoryRecRawTno >= 3.0) && (MaximumHistoryRecCI < 5.0)) 1813 || ((HistoryRecRawTno >= 3.5) && (MaximumHistoryRecCI >= 5.0))) { 1814 1815 if ((HistoryRecFinalTno <= 4.5) && (RingSpiralScore < 1.0) && (!FoundEyeSceneTF)) 1816 RingSpiralScore = -99.99; 1817 1818 /* System.out.printf(" FINALRingSpiralScore=%f ",RingSpiralScore); */ 1819 1820 if (RingSpiralScore > 0.0) { 1821 /* use Spiral/Ring methodology for center point */ 1822 FinalLatitude = RingSpiralLatitude; 1823 FinalLongitude = RingSpiralLongitude; 1824 FinalScoreValue = RingSpiralScore; 1825 PositioningMethodID = RingSpiralSelectionIDValue; 1826 } else { 1827 /* CDO... can't find anything to focus on */ 1828 FinalLatitude = ForecastLatitude; 1829 FinalLongitude = ForecastLongitude; 1830 FinalScoreValue = 0.0; 1831 PositioningMethodID = InputPositioningID; 1832 } 1833 } else { 1834 /* 1835 * current Tfinal is less than 3.5 or current scene is not an eye or 1836 * embedded center WILL USE FORECAST POSITION FOR AODT ANALYSIS 1837 */ 1838 FinalLatitude = ForecastLatitude; 1839 FinalLongitude = ForecastLongitude; 1840 FinalScoreValue = 0.0; 1841 PositioningMethodID = InputPositioningID; 1842 } 1843 1844 return new double[] { FinalLatitude, FinalLongitude, FinalScoreValue, 1845 (double) PositioningMethodID }; 1846 1847 } 1848 1849 /** 1850 * Calls routines to setup transformation, transform, data move. 1851 * 1852 * Input data provided with global variable arrays containing original and 1853 * transformed arrays. 1854 */ 1855 private static void RemapData() { 1856 /* 1857 * The following routines were originally developed by Dave Santek of 1858 * UW/SSEC and were added to the ADT under permission. If executed, an 1859 * array of latitude and longitude position arrays will be remapped to a 1860 * rectilinear projection for Tony Wimmers routines 1861 */ 1862 1863 int NumberOfCorners = 0; 1864 int LineSplineValue = 3; 1865 int ElementSplineValue = LineSplineValue; 1866 1867 tiff_vars.in_elems = Data.IRData_NumberColumns; 1868 tiff_vars.in_lines = Data.IRData_NumberRows; 1869 1870 /* 1871 * System.out.printf("elems=%d lines=%d\n", 1872 * tiff_vars.in_elems,tiff_vars.in_lines); 1873 */ 1874 1875 /* Uinit( ); */ 1876 /* 1877 * dis_vars.xrectl = (double)tiff_vars.in_lines; dis_vars.xrecte = 1878 * (double)tiff_vars.in_elems; 1879 * System.out.printf("xrectl=%f xrecte=%f\n", 1880 * dis_vars.xrectl,dis_vars.xrecte); 1881 */ 1882 1883 DetermineDest(); 1884 /* System.out.printf("after determineDest\n"); */ 1885 1886 NumberOfCorners = Init(LineSplineValue, ElementSplineValue); 1887 1888 System.out.printf("number of corners=%d\n", NumberOfCorners); 1889 Corner(NumberOfCorners, LineSplineValue, ElementSplineValue); 1890 /* System.out.printf("after corners\n"); */ 1891 1892 if ((ElementSplineValue > 1) || (LineSplineValue > 1)) { 1893 DoMap(NumberOfCorners, LineSplineValue, ElementSplineValue); 1894 } 1895 1896 } 1897 1898 /** 1899 * Interpolate between two arrays of different size. 1900 */ 1901 private static void DetermineDest() { 1902 int XInc, YInc; 1903 int XSizeMax = Data.IRData_NumberColumns - 1; 1904 int YSizeMax = Data.IRData_NumberRows - 1; 1905 1906 double NWCornerLatitude = Data.IRData_Latitude[0][0]; 1907 double NWCornerLongitude = Data.IRData_Longitude[0][0]; 1908 double NECornerLatitude = Data.IRData_Latitude[0][XSizeMax]; 1909 double NECornerLongitude = Data.IRData_Longitude[0][XSizeMax]; 1910 double SWCornerLatitude = Data.IRData_Latitude[YSizeMax][0]; 1911 double SWCornerLongitude = Data.IRData_Longitude[YSizeMax][0]; 1912 double SECornerLatitude = Data.IRData_Latitude[YSizeMax][XSizeMax]; 1913 double SECornerLongitude = Data.IRData_Longitude[YSizeMax][XSizeMax]; 1914 1915 /* crosses dateline check */ 1916 if ((NWCornerLongitude < NECornerLongitude) || (SWCornerLongitude < SECornerLongitude)) { 1917 NWCornerLongitude = NWCornerLongitude + 360.0; 1918 if (SWCornerLongitude < SECornerLongitude) { 1919 SWCornerLongitude = SWCornerLongitude + 360.0; 1920 } 1921 /* System.out.printf("DATELINE CROSS\n"); */ 1922 for (XInc = 0; XInc < XSizeMax; XInc++) { 1923 for (YInc = 0; YInc < YSizeMax; YInc++) { 1924 double DataValue = Data.IRData_Longitude[YInc][XInc]; 1925 if (DataValue < 0.0) { 1926 Data.IRData_Longitude[YInc][XInc] = (float) (DataValue + 360.0); 1927 } 1928 } 1929 } 1930 NWCornerLatitude = Data.IRData_Latitude[0][0]; 1931 NWCornerLongitude = Data.IRData_Longitude[0][0]; 1932 NECornerLatitude = Data.IRData_Latitude[0][XSizeMax]; 1933 NECornerLongitude = Data.IRData_Longitude[0][XSizeMax]; 1934 SWCornerLatitude = Data.IRData_Latitude[YSizeMax][0]; 1935 SWCornerLongitude = Data.IRData_Longitude[YSizeMax][0]; 1936 SECornerLatitude = Data.IRData_Latitude[YSizeMax][XSizeMax]; 1937 SECornerLongitude = Data.IRData_Longitude[YSizeMax][XSizeMax]; 1938 } 1939 1940 double MaximumLatitudeValue = Math.min(NWCornerLatitude, NECornerLatitude); 1941 double MinimumLatitudeValue = Math.max(SWCornerLatitude, SECornerLatitude); 1942 double MaximumLongitudeValue = Math.max(NWCornerLongitude, SWCornerLongitude); 1943 double MinimumLongitudeValue = Math.min(NECornerLongitude, SECornerLongitude); 1944 1945 double LatitudeIncrement = (MaximumLatitudeValue - MinimumLatitudeValue) 1946 / (double) Data.IRData_NumberColumns; 1947 double LongitudeIncrement = (MaximumLongitudeValue - MinimumLongitudeValue) 1948 / (double) Data.IRData_NumberRows; 1949 double MaximumIncrementValue = Math.max(LatitudeIncrement, LongitudeIncrement); 1950 System.out.printf("REMAPPING INFO\n"); 1951 System.out.printf("Source Array Bounds\n"); 1952 System.out.printf(" NW Corner : %7.2f/%7.2f\n", NWCornerLatitude, NWCornerLongitude); 1953 System.out.printf(" NE Corner : %7.2f/%7.2f\n", NECornerLatitude, NECornerLongitude); 1954 System.out.printf(" SW Corner : %7.2f/%7.2f\n", SWCornerLatitude, SWCornerLongitude); 1955 System.out.printf(" SE Corner : %7.2f/%7.2f\n", SECornerLatitude, SECornerLongitude); 1956 System.out.printf("Destination Array Bounds\n"); 1957 System.out.printf(" Max Lat/Lon: %7.2f/%7.2f\n", MaximumLatitudeValue, 1958 MaximumLongitudeValue); 1959 System.out.printf(" Min Lat/Lon: %7.2f/%7.2f\n", MinimumLatitudeValue, 1960 MinimumLongitudeValue); 1961 System.out.printf(" Inc Lat/Lon: %5.3f/ %5.3f\n", MaximumIncrementValue, 1962 MaximumIncrementValue); 1963 1964 tiff_vars.out_lines = (int) ((MaximumLatitudeValue - MinimumLatitudeValue) / MaximumIncrementValue); 1965 tiff_vars.out_elems = (int) ((MaximumLongitudeValue - MinimumLongitudeValue) / MaximumIncrementValue); 1966 for (YInc = 0; YInc < tiff_vars.out_lines; YInc++) { 1967 double LatitudeValue = MaximumLatitudeValue - (YInc * MaximumIncrementValue); 1968 for (XInc = 0; XInc < tiff_vars.out_elems; XInc++) { 1969 double LongitudeValue = MaximumLongitudeValue - (XInc * MaximumIncrementValue); 1970 IRData_Remap_Latitude[YInc][XInc] = LatitudeValue; 1971 IRData_Remap_Longitude[YInc][XInc] = LongitudeValue; 1972 } 1973 } 1974 1975 IRData_Remap_NumberColumns = tiff_vars.out_elems; 1976 IRData_Remap_NumberRows = tiff_vars.out_lines; 1977 } 1978 1979 /** 1980 * Compute number of corners for transformation and block sizes. 1981 * 1982 * @param LineSplineInput 1983 * Spline function for line values. 1984 * @param ElementSplineInput 1985 * Spline function for element values. 1986 * 1987 * @return Total number of corners to interpolate. 1988 */ 1989 private static int Init(int LineSplineInput, int ElementSplineInput) { 1990 int NumberOfCorners = 0; 1991 1992 remap_vars.nspl = (tiff_vars.out_elems + ElementSplineInput - 1) / ElementSplineInput; 1993 remap_vars.nspe = (tiff_vars.out_lines + LineSplineInput - 1) / LineSplineInput; 1994 1995 remap_vars.ncl = remap_vars.nspl + 1; 1996 remap_vars.nce = remap_vars.nspe + 1; 1997 1998 if (((tiff_vars.out_elems + ElementSplineInput - 1) % ElementSplineInput) == 0) { 1999 remap_vars.ncl = remap_vars.nspl; 2000 } 2001 if (((tiff_vars.out_lines + LineSplineInput - 1) % LineSplineInput) == 0) { 2002 remap_vars.nce = remap_vars.nspe; 2003 } 2004 2005 NumberOfCorners = remap_vars.ncl * remap_vars.nce; 2006 2007 remap_vars.in_bfw = Math.max(MINBFW, MINBLKSIZ * tiff_vars.in_elems); 2008 remap_vars.out_bfw = Math.max(MINBFW, Math.max(LineSplineInput, MINBLKSIZ) 2009 * tiff_vars.out_elems); 2010 2011 remap_vars.slb = remap_vars.in_bfw / tiff_vars.in_elems; 2012 remap_vars.dlb = ((remap_vars.out_bfw / tiff_vars.out_elems) / LineSplineInput) 2013 * LineSplineInput; 2014 2015 return NumberOfCorners; 2016 } 2017 2018 /** 2019 * Compute transformations at corners. 2020 * 2021 * Operates on the {@link #LineCoordinateArray} and 2022 * {@link #ElementCoordinateArray}. 2023 * 2024 * @param NumberOfCornersInput 2025 * Total number of corners to interpolate. 2026 * @param LineSplineInput 2027 * Spline function for line values. 2028 * @param ElementSplineInput 2029 * Spline function for element values. 2030 */ 2031 private static void Corner(int NumberOfCornersInput, int LineSplineInput, int ElementSplineInput) { 2032 int XInc; 2033 int YInc; 2034 int ArrayInc; 2035 2036 /* initialize array of corners */ 2037 for (ArrayInc = 0; ArrayInc < NumberOfCornersInput; ArrayInc++) { 2038 LineCoordinateArray[ArrayInc] = -99.9; 2039 ElementCoordinateArray[ArrayInc] = -99.9; 2040 } 2041 2042 /* loop through destination file and record source coords */ 2043 ArrayInc = -1; 2044 int NumberLines = tiff_vars.out_lines + LineSplineInput - 1; 2045 int NumberElements = tiff_vars.out_elems + ElementSplineInput - 1; 2046 2047 for (YInc = 0; YInc < NumberLines; YInc = YInc + LineSplineInput) { 2048 int LineValue = YInc; 2049 for (XInc = 0; XInc < NumberElements; XInc = XInc + ElementSplineInput) { 2050 /* System.out.printf("yinc=%d xinc=%d... \n",YInc,XInc); */ 2051 int ElementValue = XInc; 2052 int[] UMapReturn = UMap(LineValue, ElementValue); 2053 int RetErr = UMapReturn[0]; 2054 int SplineLineValue = UMapReturn[1]; 2055 int SplineElementValue = UMapReturn[2]; 2056 /* 2057 * System.out.printf("spline line=%d element=%d \n ",SplineLineValue 2058 * ,SplineElementValue); 2059 */ 2060 if ((ElementSplineInput == 1) && (LineSplineInput == 1)) { 2061 IRData_Remap_Temperature[LineValue][ElementValue] = Data.IRData_Temperature[SplineLineValue][SplineElementValue]; 2062 } else { 2063 ++ArrayInc; 2064 if (RetErr == 0) { 2065 LineCoordinateArray[ArrayInc] = SplineLineValue; 2066 ElementCoordinateArray[ArrayInc] = SplineElementValue; 2067 } 2068 } 2069 } 2070 } 2071 2072 } 2073 2074 /** 2075 * Provide coordinates between original point and transformed point. 2076 * 2077 * @param LineValueInput 2078 * Original line coordinate. 2079 * @param ElementValueInput 2080 * Ooriginal element coordinate. 2081 * 2082 * @return Array containing three values: possible error code, interpolated 2083 * line coordinate, and interpolated element coordinate. 2084 */ 2085 private static int[] UMap(int LineValueInput, int ElementValueInput) { 2086 2087 /* dest array line position value */ 2088 double DestinationLatitude; 2089 2090 /* dest array element position value */ 2091 double DestinationLongitude; 2092 2093 /* 2094 * Convert destination LineValueInput, ElementValueInput to source 2095 * coords LineValue_Return, ElementValue_Return 2096 */ 2097 LineValueInput = Math.min(LineValueInput, tiff_vars.out_lines - 1); 2098 ElementValueInput = Math.min(ElementValueInput, tiff_vars.out_elems - 1); 2099 DestinationLatitude = IRData_Remap_Latitude[LineValueInput][ElementValueInput]; 2100 DestinationLongitude = IRData_Remap_Longitude[LineValueInput][ElementValueInput]; 2101 2102 int[] FindPointReturn = FindPoint(DestinationLatitude, DestinationLongitude); 2103 int RetErr = FindPointReturn[0]; 2104 int LineValueReturn = FindPointReturn[1]; 2105 int ElementValueReturn = FindPointReturn[2]; 2106 2107 return new int[] { RetErr, LineValueReturn, ElementValueReturn }; 2108 } 2109 2110 /** 2111 * Find specific lat/lon location in array and return index values. 2112 * 2113 * @param latitude 2114 * Latitude value. 2115 * @param longitude 2116 * Longitude value. 2117 * 2118 * @return Array of three values. The first value is the status (-1 for 2119 * error, 0 for ok), the second value is array line value of lat/lon 2120 * input, and the third value is array element value of lat/lon 2121 * input. 2122 */ 2123 private static int[] FindPoint(double latitude, double longitude) { 2124 int RetErr; 2125 int XInc; 2126 int IndexValue; 2127 int YLineValueReturn; 2128 int XElementValueReturn; 2129 2130 double[] CornerLatitudeArray = new double[4]; 2131 double[] CornerLongitudeArray = new double[4]; 2132 double[] NSEWDistanceValuesArray = new double[4]; 2133 2134 /* found point logical */ 2135 boolean FoundPointTF = false; 2136 2137 /* out of bounds flag logical */ 2138 boolean OutOfBoundsTF = false; 2139 2140 /* found latitude value logical */ 2141 boolean FoundLatitudeTF = false; 2142 2143 /* found longitude value logical */ 2144 boolean FoundLongitudeTF = false; 2145 2146 int NumberElements = tiff_vars.in_elems; 2147 int NumberLines = tiff_vars.in_lines; 2148 int ElementValue = 0; 2149 int LineValue = 0; 2150 double PreviousDistance = 9999.9; 2151 2152 for (XInc = 0; XInc < 4; XInc++) { 2153 NSEWDistanceValuesArray[XInc] = 0.0; 2154 CornerLatitudeArray[XInc] = 0.0; 2155 CornerLongitudeArray[XInc] = 0.0; 2156 } 2157 while ((!FoundPointTF) && (!OutOfBoundsTF)) { 2158 CornerLatitudeArray[0] = Data.IRData_Latitude[LineValue][ElementValue]; 2159 CornerLongitudeArray[0] = Data.IRData_Longitude[LineValue][ElementValue]; 2160 CornerLatitudeArray[3] = Data.IRData_Latitude[LineValue + 1][ElementValue + 1]; 2161 CornerLongitudeArray[3] = Data.IRData_Longitude[LineValue + 1][ElementValue + 1]; 2162 /* 2163 * System.out.printf( 2164 * "x=%d y=%d : CornerLatitudeArray0=%f CornerLongitudeArray0=%f " 2165 * , " CornerLatitudeArray3=%f CornerLongitudeArray3=%f\n", 2166 * ElementValue,LineValue, 2167 * CornerLatitudeArray[0],CornerLongitudeArray[0], 2168 * CornerLatitudeArray[3],CornerLongitudeArray[3]); 2169 */ 2170 if ((longitude > CornerLongitudeArray[0]) || (longitude < CornerLongitudeArray[3])) { 2171 FoundLongitudeTF = false; 2172 if (longitude < CornerLongitudeArray[3]) { 2173 ElementValue++; 2174 } else { 2175 if (longitude > CornerLongitudeArray[0]) { 2176 ElementValue--; 2177 } 2178 } 2179 } else { 2180 FoundLongitudeTF = true; 2181 } 2182 if ((latitude > CornerLatitudeArray[0]) || (latitude < CornerLatitudeArray[3])) { 2183 FoundLatitudeTF = false; 2184 if (latitude < CornerLatitudeArray[3]) { 2185 LineValue++; 2186 } else { 2187 if (latitude > CornerLatitudeArray[0]) { 2188 LineValue--; 2189 } 2190 } 2191 } else { 2192 FoundLatitudeTF = true; 2193 } 2194 double LocalValue1[] = Functions.distance_angle(latitude, longitude, 2195 CornerLatitudeArray[0], CornerLongitudeArray[0], 1); 2196 double DistanceValue = LocalValue1[0]; 2197 2198 /* 2199 * * System.out.printf("distance : latitude=%f longitude=%f",* 2200 * " CornerLatitudeArray0=%f CornerLongitudeArray0=%f",* 2201 * " dist=%f angle=%f\n",latitude,longitude,* 2202 * CornerLatitudeArray[0],CornerLongitudeArray[0],* 2203 * DistanceValue,AngleValue); 2204 */ 2205 if (FoundLatitudeTF && FoundLongitudeTF) { 2206 FoundPointTF = true; 2207 } 2208 if (PreviousDistance <= DistanceValue) { 2209 FoundPointTF = true; 2210 } 2211 if ((ElementValue < 0) || (ElementValue > (NumberElements - 2))) { 2212 OutOfBoundsTF = true; 2213 } 2214 if ((LineValue < 0) || (LineValue > (NumberLines - 2))) { 2215 OutOfBoundsTF = true; 2216 } 2217 PreviousDistance = DistanceValue; 2218 } 2219 if (FoundPointTF) { 2220 CornerLatitudeArray[1] = Data.IRData_Latitude[LineValue][ElementValue + 1]; 2221 CornerLongitudeArray[1] = Data.IRData_Longitude[LineValue][ElementValue + 1]; 2222 CornerLatitudeArray[2] = Data.IRData_Latitude[LineValue + 1][ElementValue]; 2223 CornerLongitudeArray[2] = Data.IRData_Longitude[LineValue + 1][ElementValue]; 2224 2225 double LocalValue2[] = Functions.distance_angle(latitude, longitude, 2226 CornerLatitudeArray[0], CornerLongitudeArray[0], 1); 2227 NSEWDistanceValuesArray[0] = LocalValue2[0]; 2228 double LocalValue3[] = Functions.distance_angle(latitude, longitude, 2229 CornerLatitudeArray[1], CornerLongitudeArray[1], 1); 2230 NSEWDistanceValuesArray[1] = LocalValue3[0]; 2231 IndexValue = (NSEWDistanceValuesArray[0] < NSEWDistanceValuesArray[1]) ? 0 : 1; 2232 double LocalValue4[] = Functions.distance_angle(latitude, longitude, 2233 CornerLatitudeArray[2], CornerLongitudeArray[2], 1); 2234 NSEWDistanceValuesArray[2] = LocalValue4[0]; 2235 IndexValue = (NSEWDistanceValuesArray[IndexValue] < NSEWDistanceValuesArray[2]) ? IndexValue 2236 : 2; 2237 double LocalValue5[] = Functions.distance_angle(latitude, longitude, 2238 CornerLatitudeArray[3], CornerLongitudeArray[3], 1); 2239 NSEWDistanceValuesArray[3] = LocalValue5[0]; 2240 IndexValue = (NSEWDistanceValuesArray[IndexValue] < NSEWDistanceValuesArray[3]) ? IndexValue 2241 : 3; 2242 2243 XElementValueReturn = ((IndexValue == 0) || (IndexValue == 2)) ? ElementValue 2244 : ElementValue + 1; 2245 YLineValueReturn = ((IndexValue == 0) || (IndexValue == 1)) ? LineValue : LineValue + 1; 2246 RetErr = 0; 2247 } else { 2248 XElementValueReturn = -1; 2249 YLineValueReturn = -1; 2250 RetErr = -1; 2251 } 2252 2253 return new int[] { RetErr, YLineValueReturn, XElementValueReturn }; 2254 } 2255 2256 private static int DoMap(int NumberOfCornersInput, int LineSplineInput, int ElementSplineInput) { 2257 /* LineCoordsArrayInput = LineCoordinateArray */ 2258 /* ElementCoordsArrayInput = ElementCoordinateArray */ 2259 2260 /* line increment */ 2261 int[] LineIncArray1 = { -2, -2, 0, 2, 2, 2, 0, -2 }; 2262 2263 /* line increment */ 2264 int[] LineIncArray2 = { -1, -1, 0, 1, 1, 1, 0, -1 }; 2265 2266 /* ele increment */ 2267 int[] ElementIncArray1 = { 0, 2, 2, 2, 0, -2, -2, -2 }; 2268 2269 /* ele increment */ 2270 int[] ElementIncArray2 = { 0, 1, 1, 1, 0, -1, -1, -1 }; 2271 2272 int BufferSize = tiff_vars.in_lines * tiff_vars.in_elems; 2273 2274 double[] SourceArray = new double[BufferSize]; 2275 double[] InterpArray = new double[BufferSize]; 2276 double[] TempCharArray = new double[NumberOfCornersInput]; 2277 2278 int Ret_ID; 2279 int XInc, YInc, IncVal; 2280 int ArrayIndexValue; 2281 int ArrayPointValue; 2282 int SplinePixelValue; 2283 int SourceBlockValue; 2284 int SourceBlockInc; 2285 int SplineInc; 2286 int OffsetValue; 2287 int OffsetValue0; 2288 int OffsetValue1; 2289 int OffsetValue2; 2290 int OffsetValueL = 0; 2291 int OffsetValueE = 0; 2292 int CornerPointer; 2293 int AccumulatedLines; 2294 int FirstCornerPointer; 2295 int FirstCornerPointerHold; 2296 int LastCornerPointer; 2297 int ValX; 2298 int LineMinimumFinal; 2299 int LineMaximumFinal; 2300 int ElementMinimumFinal; 2301 int ElementMaximumFinal; 2302 int EdgeFixID; 2303 int SourceLine = 0; 2304 int SourceElement = 0; 2305 int SourceOffsetValue; 2306 int MaximumSourceLine; 2307 2308 double LineValueA; 2309 double LineValueB; 2310 double LineValueC; 2311 double ElementValueA; 2312 double ElementValueB; 2313 double ElementValueC; 2314 double LineValueACounter; 2315 double LineValueBCounter; 2316 double LineValueCCounter; 2317 double ElementValueACounter; 2318 double ElementValueBCounter; 2319 double ElementValueCCounter; 2320 double LineValueACounter0; 2321 double ElementValueACounter0; 2322 double LineULValue; 2323 double LineURValue; 2324 double LineLLValue; 2325 double LineLRValue; 2326 double LineMinimum; 2327 double LineMaximum; 2328 double ElementULValue; 2329 double ElementURValue; 2330 double ElementLLValue; 2331 double ElementLRValue; 2332 double ElementMinimum; 2333 double ElementMaximum; 2334 boolean ReadAllTF = true; 2335 boolean SKIP; 2336 boolean LABEL30; 2337 boolean LABEL38; 2338 2339 if ((SourceArray == null) || (InterpArray == null) || (TempCharArray == null)) { 2340 Ret_ID = -1; 2341 } else { 2342 SplinePixelValue = LineSplineInput * ElementSplineInput; 2343 2344 for (YInc = 0; YInc < tiff_vars.in_lines; YInc++) { 2345 for (XInc = 0; XInc < tiff_vars.in_elems; XInc++) { 2346 ArrayIndexValue = (YInc * tiff_vars.in_elems) + XInc; 2347 SourceArray[ArrayIndexValue] = Data.IRData_Temperature[YInc][XInc]; 2348 } 2349 } 2350 2351 /* 2352 * System.out.printf("remap nce=%d ncl=%d\n",remap_vars.nce,remap_vars 2353 * .ncl); 2354 */ 2355 for (YInc = 1; YInc < remap_vars.nce + 1; YInc++) { 2356 for (XInc = 1; XInc < remap_vars.ncl + 1; XInc++) { 2357 ArrayPointValue = IND(YInc, XInc); 2358 2359 if (LineCoordinateArray[ArrayPointValue - 1] == (double) -99.9) { 2360 double LineSum = 0.0; 2361 double ElementSum = 0.0; 2362 int PointCounter = 0; 2363 for (IncVal = 0; IncVal < 8; IncVal++) { 2364 SKIP = false; 2365 int YInc1 = YInc + LineIncArray1[IncVal]; 2366 int YInc2 = YInc + LineIncArray2[IncVal]; 2367 if ((YInc1 < 1) || (YInc2 < 1)) { 2368 SKIP = true; 2369 } 2370 if ((YInc1 > remap_vars.nce) || (YInc2 > remap_vars.nce)) { 2371 SKIP = true; 2372 } 2373 2374 int XInc1 = XInc + ElementIncArray1[IncVal]; 2375 int XInc2 = XInc + ElementIncArray2[IncVal]; 2376 2377 if ((XInc1 < 1) || (XInc2 < 1)) { 2378 SKIP = true; 2379 } 2380 if ((XInc1 > remap_vars.ncl) || (XInc2 > remap_vars.ncl)) { 2381 SKIP = true; 2382 } 2383 2384 int ValueIND1 = IND(YInc1, XInc1); 2385 int ValueIND2 = IND(YInc2, XInc2); 2386 2387 if (!SKIP) { 2388 if ((LineCoordinateArray[ValueIND1 - 1] == -99.9) 2389 || (LineCoordinateArray[ValueIND2 - 1] == -99.9)) { 2390 SKIP = true; 2391 } 2392 if (TempCharArray[ValueIND1 - 1] != 0) { 2393 SKIP = true; 2394 } 2395 if (TempCharArray[ValueIND2 - 1] != 0) { 2396 SKIP = true; 2397 } 2398 if (!SKIP) { 2399 PointCounter = PointCounter + 1; 2400 LineSum = LineSum 2401 + ((double) (2.0 * LineCoordinateArray[ValueIND2 - 1])) 2402 - LineCoordinateArray[ValueIND1 - 1]; 2403 ElementSum = ElementSum 2404 + ((double) 2.0 * ElementCoordinateArray[ValueIND2 - 1]) 2405 - ElementCoordinateArray[ValueIND1 - 1]; 2406 } /* SKIP:; */ 2407 } /* SKIP:; */ 2408 } 2409 2410 if (PointCounter > 0) { 2411 LineCoordinateArray[ArrayPointValue - 1] = LineSum / PointCounter; 2412 ElementCoordinateArray[ArrayPointValue - 1] = ElementSum / PointCounter; 2413 TempCharArray[ArrayPointValue - 1] = 1; 2414 } 2415 } 2416 } 2417 } 2418 2419 /* Loop through by destination blocks */ 2420 int BlockCounter = 0; 2421 2422 for (IncVal = 1; IncVal < tiff_vars.out_lines + 1; IncVal = IncVal + remap_vars.dlb) { 2423 /* Accumulated lines/block */ 2424 AccumulatedLines = BlockCounter * remap_vars.dlb; 2425 2426 /* Pointer to first corner of splines for this dest block */ 2427 FirstCornerPointer = (BlockCounter * remap_vars.ncl * remap_vars.dlb) 2428 / LineSplineInput; 2429 FirstCornerPointerHold = FirstCornerPointer; 2430 2431 /* Pointer to last corner for this dest block */ 2432 LastCornerPointer = (((BlockCounter + 1) * remap_vars.ncl * remap_vars.dlb) / LineSplineInput) - 1; 2433 LastCornerPointer = Math.min(LastCornerPointer, NumberOfCornersInput 2434 - remap_vars.ncl); 2435 2436 /* For each destination block loop through entire source */ 2437 for (SourceBlockInc = 1; SourceBlockInc < tiff_vars.in_lines + 1; SourceBlockInc = SourceBlockInc 2438 + remap_vars.slb) { 2439 MaximumSourceLine = Math.min(tiff_vars.in_lines, (SourceBlockInc 2440 + remap_vars.slb - 1)); 2441 ReadAllTF = false; 2442 2443 /* Loop through splines and move any data */ 2444 2445 FirstCornerPointer = FirstCornerPointerHold; 2446 SourceBlockValue = 0; 2447 while (FirstCornerPointer < LastCornerPointer) { 2448 for (SplineInc = 1; SplineInc < remap_vars.nspl + 1; SplineInc++) { 2449 LABEL30 = false; 2450 OffsetValue0 = (SourceBlockValue / remap_vars.nspl) * LineSplineInput 2451 * tiff_vars.out_elems; 2452 OffsetValue1 = (SourceBlockValue % remap_vars.nspl) 2453 * ElementSplineInput; 2454 OffsetValue2 = OffsetValue1 + OffsetValue0 + 1; 2455 CornerPointer = FirstCornerPointer + SplineInc - 1; 2456 2457 /* 2458 * Get 4 corners in line space and check for out of 2459 * bounds 2460 */ 2461 2462 ValX = remap_vars.ncl; 2463 LineULValue = LineCoordinateArray[CornerPointer]; 2464 LineURValue = LineCoordinateArray[CornerPointer + 1]; 2465 LineLLValue = LineCoordinateArray[CornerPointer + ValX]; 2466 if ((CornerPointer + 1 + ValX) < NumberOfCornersInput) { 2467 LineLRValue = LineCoordinateArray[CornerPointer + 1 + ValX]; 2468 } else { 2469 LineLRValue = LineCoordinateArray[CornerPointer + ValX]; 2470 } 2471 LineMinimum = Math.min(LineULValue, LineURValue); 2472 LineMinimum = Math.min(LineMinimum, LineLLValue); 2473 LineMinimum = Math.min(LineMinimum, LineLRValue); 2474 2475 /* Test for the presence of a limb in the spline box */ 2476 2477 if (LineMinimum == -99.9) { 2478 LABEL30 = true; 2479 } 2480 2481 LineMinimumFinal = (int) (LineMinimum + 0.5); 2482 if (LineMinimumFinal > MaximumSourceLine) { 2483 LABEL30 = true; 2484 } 2485 LineMaximum = Math.max(LineULValue, LineURValue); 2486 LineMaximum = Math.max(LineMaximum, LineLLValue); 2487 LineMaximum = Math.max(LineMaximum, LineLRValue); 2488 LineMaximumFinal = (int) (LineMaximum + 0.5); 2489 if (LineMaximumFinal < SourceBlockInc) { 2490 LABEL30 = true; 2491 } 2492 2493 /* 2494 * Get 4 corners in elem space & check for out of 2495 * bound 2496 */ 2497 2498 ValX = remap_vars.ncl; 2499 ElementULValue = ElementCoordinateArray[CornerPointer]; 2500 ElementURValue = ElementCoordinateArray[CornerPointer + 1]; 2501 ElementLLValue = ElementCoordinateArray[CornerPointer + ValX]; 2502 if ((CornerPointer + 1 + ValX) < NumberOfCornersInput) { 2503 ElementLRValue = ElementCoordinateArray[CornerPointer + 1 + ValX]; 2504 } else { 2505 ElementLRValue = ElementCoordinateArray[CornerPointer + ValX]; 2506 } 2507 2508 ElementMaximum = Math.max(ElementULValue, ElementURValue); 2509 ElementMaximum = Math.max(ElementMaximum, ElementLLValue); 2510 ElementMaximum = Math.max(ElementMaximum, ElementLRValue); 2511 ElementMaximumFinal = (int) (ElementMaximum + 0.5); 2512 if (ElementMaximumFinal < 1) { 2513 LABEL30 = true; 2514 } 2515 2516 ElementMinimum = Math.min(ElementULValue, ElementURValue); 2517 ElementMinimum = Math.min(ElementMinimum, ElementLLValue); 2518 ElementMinimum = Math.min(ElementMinimum, ElementLRValue); 2519 ElementMinimumFinal = (int) (ElementMinimum + 0.5); 2520 2521 if (ElementMinimumFinal > tiff_vars.in_elems) { 2522 LABEL30 = true; 2523 } 2524 EdgeFixID = 0; 2525 2526 /* 2527 * If the max & min element fall off the 2528 * image...pitch it 2529 */ 2530 2531 if ((ElementMaximumFinal > tiff_vars.in_elems) 2532 && (ElementMinimumFinal < 1)) { 2533 LABEL30 = true; 2534 } 2535 2536 /* Fix if left & right edge should be continuous */ 2537 2538 if (!LABEL30) { 2539 if ((ElementMaximumFinal - ElementMinimumFinal) > (int) (.75 * tiff_vars.in_elems)) { 2540 if (ElementULValue < (tiff_vars.in_elems / 2)) { 2541 ElementULValue = ElementULValue + tiff_vars.in_elems; 2542 } 2543 if (ElementURValue < (tiff_vars.in_elems / 2)) { 2544 ElementURValue = ElementURValue + tiff_vars.in_elems; 2545 } 2546 if (ElementLLValue < (tiff_vars.in_elems / 2)) { 2547 ElementLLValue = ElementLLValue + tiff_vars.in_elems; 2548 } 2549 if (ElementLRValue < (tiff_vars.in_elems / 2)) { 2550 ElementLRValue = ElementLRValue + tiff_vars.in_elems; 2551 } 2552 EdgeFixID = 1; 2553 } 2554 2555 LineValueA = (LineURValue - LineULValue) / ElementSplineInput; 2556 LineValueB = (LineLLValue - LineULValue) / LineSplineInput; 2557 LineValueC = (LineLRValue + LineULValue - LineURValue - LineLLValue) 2558 / SplinePixelValue; 2559 ElementValueA = (ElementURValue - ElementULValue) 2560 / ElementSplineInput; 2561 ElementValueB = (ElementLLValue - ElementULValue) / LineSplineInput; 2562 ElementValueC = (ElementLRValue + ElementULValue - ElementLLValue - ElementURValue) 2563 / SplinePixelValue; 2564 2565 int ElementMiscValue = 0; 2566 LineValueBCounter = LineULValue + 0.5; 2567 LineValueCCounter = 0.0; 2568 ElementValueBCounter = ElementULValue + 0.5; 2569 ElementValueCCounter = 0.0; 2570 2571 if (ReadAllTF == false) { 2572 ReadAllTF = true; 2573 } 2574 2575 if ((SplineInc == remap_vars.nspl) 2576 || (ElementMinimumFinal < 1 || (ElementMaximumFinal > tiff_vars.in_elems)) 2577 || ((LineMinimumFinal < SourceBlockInc) || (LineMaximumFinal > MaximumSourceLine)) 2578 || ((FirstCornerPointer + (2 * remap_vars.ncl) - 1) > LastCornerPointer)) { 2579 for (YInc = 1; YInc < LineSplineInput + 1; YInc++) { 2580 LineValueACounter = LineValueCCounter + LineValueA; 2581 ElementValueACounter = ElementValueCCounter + ElementValueA; 2582 LineValueACounter0 = 0.0; 2583 ElementValueACounter0 = 0.0; 2584 for (XInc = 1; XInc < ElementSplineInput + 1; XInc++) { 2585 LABEL38 = false; 2586 SourceLine = (int) (LineValueBCounter + LineValueACounter0); 2587 if (SourceLine < SourceBlockInc) { 2588 LABEL38 = true; 2589 } 2590 if (SourceLine > MaximumSourceLine) { 2591 LABEL38 = true; 2592 } 2593 if (!LABEL38) 2594 SourceElement = (int) (ElementValueBCounter + ElementValueACounter0); 2595 if (SourceElement < 1) { 2596 LABEL38 = true; 2597 } 2598 if ((SourceElement > tiff_vars.in_elems) 2599 && (EdgeFixID == 0)) { 2600 LABEL38 = true; 2601 } 2602 if (!LABEL38) { 2603 if (SourceElement > tiff_vars.in_elems) { 2604 SourceElement = SourceElement 2605 - tiff_vars.in_elems; 2606 } 2607 SourceOffsetValue = ((SourceLine - SourceBlockInc) * tiff_vars.in_elems) 2608 + SourceElement; 2609 OffsetValueE = OffsetValue1 + XInc; 2610 if (OffsetValueE > tiff_vars.out_elems) { 2611 LABEL38 = true; 2612 } 2613 if (!LABEL38) 2614 OffsetValueL = OffsetValue0 + ElementMiscValue; 2615 if ((OffsetValueL / (tiff_vars.out_elems 2616 + AccumulatedLines - 1)) > tiff_vars.out_lines) { 2617 LABEL38 = true; 2618 } 2619 if (!LABEL38) { 2620 OffsetValue = OffsetValueL + OffsetValueE; 2621 InterpArray[OffsetValue - 1] = SourceArray[SourceOffsetValue - 1]; 2622 } /* LABEL38: */ 2623 } /* LABEL38: */ 2624 LineValueACounter0 = LineValueACounter0 2625 + LineValueACounter; 2626 ElementValueACounter0 = ElementValueACounter0 2627 + ElementValueACounter; 2628 } 2629 LineValueBCounter = LineValueBCounter + LineValueB; 2630 LineValueCCounter = LineValueCCounter + LineValueC; 2631 ElementValueBCounter = ElementValueBCounter + ElementValueB; 2632 ElementValueCCounter = ElementValueCCounter + ElementValueC; 2633 ElementMiscValue = ElementMiscValue + tiff_vars.out_elems; 2634 } 2635 } else { 2636 if (EdgeFixID == 0) { 2637 for (YInc = 1; YInc < LineSplineInput + 1; YInc++) { 2638 LineValueACounter = LineValueCCounter + LineValueA; 2639 ElementValueACounter = ElementValueCCounter 2640 + ElementValueA; 2641 LineValueACounter0 = 0.0; 2642 ElementValueACounter0 = 0.0; 2643 OffsetValue = OffsetValue2 + ElementMiscValue; 2644 for (XInc = 1; XInc < ElementSplineInput + 1; XInc++) { 2645 SourceLine = (int) (LineValueBCounter + LineValueACounter0); 2646 SourceElement = (int) (ElementValueBCounter + ElementValueACounter0); 2647 SourceOffsetValue = ((SourceLine - SourceBlockInc) * tiff_vars.in_elems) 2648 + SourceElement; 2649 InterpArray[OffsetValue - 1] = SourceArray[SourceOffsetValue - 1]; 2650 OffsetValue = OffsetValue + 1; 2651 LineValueACounter0 = LineValueACounter0 2652 + LineValueACounter; 2653 ElementValueACounter0 = ElementValueACounter0 2654 + ElementValueACounter; 2655 } 2656 LineValueBCounter = LineValueBCounter + LineValueB; 2657 LineValueCCounter = LineValueCCounter + LineValueC; 2658 ElementValueBCounter = ElementValueBCounter 2659 + ElementValueB; 2660 ElementValueCCounter = ElementValueCCounter 2661 + ElementValueC; 2662 ElementMiscValue = ElementMiscValue 2663 + tiff_vars.out_elems; 2664 } 2665 } else if (EdgeFixID == 1) { 2666 for (YInc = 1; YInc < LineSplineInput + 1; YInc++) { 2667 LineValueACounter = LineValueCCounter + LineValueA; 2668 ElementValueACounter = ElementValueCCounter 2669 + ElementValueA; 2670 LineValueACounter0 = 0.0; 2671 ElementValueACounter0 = 0.0; 2672 OffsetValue = OffsetValue2 + ElementMiscValue; 2673 for (XInc = 1; XInc < ElementSplineInput + 1; XInc++) { 2674 SourceLine = (int) (LineValueBCounter + LineValueACounter0); 2675 SourceElement = (int) (ElementValueBCounter + ElementValueACounter0); 2676 if (SourceElement > tiff_vars.in_elems) { 2677 SourceElement = SourceElement 2678 - tiff_vars.in_elems; 2679 } 2680 SourceOffsetValue = ((SourceLine - SourceBlockInc) * tiff_vars.in_elems) 2681 + SourceElement; 2682 InterpArray[OffsetValue - 1] = SourceArray[SourceOffsetValue - 1]; 2683 OffsetValue = OffsetValue + 1; 2684 LineValueACounter0 = LineValueACounter0 2685 + LineValueACounter; 2686 ElementValueACounter0 = ElementValueACounter0 2687 + ElementValueACounter; 2688 } 2689 LineValueBCounter = LineValueBCounter + LineValueB; 2690 LineValueCCounter = LineValueCCounter + LineValueC; 2691 ElementValueBCounter = ElementValueBCounter 2692 + ElementValueB; 2693 ElementValueCCounter = ElementValueCCounter 2694 + ElementValueC; 2695 ElementMiscValue = ElementMiscValue 2696 + tiff_vars.out_elems; 2697 } 2698 } 2699 } 2700 } /* LABEL30: */ 2701 SourceBlockValue = SourceBlockValue + 1; 2702 } 2703 FirstCornerPointer = FirstCornerPointer + remap_vars.ncl; 2704 } 2705 } 2706 BlockCounter = BlockCounter + 1; 2707 } 2708 2709 for (YInc = 0; YInc < tiff_vars.out_lines; YInc++) { 2710 for (XInc = 0; XInc < tiff_vars.out_elems; XInc++) { 2711 ArrayIndexValue = (YInc * tiff_vars.out_elems) + XInc; 2712 if ((ArrayIndexValue > 0) && (InterpArray[ArrayIndexValue] == 0.0)) { 2713 InterpArray[ArrayIndexValue] = InterpArray[ArrayIndexValue - 1]; 2714 } 2715 IRData_Remap_Temperature[YInc][XInc] = InterpArray[ArrayIndexValue]; 2716 } 2717 } 2718 Ret_ID = 0; 2719 } 2720 2721 return Ret_ID; 2722 2723 } 2724 2725 private static int IND(int y, int x) { 2726 /* #define IND(y,x) ((y-1)*remap_vars.ncl+x) */ 2727 return ((y - 1) * remap_vars.ncl + x); 2728 } 2729 2730}