001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2017 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028package edu.wisc.ssec.mcidasv.data.hydra; 029 030import visad.Data; 031import visad.FlatField; 032import visad.VisADException; 033import visad.FunctionType; 034import visad.RealType; 035import visad.RealTupleType; 036import visad.Linear1DSet; 037import visad.Linear2DSet; 038import visad.Gridded2DSet; 039import visad.CoordinateSystem; 040import visad.CommonUnit; 041import visad.SetType; 042import visad.georef.MapProjection; 043import visad.util.ThreadManager; 044 045import java.util.Arrays; 046import java.rmi.RemoteException; 047 048public class ReprojectSwath { 049 private static int count = 0; 050 051 Linear2DSet grid; 052 Linear2DSet swathDomain; 053 FunctionType ftype; 054 float[][] swathRange; 055 CoordinateSystem swathCoordSys; 056 CoordinateSystem gridCoordSys; 057 058 float[][] allSwathGridCoords; 059 int[] allSwathGridIndexs; 060 float[][] swathGridCoord; 061 int[] swathIndexAtGrid; 062 063 int trackLen; 064 int xtrackLen; 065 066 int gridXLen; 067 int gridYLen; 068 int gridLen; 069 070 float[][] gridRange; 071 int rngTupDim; 072 FlatField grdFF; 073 074 int[][][] quads; 075 int mode; 076 077 public static final int NEAREST = 1; 078 public static final int BILINEAR_VISAD = 0; 079 080 int numProc = Runtime.getRuntime().availableProcessors(); 081 private static boolean doParallel = false; 082 083 private static ReprojectSwath lastReproject = null; 084 085 public static void setDoParallel(boolean enable) { 086 doParallel = enable; 087 } 088 089 public static FlatField swathToGrid(Linear2DSet grid, FlatField[] swaths, int mode) throws Exception { 090 return swathToGrid(grid, swaths, mode, true); 091 } 092 093 public static FlatField swathToGrid(Linear2DSet grid, FlatField[] swaths, int mode, boolean filter) throws Exception { 094 FunctionType ftype = (FunctionType) swaths[0].getType(); 095 visad.Set domSet = swaths[0].getDomainSet(); 096 097 FlatField swath = new FlatField(new FunctionType(ftype.getDomain(), 098 new RealTupleType(new RealType[] 099 {RealType.getRealType("redimage_"+count), RealType.getRealType("greenimage_"+count), RealType.getRealType("blueimage_"+count)})), domSet); 100 101 swath.setSamples(new float[][] 102 {swaths[0].getFloats(false)[0], swaths[1].getFloats(false)[0], swaths[2].getFloats(false)[0]}); 103 104 count++; 105 106 return swathToGrid(grid, swath, mode); 107 } 108 109 public static FlatField swathToGrid(Linear2DSet grid, FlatField swath, int mode) throws Exception { 110 return swathToGrid(grid, swath, mode, true); 111 } 112 113 public static FlatField swathToGrid(Linear2DSet grid, FlatField swath, int mode, boolean filter) throws Exception { 114 ReprojectSwath obj = null; 115 FlatField ff = null; 116 117 if (lastReproject != null) { 118 if (grid.equals(lastReproject.grid) && (swath.getDomainSet()).equals(lastReproject.swathDomain)) { 119 obj = lastReproject; 120 ff = obj.reproject(swath, mode, filter); 121 } 122 else { 123 obj = new ReprojectSwath(grid, swath); 124 ff = obj.reproject(mode, filter); 125 } 126 } 127 else { 128 obj = new ReprojectSwath(grid, swath); 129 ff = obj.reproject(mode, filter); 130 } 131 lastReproject = obj; 132 133 return ff; 134 } 135 136 public ReprojectSwath() { 137 } 138 139 public ReprojectSwath(Linear2DSet grid, FlatField swath) throws Exception { 140 141 init(grid, swath); 142 143 if (trackLen < 200 || doParallel == false) { 144 numProc = 1; 145 } 146 147 projectSwathToGrid(); 148 } 149 150 private void init(Linear2DSet grid, FlatField swath) throws VisADException { 151 this.grid = grid; 152 gridLen = grid.getLength(); 153 int[] lens = grid.getLengths(); 154 gridXLen = lens[0]; 155 gridYLen = lens[1]; 156 gridCoordSys = grid.getCoordinateSystem(); 157 158 swathDomain = (Linear2DSet) swath.getDomainSet(); 159 lens = swathDomain.getLengths(); 160 trackLen = lens[1]; 161 xtrackLen = lens[0]; 162 int swathLen = trackLen*xtrackLen; 163 swathCoordSys = swathDomain.getCoordinateSystem(); 164 swathRange = swath.getFloats(false); 165 ftype = (FunctionType) swath.getType(); 166 167 allSwathGridCoords = new float[2][swathLen]; 168 allSwathGridIndexs = new int[swathLen]; 169 swathGridCoord = new float[2][gridLen]; 170 swathIndexAtGrid = new int[gridLen]; 171 172 quads = new int[gridYLen][gridXLen][4]; 173 } 174 175 /* 176 public FlatField reproject(Linear2DSet grid, FlatField swath, int mode, boolean filter) throws Exception { 177 init(); 178 179 if (trackLen < 200 || doParallel == false) { 180 numProc = 1; 181 } 182 183 return reproject(mode, filter); 184 } 185 */ 186 187 public FlatField reproject(int mode, boolean filter) throws Exception { 188 this.mode = mode; 189 190 initGrid(); 191 192 getBoundingQuadAtGridPts(); 193 194 interpolateToGrid(); 195 196 if (filter) { 197 grdFF.setSamples(filter(), false); 198 } 199 else { 200 grdFF.setSamples(gridRange, false); 201 } 202 203 return grdFF; 204 } 205 206 private FlatField reproject(FlatField swath, int mode, boolean filter) throws Exception { 207 this.mode = mode; 208 swathRange = swath.getFloats(false); 209 ftype = (FunctionType) swath.getType(); 210 211 initGrid(); 212 213 getBoundingQuadAtGridPts(); 214 215 interpolateToGrid(); 216 217 if (filter) { 218 grdFF.setSamples(filter(), false); 219 } 220 else { 221 grdFF.setSamples(gridRange, false); 222 } 223 224 return grdFF; 225 } 226 227 private void getBoundingQuadAtGridPts() throws VisADException, RemoteException { 228 int ystart = 3; 229 int ystop = gridYLen-4; 230 int subLen = ((ystop - ystart)+1)/numProc; 231 int rem = ((ystop - ystart)+1) % numProc; 232 233 234 ThreadManager threadManager = new ThreadManager("getBoundingQuadAtGridPts"); 235 for (int i=0; i<numProc; i++) { 236 final int start = i*subLen + ystart; 237 final int stop = (i != numProc-1 ) ? (start + subLen - 1): (start + subLen + rem - 1); 238 threadManager.addRunnable(new ThreadManager.MyRunnable() { 239 public void run() throws Exception { 240 getBoundingQuadAtGridPts(start, stop); 241 } 242 }); 243 } 244 245 if (numProc == 1 || !doParallel) { 246 threadManager.runSequentially(); 247 } 248 else { 249 threadManager.runAllParallel(); 250 } 251 } 252 253 // start to stop inclusive 254 private void getBoundingQuadAtGridPts(int grdYstart, int grdYstop) { 255 256 for (int j=grdYstart; j<=grdYstop; j++) { 257 for (int i=3; i<gridXLen-3; i++) { 258 int grdIdx = i + j*gridXLen; 259 260 int ll = findSwathGridLoc(grdIdx, swathGridCoord, gridYLen, gridXLen, "LL"); 261 quads[j][i][0] = ll; 262 263 int lr = findSwathGridLoc(grdIdx, swathGridCoord, gridYLen, gridXLen, "LR"); 264 quads[j][i][1] = lr; 265 266 int ul = findSwathGridLoc(grdIdx, swathGridCoord, gridYLen, gridXLen, "UL"); 267 quads[j][i][2] = ul; 268 269 int ur = findSwathGridLoc(grdIdx, swathGridCoord, gridYLen, gridXLen, "UR"); 270 quads[j][i][3] = ur; 271 } 272 } 273 } 274 275 public void interpolateToGrid() throws VisADException, RemoteException { 276 int ystart = 3; 277 int ystop = gridYLen-4; 278 int subLen = ((ystop - ystart)+1)/numProc; 279 int rem = ((ystop - ystart)+1) % numProc; 280 281 ThreadManager threadManager = new ThreadManager("interpolateToGrid"); 282 for (int i=0; i<numProc; i++) { 283 final int start = i*subLen + ystart; 284 final int stop = (i != numProc-1 ) ? (start + subLen - 1): (start + subLen + rem - 1); 285 threadManager.addRunnable(new ThreadManager.MyRunnable() { 286 public void run() throws Exception { 287 interpolateToGrid(start, stop); 288 } 289 }); 290 } 291 292 if (numProc == 1 || !doParallel) { 293 threadManager.runSequentially(); 294 } 295 else { 296 threadManager.runAllParallel(); 297 } 298 } 299 300 // start to stop inclusive 301 public void interpolateToGrid(int grdYstart, int grdYstop) throws VisADException, RemoteException { 302 303 float[][] corners = new float[2][4]; 304 float[][] rngVals = new float[rngTupDim][4]; 305 float[] values = new float[4]; 306 float gx; 307 float gy; 308 309 for (int j=grdYstart; j<=grdYstop; j++) { 310 for (int i=3; i<gridXLen-3; i++) { 311 int grdIdx = i + j*gridXLen; 312 gx = (float) (grdIdx % gridXLen); 313 gy = (float) (grdIdx / gridXLen); 314 315 java.util.Arrays.fill(corners[0], Float.NaN); 316 java.util.Arrays.fill(corners[1], Float.NaN); 317 318 int ll = quads[j][i][0]; 319 int lr = quads[j][i][1]; 320 int ul = quads[j][i][2]; 321 int ur = quads[j][i][3]; 322 323 if (ll >= 0) { 324 corners[0][0] = swathGridCoord[0][ll] - gx; 325 corners[1][0] = swathGridCoord[1][ll] - gy; 326 } 327 if (lr >= 0) { 328 corners[0][1] = swathGridCoord[0][lr] - gx; 329 corners[1][1] = swathGridCoord[1][lr] - gy; 330 } 331 if (ul >= 0) { 332 corners[0][2] = swathGridCoord[0][ul] - gx; 333 corners[1][2] = swathGridCoord[1][ul] - gy; 334 } 335 if (ur >= 0) { 336 corners[0][3] = swathGridCoord[0][ur] - gx; 337 corners[1][3] = swathGridCoord[1][ur] - gy; 338 } 339 340 if (mode == NEAREST) { // Nearest neighbor 341 for (int t=0; t<rngTupDim; t++) { 342 java.util.Arrays.fill(values, Float.NaN); 343 if (ll >=0) { 344 values[0] = swathRange[t][swathIndexAtGrid[ll]]; 345 } 346 if (lr >= 0) { 347 values[1] = swathRange[t][swathIndexAtGrid[lr]]; 348 } 349 if (ul >= 0) { 350 values[2] = swathRange[t][swathIndexAtGrid[ul]]; 351 } 352 if (ur >= 0) { 353 values[3] = swathRange[t][swathIndexAtGrid[ur]]; 354 } 355 float val = nearest(0f, 0f, corners, values); 356 gridRange[t][grdIdx] = val; 357 } 358 } 359 else if (mode == BILINEAR_VISAD) { //from VisAD 360 if (!(ll >= 0 && lr >= 0 && ul >= 0 && ur >= 0)) { 361 continue; 362 } 363 corners[0][0] = swathGridCoord[0][ll]; 364 corners[1][0] = swathGridCoord[1][ll]; 365 corners[0][1] = swathGridCoord[0][lr]; 366 corners[1][1] = swathGridCoord[1][lr]; 367 corners[0][2] = swathGridCoord[0][ul]; 368 corners[1][2] = swathGridCoord[1][ul]; 369 corners[0][3] = swathGridCoord[0][ur]; 370 corners[1][3] = swathGridCoord[1][ur]; 371 for (int t=0; t<rngTupDim; t++) { 372 java.util.Arrays.fill(values, Float.NaN); 373 values[0] = swathRange[t][swathIndexAtGrid[ll]]; 374 values[1] = swathRange[t][swathIndexAtGrid[lr]]; 375 values[2] = swathRange[t][swathIndexAtGrid[ul]]; 376 values[3] = swathRange[t][swathIndexAtGrid[ur]]; 377 float val = visad2D(gy, gx, corners, values); 378 gridRange[t][grdIdx] = val; 379 } 380 } 381 else if (mode == 1) { //TODO: not working yet 382 if (!(ll >= 0 && lr >= 0 && ul >= 0 && ur >= 0)) { 383 continue; 384 } 385 gx -= swathGridCoord[0][ll]; 386 gy -= swathGridCoord[1][ll]; 387 corners[0][0] = 0f; 388 corners[1][0] = 0f; 389 corners[0][1] = swathGridCoord[0][ul] - swathGridCoord[0][ll]; 390 corners[1][1] = swathGridCoord[1][ul] - swathGridCoord[1][ll]; 391 corners[0][2] = swathGridCoord[0][ur] - swathGridCoord[0][ll]; 392 corners[1][2] = swathGridCoord[1][ur] - swathGridCoord[1][ll]; 393 corners[0][3] = swathGridCoord[0][lr] - swathGridCoord[0][ll]; 394 corners[1][3] = swathGridCoord[1][lr] - swathGridCoord[1][ll]; 395 for (int t=0; t<rngTupDim; t++) { 396 java.util.Arrays.fill(values, Float.NaN); 397 values[0] = swathRange[t][swathIndexAtGrid[ll]]; 398 values[1] = swathRange[t][swathIndexAtGrid[ul]]; 399 values[2] = swathRange[t][swathIndexAtGrid[ur]]; 400 values[3] = swathRange[t][swathIndexAtGrid[lr]]; 401 float val = biLinearIntrp(gy, gx, corners, values); 402 gridRange[t][grdIdx] = val; 403 } 404 405 } 406 } 407 } 408 409 } 410 411 public void projectSwathToGrid() throws VisADException, RemoteException { 412 int subLen = trackLen/numProc; 413 int rem = trackLen % numProc; 414 415 ThreadManager threadManager = new ThreadManager("projectSwathToGrid"); 416 for (int i=0; i<numProc; i++) { 417 final int start = i*subLen; 418 final int stop = (i != numProc-1 ) ? (start + subLen - 1): (start + subLen + rem - 1); 419 threadManager.addRunnable(new ThreadManager.MyRunnable() { 420 public void run() throws Exception { 421 projectSwathToGrid(start, stop); 422 } 423 }); 424 } 425 426 if (numProc == 1 || !doParallel) { 427 threadManager.runSequentially(); 428 } 429 else { 430 threadManager.runAllParallel(); 431 } 432 } 433 434 public void projectSwathToGrid(int trackStart, int trackStop) throws VisADException, RemoteException { 435 436 for (int j=trackStart; j <= trackStop; j++) { 437 for (int i=0; i < xtrackLen; i++) { 438 int swathIdx = j*xtrackLen + i; 439 440 float[][] swathCoord = swathDomain.indexToValue(new int[] {swathIdx}); 441 float[][] swathEarthCoord = swathCoordSys.toReference(swathCoord); 442 443 float[][] gridValue = gridCoordSys.fromReference(swathEarthCoord); 444 float[][] gridCoord = grid.valueToGrid(gridValue); 445 float g0 = gridCoord[0][0]; 446 float g1 = gridCoord[1][0]; 447 int grdIdx = (g0 != g0 || g1 != g1) ? -1 : ((int) g0) + gridXLen * ((int) g1); 448 int m=0; 449 int n=0; 450 int k = grdIdx + (m + n*gridXLen); 451 452 allSwathGridCoords[0][swathIdx] = g0; 453 allSwathGridCoords[1][swathIdx] = g1; 454 allSwathGridIndexs[swathIdx] = k; 455 456 } 457 } 458 } 459 460 public void initGrid() throws VisADException { 461 Arrays.fill(swathGridCoord[0], -999.9f); 462 Arrays.fill(swathGridCoord[1], -999.9f); 463 Arrays.fill(swathIndexAtGrid, -1); 464 465 for (int j=0; j < trackLen; j++) { 466 for (int i=0; i < xtrackLen; i++) { 467 int swathIdx = j*xtrackLen + i; 468 float val = swathRange[0][swathIdx]; 469 int k = allSwathGridIndexs[swathIdx]; 470 471 if ( !(Float.isNaN(val)) && ((k >=0) && (k < gridLen)) ) { // val or val[rngTupDim] ? 472 if (swathIndexAtGrid[k] == -1) { 473 swathGridCoord[0][k] = allSwathGridCoords[0][swathIdx]; 474 swathGridCoord[1][k] = allSwathGridCoords[1][swathIdx]; 475 swathIndexAtGrid[k] = swathIdx; 476 } 477 } 478 } 479 } 480 481 for (int j=0; j<gridYLen; j++) { 482 for (int i=0; i<gridXLen; i++) { 483 java.util.Arrays.fill(quads[j][i], -1); 484 } 485 } 486 487 RealTupleType rtt = ((SetType)grid.getType()).getDomain(); 488 grdFF = new FlatField(new FunctionType(rtt, ftype.getRange()), grid); 489 gridRange = grdFF.getFloats(false); 490 rngTupDim = gridRange.length; 491 for (int t=0; t<rngTupDim; t++) { 492 java.util.Arrays.fill(gridRange[t], Float.NaN); 493 } 494 } 495 496 private float[][] filter() throws VisADException, RemoteException { 497 498 double mag = 3.0; 499 double sigma = 0.4; 500 501 float[][] weights = new float[3][3]; 502 503 float sumWeights = 0f; 504 for (int n=-1; n<=1; n++) { 505 for (int m=-1; m<=1; m++) { 506 double del_0 = m; 507 double del_1 = n; 508 double dst = Math.sqrt(del_0*del_0 + del_1*del_1); 509 510 weights[n+1][m+1] = (float) (mag/Math.exp(dst/sigma)); 511 512 sumWeights += weights[n+1][m+1]; 513 } 514 } 515 516 for (int n=-1; n<=1; n++) { 517 for (int m=-1; m<=1; m++) { 518 weights[n+1][m+1] /= sumWeights; 519 } 520 } 521 522 float[][] newRange = new float[rngTupDim][gridLen]; 523 for (int t=0; t<rngTupDim; t++) { 524 java.util.Arrays.fill(newRange[t], Float.NaN); 525 } 526 float[] sum = new float[rngTupDim]; 527 528 for (int j=2; j<gridYLen-2; j++) { 529 for (int i=2; i<gridXLen-2; i++) { 530 int grdIdx = i + j*gridXLen; 531 532 java.util.Arrays.fill(sum, 0f); 533 for (int n=-1; n<=1; n++) { 534 for (int m=-1; m<=1; m++) { 535 int k = grdIdx + (m + n*gridXLen); 536 537 for (int t=0; t<rngTupDim; t++) { 538 sum[t] += weights[n+1][m+1]*gridRange[t][k]; 539 } 540 } 541 } 542 543 for (int t=0; t<rngTupDim; t++) { 544 newRange[t][grdIdx] = sum[t]; 545 } 546 } 547 } 548 549 return newRange; 550 } 551 private static int findSwathGridLoc(int grdIdx, float[][] swathGridCoord, int gridYLen, int gridXLen, String which) { 552 553 int idx = -1; 554 555 int gy = grdIdx/gridXLen; 556 int gx = grdIdx % gridXLen; 557 558 int yu1 = (gy+1)*gridXLen; 559 int yu2 = (gy+2)*gridXLen; 560 int yu3 = (gy+3)*gridXLen; 561 562 int yd1 = (gy-1)*gridXLen; 563 int yd2 = (gy-2)*gridXLen; 564 int yd3 = (gy-3)*gridXLen; 565 566 switch (which) { 567 case "LL": 568 569 idx = yd1 + (gx-1); 570 if (swathGridCoord[0][idx] != -999.9f) { 571 break; 572 } 573 idx = yd2 + (gx-1); 574 if (swathGridCoord[0][idx] != -999.9f) { 575 break; 576 } 577 idx = yd1 + (gx-2); 578 if (swathGridCoord[0][idx] != -999.9f) { 579 break; 580 } 581 idx = yd2 + (gx-2); 582 if (swathGridCoord[0][idx] != -999.9f) { 583 break; 584 } 585 586 587 idx = yd2 + (gx-3); 588 if (swathGridCoord[0][idx] != -999.9f) { 589 break; 590 } 591 idx = yd3 + (gx-2); 592 if (swathGridCoord[0][idx] != -999.9f) { 593 break; 594 } 595 idx = yd3 + (gx-1); 596 if (swathGridCoord[0][idx] != -999.9f) { 597 break; 598 } 599 idx = yd1 + (gx-3); 600 if (swathGridCoord[0][idx] != -999.9f) { 601 break; 602 } 603 idx = yd3 + (gx-3); 604 if (swathGridCoord[0][idx] != -999.9f) { 605 break; 606 } 607 608 idx = -1; 609 break; 610 case "UL": 611 idx = (gy)*gridXLen + (gx-1); 612 if (swathGridCoord[0][idx] != -999.9f) { 613 break; 614 } 615 idx = (gy)*gridXLen + (gx-2); 616 if (swathGridCoord[0][idx] != -999.9f) { 617 break; 618 } 619 idx = yu1 + (gx-1); 620 if (swathGridCoord[0][idx] != -999.9f) { 621 break; 622 } 623 idx = yu1 + (gx-2); 624 if (swathGridCoord[0][idx] != -999.9f) { 625 break; 626 } 627 628 idx = yu1 + (gx-3); 629 if (swathGridCoord[0][idx] != -999.9f) { 630 break; 631 } 632 idx = yu2 + (gx-3); 633 if (swathGridCoord[0][idx] != -999.9f) { 634 break; 635 } 636 idx = yu2 + (gx-2); 637 if (swathGridCoord[0][idx] != -999.9f) { 638 break; 639 } 640 idx = (gy)*gridXLen + (gx-3); 641 if (swathGridCoord[0][idx] != -999.9f) { 642 break; 643 } 644 idx = yd1 + (gx-3); 645 if (swathGridCoord[0][idx] != -999.9f) { 646 break; 647 } 648 649 idx = -1; 650 break; 651 case "UR": 652 idx = (gy)*gridXLen + (gx); 653 if (swathGridCoord[0][idx] != -999.9f) { 654 break; 655 } 656 idx = yu1 + (gx); 657 if (swathGridCoord[0][idx] != -999.9f) { 658 break; 659 } 660 idx = (gy)*gridXLen + (gx+1); 661 if (swathGridCoord[0][idx] != -999.9f) { 662 break; 663 } 664 idx = yu1 + (gx+1); 665 if (swathGridCoord[0][idx] != -999.9f) { 666 break; 667 } 668 669 idx = yu2 + (gx+1); 670 if (swathGridCoord[0][idx] != -999.9f) { 671 break; 672 } 673 idx = yu1 + (gx+2); 674 if (swathGridCoord[0][idx] != -999.9f) { 675 break; 676 } 677 idx = yu2 + (gx+2); 678 if (swathGridCoord[0][idx] != -999.9f) { 679 break; 680 } 681 idx = (gy)*gridXLen + (gx+2); 682 if (swathGridCoord[0][idx] != -999.9f) { 683 break; 684 } 685 idx = yd1 + (gx+2); 686 if (swathGridCoord[0][idx] != -999.9f) { 687 break; 688 } 689 690 idx = -1; 691 break; 692 case "LR": 693 idx = yd1 + (gx); 694 if (swathGridCoord[0][idx] != -999.9f) { 695 break; 696 } 697 idx = yd1 + (gx+1); 698 if (swathGridCoord[0][idx] != -999.9f) { 699 break; 700 } 701 idx = yd2 + (gx); 702 if (swathGridCoord[0][idx] != -999.9f) { 703 break; 704 } 705 idx = yd2 + (gx+1); 706 if (swathGridCoord[0][idx] != -999.9f) { 707 break; 708 } 709 710 idx = yd1 + (gx+2); 711 if (swathGridCoord[0][idx] != -999.9f) { 712 break; 713 } 714 idx = yd2 + (gx+2); 715 if (swathGridCoord[0][idx] != -999.9f) { 716 break; 717 } 718 idx = yd3 + (gx); 719 if (swathGridCoord[0][idx] != -999.9f) { 720 break; 721 } 722 idx = yd3 + (gx+1); 723 if (swathGridCoord[0][idx] != -999.9f) { 724 break; 725 } 726 idx = yd3 + (gx+2); 727 if (swathGridCoord[0][idx] != -999.9f) { 728 break; 729 } 730 731 idx = -1; 732 break; 733 } 734 735 return idx; 736 } 737 738 /* Reference: David W. Zingg, University of Toronto, Downsview, Ontario, Canada 739 Maurice Yarrow, Sterling Software, Arnes Research Center, Moffett Field, California. 740 NASA Technical Memorandum 102213 741 742 y -> q, x -> p; first point (x=0, y=0) and clockwise around 743 */ 744 public static float biLinearIntrp(float gy, float gx, float[][] corners, float[] values) { 745 // transform physical space (gy, gx) to unit square (q, p) 746 // bilinear mapping coefficients 747/* 748 float a = corners[0][3]; 749 float b = corners[0][1]; 750 float c = (corners[0][2] - corners[0][3] - corners[0][1]); 751 752 float d = corners[1][3]; 753 float e = corners[1][1]; 754 float f = (corners[1][2] - corners[1][3] - corners[1][1]); 755*/ 756 757 float a = corners[0][1]; 758 float b = corners[0][3]; 759 float c = (corners[0][2] - corners[0][1] - corners[0][3]); 760 761 float d = corners[1][1]; 762 float e = corners[1][3]; 763 float f = (corners[1][2] - corners[1][1] - corners[1][3]); 764 765 766 // quadratic terms to determine p 767 // p = (-coef1 +/- sqrt(coef1^2 - 4*coef2*coef0))/2*coef2 768 769 float coef2 = (c*d - a*f); // A 770 float coef1 = (-c*gy + b*d + gx*f - a*e); // B 771 float coef0 = (-gy*b + gx*e); // C 772 773 // two p vals from quadratic: 774 float p0 = (-coef1 + ((float)Math.sqrt(coef1*coef1 - 4*coef2*coef0)) )/2f*coef2; 775 float p1 = (-coef1 - ((float)Math.sqrt(coef1*coef1 - 4*coef2*coef0)) )/2f*coef2; 776 777 // the corresponding q values for both p solutions: 778 float q0 = (gx - a*p0)/(b + c*p0); 779 float q1 = (gx - a*p1)/(b + c*p1); 780 781 // test which point to use. One will be outside unit square: 782 float p = Float.NaN; 783 float q = Float.NaN; 784 if ((p0 >= 0f && p0 <= 1f) && (q0 >= 0f && q0 <= 1f)) { 785 p = p0; 786 q = q0; 787 } 788 else if ((p1 >= 0f && p1 <= 1f) && (q1 >= 0f && q1 <= 1f)) { 789 p = p1; 790 q = q1; 791 } 792 793 // bilinear interpolation within the unit square: 794 795 float intrp = values[0]*(1f-p)*(1f-q) + values[1]*(1f-p)*q + values[2]*p*q + values[3]*p*(1f-q); 796 797 return intrp; 798 } 799 800 private static float nearest(float gy, float gx, float[][] corners, float[] values) { 801 float minDist = Float.MAX_VALUE; 802 803 float delx; 804 float dely; 805 int closest = 0; 806 for (int k=0; k<4; k++) { 807 delx = corners[0][k] - gx; 808 dely = corners[1][k] - gy; 809 float dst_sqrd = delx*delx + dely*dely; 810 811 if (dst_sqrd < minDist) { 812 minDist = dst_sqrd; 813 closest = k; 814 } 815 } 816 817 return values[closest]; 818 } 819 public static float visad2D(float gy, float gx, float[][] corners, float[] values) { 820 boolean Pos = true; 821 822 // A:0, B:1, C:2, D:3 823 float v0x = corners[0][0]; 824 float v0y = corners[1][0]; 825 float v1x = corners[0][1]; 826 float v1y = corners[1][1]; 827 float v2x = corners[0][2]; 828 float v2y = corners[1][2]; 829 float v3x = corners[0][3]; 830 float v3y = corners[1][3]; 831 832 float bdx = v2x-v1x; 833 float bdy = v2y-v1y; 834 835 float bpx = gx-v1x; 836 float bpy = gy-v1y; 837 838 float dpx = gx-v2x; 839 float dpy = gy-v2y; 840 841 // lower triangle first 842 843 boolean insideTri = true; 844 845 float abx = v1x-v0x; 846 float aby = v1y-v0y; 847 float dax = v0x-v2x; 848 float day = v0y-v2y; 849 float apx = gx-v0x; 850 float apy = gy-v0y; 851 852 float tval1 = abx*apy-aby*apx; 853 float tval2 = bdx*bpy-bdy*bpx; 854 float tval3 = dax*dpy-day*dpx; 855 boolean test1 = (tval1 == 0) || ((tval1 > 0) == Pos); 856 boolean test2 = (tval2 == 0) || ((tval2 > 0) == Pos); 857 boolean test3 = (tval3 == 0) || ((tval3 > 0) == Pos); 858 859 if (!test1 && !test2) { // Go UP & RIGHT 860 insideTri = false; 861 } 862 else if (!test2 && !test3) { // Go DOWN & LEFT 863 insideTri = false; 864 } 865 else if (!test1 && !test3) { // Go UP & LEFT 866 insideTri = false; 867 } 868 else if (!test1) { // Go UP 869 insideTri = false; 870 } 871 else if (!test3) { // Go LEFT 872 insideTri = false; 873 } 874 875 insideTri = (insideTri && test2); 876 877 float gxx = Float.NaN; 878 float gyy = Float.NaN; 879 880 if (insideTri) { 881 gxx = ((gx-v0x)*(v2y-v0y) 882 + (v0y-gy)*(v2x-v0x)) 883 / ((v1x-v0x)*(v2y-v0y) 884 + (v0y-v1y)*(v2x-v0x)); 885 886 gyy = ((gx-v0x)*(v1y-v0y) 887 + (v0y-gy)*(v1x-v0x)) 888 / ((v2x-v0x)*(v1y-v0y) 889 + (v0y-v2y)*(v1x-v0x)); 890 } 891 else { 892 insideTri = true; 893 894 float bcx = v3x-v1x; 895 float bcy = v3y-v1y; 896 float cdx = v2x-v3x; 897 float cdy = v2y-v3y; 898 float cpx = gx-v3x; 899 float cpy = gy-v3y; 900 901 tval1 = bcx*bpy-bcy*bpx; 902 tval2 = cdx*cpy-cdy*cpx; 903 tval3 = bdx*dpy-bdy*dpx; 904 test1 = (tval1 == 0) || ((tval1 > 0) == Pos); 905 test2 = (tval2 == 0) || ((tval2 > 0) == Pos); 906 test3 = (tval3 == 0) || ((tval3 < 0) == Pos); 907 if (!test1 && !test3) { // Go UP & RIGHT 908 insideTri = false; 909 } 910 else if (!test2 && !test3) { // Go DOWN & LEFT 911 insideTri = false; 912 } 913 else if (!test1 && !test2) { // Go DOWN & RIGHT 914 insideTri = false; 915 } 916 else if (!test1) { // Go RIGHT 917 insideTri = false; 918 } 919 else if (!test2) { // Go DOWN 920 insideTri = false; 921 } 922 insideTri = (insideTri && test3); 923 924 if (insideTri) { 925 // Found correct grid triangle 926 // Solve the point with the reverse interpolation 927 gxx = ((v3x-gx)*(v1y-v3y) 928 + (gy-v3y)*(v1x-v3x)) 929 / ((v2x-v3x)*(v1y-v3y) 930 - (v2y-v3y)*(v1x-v3x)) + 1; 931 gyy = ((v2y-v3y)*(v3x-gx) 932 + (v2x-v3x)*(gy-v3y)) 933 / ((v1x-v3x)*(v2y-v3y) 934 - (v2x-v3x)*(v1y-v3y)) + 1; 935 } 936 937 } 938 939 // bilinear interpolation within the unit square: 940 941 float intrp = values[0]*(1f-gxx)*(1f-gyy) + values[2]*(1f-gxx)*gyy + values[3]*gxx*gyy + values[1]*gxx*(1f-gyy); 942 943 944 return intrp; 945 } 946 947}