001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2017 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029package edu.wisc.ssec.mcidasv.data.hydra; 030 031import java.rmi.RemoteException; 032import visad.Set; 033import visad.Gridded1DSet; 034import visad.CoordinateSystem; 035import visad.RealType; 036import visad.RealTupleType; 037import visad.Linear1DSet; 038import visad.Linear2DSet; 039import visad.Gridded2DSet; 040import visad.SampledSet; 041import visad.Unit; 042import visad.FunctionType; 043import visad.VisADException; 044import visad.QuickSort; 045import visad.FlatField; 046import visad.FieldImpl; 047import java.util.HashMap; 048import java.util.Map; 049import visad.GriddedSet; 050 051 052public abstract class ProfileAlongTrack extends MultiDimensionAdapter { 053 054 private FunctionType mathtype; 055 056 int TrackLen; 057 int VertLen; 058 059 private float[] vertLocs = null; 060 private float[] trackTimes = null; 061 private float[] trackLongitude = null; 062 private float[] trackLatitude = null; 063 064 public static String longitude_name = "Longitude"; 065 public static String latitude_name = "Latitude"; 066 public static String trackDim_name = "TrackDim"; 067 public static String vertDim_name = "VertDim"; 068 public static String array_name = "array_name"; 069 public static String profileTime_name = "ProfileTime"; 070 public static String profileTime_unit = "ProfileTime_unit"; 071 public static String altitude_unit = "altitude_unit"; 072 public static String sfcElev_name = "SurfaceElev"; 073 public static String range_name = "range_name"; 074 public static String scale_name = "scale_name"; 075 public static String offset_name = "offset_name"; 076 public static String fill_value_name = "fill_value_name"; 077 public static String valid_range = "valid_range"; 078 public static String ancillary_file_name = "ancillary_file"; 079 static String product_name = "product_name"; 080 081 String[] rangeName_s = null; 082 Class[] arrayType_s = null; 083 Unit[] rangeUnit_s = new Unit[] {null}; 084 085 RealType track = RealType.getRealType(trackDim_name); 086 RealType vert = RealType.getRealType(vertDim_name); 087 RealType[] domainRealTypes = new RealType[2]; 088 089 RealType vertLocType; 090 RealType trackTimeType; 091 092 int track_idx = -1; 093 int vert_idx = -1; 094 int range_rank = -1; 095 096 int track_tup_idx; 097 int vert_tup_idx; 098 099 boolean isVertDimAlt = true; 100 101 CoordinateSystem cs = null; 102 103 int medianFilterTrackWidth = 10; 104 int medianFilterVertWidth = 10; 105 106 public static Map<String, double[]> getEmptySubset() { 107 Map<String, double[]> subset = new HashMap<>(); 108 subset.put(trackDim_name, new double[3]); 109 subset.put(vertDim_name, new double[3]); 110 return subset; 111 } 112 113 public static Map<String, Object> getEmptyMetadataTable() { 114 Map<String, Object> metadata = new HashMap<>(); 115 metadata.put(array_name, null); 116 metadata.put(trackDim_name, null); 117 metadata.put(vertDim_name, null); 118 metadata.put(longitude_name, null); 119 metadata.put(latitude_name, null); 120 metadata.put(profileTime_name, null); 121 metadata.put(profileTime_unit, null); 122 metadata.put(altitude_unit, null); 123 metadata.put(sfcElev_name, null); 124 metadata.put(scale_name, null); 125 metadata.put(offset_name, null); 126 metadata.put(fill_value_name, null); 127 /* 128 metadata.put(range_name, null); 129 metadata.put(range_unit, null); 130 metadata.put(valid_range, null); 131 */ 132 return metadata; 133 } 134 135 public ProfileAlongTrack() { 136 } 137 138 public ProfileAlongTrack(MultiDimensionReader reader, Map<String, Object> metadata) { 139 this(reader, metadata, true); 140 } 141 142 public ProfileAlongTrack(MultiDimensionReader reader, Map<String, Object> metadata, boolean isVertDimAlt) { 143 super(reader, metadata); 144 this.isVertDimAlt = isVertDimAlt; 145 this.init(); 146 } 147 148 149 private void init() { 150 for (int k=0; k<array_rank;k++) { 151 if ( ((String)metadata.get(trackDim_name)).equals(array_dim_names[k]) ) { 152 track_idx = k; 153 } 154 if ( ((String)metadata.get(vertDim_name)).equals(array_dim_names[k]) ) { 155 vert_idx = k; 156 } 157 } 158 159 int[] lengths = new int[2]; 160 161 if (track_idx < vert_idx) { 162 domainRealTypes[0] = vert; 163 domainRealTypes[1] = track; 164 track_tup_idx = 1; 165 vert_tup_idx = 0; 166 lengths[0] = array_dim_lengths[vert_idx]; 167 lengths[1] = array_dim_lengths[track_idx]; 168 } 169 else { 170 domainRealTypes[0] = track; 171 domainRealTypes[1] = vert; 172 track_tup_idx = 0; 173 vert_tup_idx = 1; 174 lengths[0] = array_dim_lengths[track_idx]; 175 lengths[1] = array_dim_lengths[vert_idx]; 176 } 177 178 TrackLen = array_dim_lengths[track_idx]; 179 VertLen = array_dim_lengths[vert_idx]; 180 181 String rangeName = null; 182 if (metadata.get("range_name") != null) { 183 rangeName = (String)metadata.get("range_name"); 184 } 185 else { 186 rangeName = (String)metadata.get("array_name"); 187 } 188 rangeType = RealType.getRealType(rangeName, rangeUnit_s[0]); 189 190 try { 191 rangeProcessor = RangeProcessor.createRangeProcessor(reader, metadata); 192 } 193 catch (Exception e) { 194 System.out.println("RangeProcessor failed to create"); 195 e.printStackTrace(); 196 } 197 198 try { 199 if (isVertDimAlt) { 200 vertLocs = getVertBinAltitude(); 201 } 202 vertLocType = makeVertLocType(); 203 trackTimes = getTrackTimes(); 204 trackTimeType = makeTrackTimeType(); 205 trackLongitude = getTrackLongitude(); 206 trackLatitude = getTrackLatitude(); 207 } 208 catch (Exception e) { 209 System.out.println(e); 210 } 211 212 } 213 214 public int getTrackLength() { 215 return TrackLen; 216 } 217 218 public int getVertLength() { 219 return VertLen; 220 } 221 222 public int getVertIdx() { 223 return vert_idx; 224 } 225 226 public int getTrackIdx() { 227 return track_idx; 228 } 229 230 public int getVertTupIdx() { 231 return vert_tup_idx; 232 } 233 234 public int getTrackTupIdx() { 235 return track_tup_idx; 236 } 237 238 public int getMedianFilterWindowWidth() { 239 return medianFilterTrackWidth; 240 } 241 242 public int getMedianFilterWindowHeight() { 243 return medianFilterVertWidth; 244 } 245 246 public Set makeDomain(Map<String, double[]> subset) throws Exception { 247 double[] first = new double[2]; 248 double[] last = new double[2]; 249 int[] length = new int[2]; 250 251 Map<String, double[]> domainSubset = new HashMap<>(); 252 domainSubset.put(trackDim_name, subset.get(trackDim_name)); 253 domainSubset.put(vertDim_name, subset.get(vertDim_name)); 254 255 for (int kk=0; kk<2; kk++) { 256 RealType rtype = domainRealTypes[kk]; 257 double[] coords = subset.get(rtype.getName()); 258 first[kk] = coords[0]; 259 last[kk] = coords[1]; 260 length[kk] = (int) ((last[kk] - first[kk])/coords[2] + 1); 261 last[kk] = first[kk]+coords[2]*(length[kk]-1); 262 } 263 Linear2DSet domainSet = new Linear2DSet(first[0], last[0], length[0], first[1], last[1], length[1]); 264 final Linear1DSet[] lin1DSet_s = new Linear1DSet[] {domainSet.getLinear1DComponent(0), 265 domainSet.getLinear1DComponent(1)}; 266 267 float[] new_altitudes = new float[length[vert_tup_idx]]; 268 float[] new_times = new float[length[track_tup_idx]]; 269 270 int track_start = (int) first[track_tup_idx]; 271 int vert_start = (int) first[vert_tup_idx]; 272 int vert_skip = (int) (subset.get(vertDim_name))[2]; 273 int track_skip = (int) (subset.get(trackDim_name))[2]; 274 for (int k=0; k<new_altitudes.length; k++) { 275 new_altitudes[k] = vertLocs[vert_start+(k*vert_skip)]; 276 } 277 278 for (int k=0; k<new_times.length; k++) { 279 new_times[k] = trackTimes[track_start+(k*track_skip)]; 280 } 281 282 final Gridded1DSet alt_set = new Gridded1DSet(vertLocType, new float[][] {new_altitudes}, new_altitudes.length); 283 final Gridded1DSet time_set = new Gridded1DSet(trackTimeType, new float[][] {new_times}, new_times.length); 284 final float vert_offset = (float) first[vert_tup_idx]; 285 final float track_offset = (float) first[track_tup_idx]; 286 287 RealTupleType reference = new RealTupleType(vertLocType, trackTimeType); 288 289 CoordinateSystem cs = null; 290 291 try { 292 cs = new CoordinateSystem(reference, null) { 293 public float[][] toReference(float[][] vals) throws VisADException { 294 int[] indexes = lin1DSet_s[0].valueToIndex(new float[][] {vals[0]}); 295 /* ? 296 for (int k=0; k<vals[0].length;k++) { 297 indexes[k] = (int) (vals[vert_tup_idx][k] - vert_offset); 298 } 299 */ 300 float[][] alts = alt_set.indexToValue(indexes); 301 302 indexes = lin1DSet_s[1].valueToIndex(new float[][] {vals[1]}); 303 /* ? 304 for (int k=0; k<vals[0].length;k++) { 305 indexes[k] = (int) (vals[track_tup_idx][k] - track_offset); 306 } 307 */ 308 float[][] times = time_set.indexToValue(indexes); 309 310 return new float[][] {alts[0], times[0]}; 311 } 312 public float[][] fromReference(float[][] vals) throws VisADException { 313 int[] indexes = alt_set.valueToIndex(new float[][] {vals[vert_tup_idx]}); 314 float[][] vert_coords = lin1DSet_s[vert_tup_idx].indexToValue(indexes); 315 indexes = time_set.valueToIndex(new float[][] {vals[track_tup_idx]}); 316 float[][] track_coords = lin1DSet_s[track_tup_idx].indexToValue(indexes); 317 return new float[][] {vert_coords[0], track_coords[0]}; 318 } 319 public double[][] toReference(double[][] vals) throws VisADException { 320 return Set.floatToDouble(toReference(Set.doubleToFloat(vals))); 321 } 322 public double[][] fromReference(double[][] vals) throws VisADException { 323 return Set.floatToDouble(fromReference(Set.doubleToFloat(vals))); 324 } 325 public boolean equals(Object obj) { 326 return true; 327 } 328 }; 329 } 330 catch (Exception e) { 331 } 332 333 RealTupleType domainTupType = new RealTupleType(domainRealTypes[0], domainRealTypes[1], cs, null); 334 domainSet = new Linear2DSet(domainTupType, first[0], last[0], length[0], first[1], last[1], length[1]); 335 336 return domainSet; 337 } 338 339 public FunctionType getMathType() { 340 return null; 341 } 342 343 public RealType[] getDomainRealTypes() { 344 return domainRealTypes; 345 } 346 347 public Map<String, double[]> getDefaultSubset() { 348 Map<String, double[]> subset = ProfileAlongTrack.getEmptySubset(); 349 350 double[] coords = subset.get("TrackDim"); 351 coords[0] = 20000.0; 352 coords[1] = (TrackLen - 15000.0) - 1; 353 //-coords[2] = 30.0; 354 coords[2] = 5.0; 355 subset.put("TrackDim", coords); 356 357 coords = subset.get("VertDim"); 358 coords[0] = 98.0; 359 coords[1] = (VertLen) - 1; 360 coords[2] = 2.0; 361 subset.put("VertDim", coords); 362 return subset; 363 } 364 365 public int[] getTrackRangeInsideLonLatRect(double minLat, double maxLat, double minLon, double maxLon) { 366 int nn = 100; 367 int skip = TrackLen/nn; 368 double lon; 369 double lat; 370 371 int idx = 0; 372 while (idx < TrackLen) { 373 lon = (double)trackLongitude[idx]; 374 lat = (double)trackLatitude[idx]; 375 if (((lon > minLon) && (lon < maxLon)) && ((lat > minLat)&&(lat < maxLat))) break; 376 idx += skip; 377 } 378 if (idx > TrackLen-1) idx = TrackLen-1; 379 if (idx == TrackLen-1) return new int[] {-1,-1}; 380 381 int low_idx = idx; 382 while (low_idx > 0) { 383 lon = (double)trackLongitude[low_idx]; 384 lat = (double)trackLatitude[low_idx]; 385 if (((lon > minLon) && (lon < maxLon)) && ((lat > minLat)&&(lat < maxLat))) { 386 low_idx -= 1; 387 continue; 388 } 389 else { 390 break; 391 } 392 } 393 394 int hi_idx = idx; 395 while (hi_idx < TrackLen-1) { 396 lon = (double)trackLongitude[hi_idx]; 397 lat = (double)trackLatitude[hi_idx]; 398 if (((lon > minLon) && (lon < maxLon)) && ((lat > minLat)&&(lat < maxLat))) { 399 hi_idx += 1; 400 continue; 401 } 402 else { 403 break; 404 } 405 } 406 return new int[] {low_idx, hi_idx}; 407 } 408 409 public Map<String, double[]> getSubsetFromLonLatRect(Map<String, double[]> subset, double minLat, double maxLat, double minLon, double maxLon) { 410 double[] coords = subset.get("TrackDim"); 411 int[] idxs = getTrackRangeInsideLonLatRect(minLat, maxLat, minLon, maxLon); 412 coords[0] = (double) idxs[0]; 413 coords[1] = (double) idxs[1]; 414 if ((coords[0] == -1) || (coords[1] == -1)) return null; 415 return subset; 416 } 417 418 public Map<String, double[]> getSubsetFromLonLatRect(Map<String, double[]> subset, double minLat, double maxLat, double minLon, double maxLon, 419 int xStride, int yStride, int zStride) { 420 421 double[] coords = subset.get("TrackDim"); 422 int[] idxs = getTrackRangeInsideLonLatRect(minLat, maxLat, minLon, maxLon); 423 coords[0] = (double) idxs[0]; 424 coords[1] = (double) idxs[1]; 425 if ((coords[0] == -1) || (coords[1] == -1)) return null; 426 if (xStride > 0) { 427 coords[2] = xStride; 428 } 429 430 coords = subset.get("VertDim"); 431 if (yStride > 0) { 432 coords[2] = yStride; 433 } 434 return subset; 435 } 436 437 public Map<String, double[]> getSubsetFromLonLatRect(double minLat, double maxLat, double minLon, double maxLon) { 438 return getSubsetFromLonLatRect(getDefaultSubset(), minLat, maxLat, minLon, maxLon); 439 } 440 441 public Map<String, double[]> getSubsetFromLonLatRect(double minLat, double maxLat, double minLon, double maxLon, 442 int xStride, int yStride, int zStride) { 443 444 return getSubsetFromLonLatRect(getDefaultSubset(), minLat, maxLat, minLon, maxLon, xStride, yStride, zStride); 445 } 446 447 public abstract float[] getVertBinAltitude() throws Exception; 448 public abstract float[] getTrackTimes() throws Exception; 449 public abstract RealType makeVertLocType() throws Exception; 450 public abstract RealType makeTrackTimeType() throws Exception; 451 public abstract float[] getTrackLongitude() throws Exception; 452 public abstract float[] getTrackLatitude() throws Exception; 453 454 public static FieldImpl medianFilter(FieldImpl field, int window_lenx, int window_leny) throws VisADException, RemoteException, CloneNotSupportedException { 455 Set dSet = field.getDomainSet(); 456 if (dSet.getManifoldDimension() != 1) { 457 throw new VisADException("medianFilter: outer field domain must have manifoldDimension = 1"); 458 } 459 int outerLen = dSet.getLength(); 460 461 FieldImpl filtField = (FieldImpl)field.clone(); 462 463 for (int t=0; t<outerLen; t++) { 464 FlatField ff = (FlatField) filtField.getSample(t, false); 465 medianFilter(ff, window_lenx, window_leny); 466 } 467 468 return filtField; 469 } 470 471 public static FlatField medianFilter(FlatField fltFld, int window_lenx, int window_leny) throws VisADException, RemoteException { 472 GriddedSet domSet = (GriddedSet) fltFld.getDomainSet(); 473 FlatField filtFld = new FlatField((FunctionType)fltFld.getType(), domSet); 474 475 int[] lens = domSet.getLengths(); 476 int manifoldDimension = domSet.getManifoldDimension(); 477 478 float[][] rngVals = fltFld.getFloats(false); 479 int rngTupleDim = rngVals.length; 480 float[][] filtVals = new float[rngTupleDim][]; 481 482 if (manifoldDimension == 2) { 483 for (int t=0; t<rngTupleDim; t++) { 484 filtVals[t] = medianFilter(rngVals[t], lens[0], lens[1], window_lenx, window_leny); 485 } 486 } 487 else if (manifoldDimension == 3) { 488 int outerDimLen = lens[0]; 489 filtVals = new float[rngTupleDim][lens[0]*lens[1]*lens[2]]; 490 float[] rngVals2D = new float[lens[1]*lens[2]]; 491 492 for (int k = 0; k<outerDimLen; k++) { 493 int idx = k*lens[1]*lens[2]; 494 for (int t=0; t<rngTupleDim; t++) { 495 System.arraycopy(rngVals[t], idx, rngVals2D, 0, lens[1]*lens[2]); 496 497 float[] fltA = medianFilter(rngVals2D, lens[1], lens[2], window_lenx, window_leny); 498 499 System.arraycopy(fltA, 0, filtVals[t], idx, lens[1]*lens[2]); 500 } 501 } 502 } 503 504 filtFld.setSamples(filtVals, false); 505 506 return filtFld; 507 } 508 509 public static float[] medianFilter(float[] A, int lenx, int leny, int window_lenx, int window_leny) 510 throws VisADException { 511 float[] result = new float[A.length]; 512 float[] window = new float[window_lenx*window_leny]; 513 float[] sortedWindow = new float[window_lenx*window_leny]; 514 int[] sort_indexes = new int[window_lenx*window_leny]; 515 int[] indexes = new int[window_lenx*window_leny]; 516 int[] indexesB = new int[window_lenx*window_leny]; 517 518 int[] numToInsertAt = new int[window_lenx*window_leny]; 519 float[][] valsToInsert = new float[window_lenx*window_leny][window_lenx*window_leny]; 520 int[][] idxsToInsert = new int[window_lenx*window_leny][window_lenx*window_leny]; 521 522 int[] numBefore = new int[window_lenx*window_leny]; 523 float[][] valsBefore = new float[window_lenx*window_leny][window_lenx*window_leny]; 524 int[][] idxsBefore = new int[window_lenx*window_leny][window_lenx*window_leny]; 525 526 int[] numAfter = new int[window_lenx*window_leny]; 527 float[][] valsAfter = new float[window_lenx*window_leny][window_lenx*window_leny]; 528 int[][] idxsAfter = new int[window_lenx*window_leny][window_lenx*window_leny]; 529 530 float[] sortedArray = new float[window_lenx*window_leny]; 531 532 int a_idx; 533 int w_idx; 534 535 int w_lenx = window_lenx/2; 536 int w_leny = window_leny/2; 537 538 int lo; 539 int hi; 540 int ww_jj; 541 int ww_ii; 542 int cnt=0; 543 int ncnt; 544 int midx; 545 float median; 546 547 int lenA = A.length; 548 549 for (int i=0; i<lenx; i++) { // zig-zag better? Maybe, but more complicated 550 for (int j=0; j<leny; j++) { 551 a_idx = j*lenx + i; 552 553 if (j > 0) { 554 ncnt = 0; 555 for (int t=0; t<cnt; t++) { 556 // last window index in data coords: A[lenx,leny] 557 int k = indexes[sort_indexes[t]]; 558 ww_jj = k/lenx; 559 ww_ii = k % lenx; 560 561 // current window bounds in data coords 562 int ww_jj_lo = j - w_leny; 563 int ww_jj_hi = j + w_leny; 564 int ww_ii_lo = i - w_lenx; 565 int ww_ii_hi = i + w_lenx; 566 567 if (ww_jj_lo < 0) ww_jj_lo = 0; 568 if (ww_ii_lo < 0) ww_ii_lo = 0; 569 if (ww_jj_hi > leny-1) ww_jj_hi = leny-1; 570 if (ww_ii_hi > lenx-1) ww_ii_hi = lenx-1; 571 572 573 // These are the points which overlap between the last and current window 574 if ((ww_jj >= ww_jj_lo && ww_jj < ww_jj_hi) && (ww_ii >= ww_ii_lo && ww_ii < ww_ii_hi)) { 575 window[ncnt] = sortedWindow[t]; 576 indexesB[ncnt] = k; 577 ncnt++; 578 } 579 } 580 581 582 // Add the new points from sliding the window to the overlap points above 583 java.util.Arrays.fill(numToInsertAt, 0); 584 java.util.Arrays.fill(numBefore, 0); 585 java.util.Arrays.fill(numAfter, 0); 586 587 ww_jj = w_leny-1 + j; 588 for (int w_i=-w_lenx; w_i<w_lenx; w_i++) { 589 ww_ii = w_i + i; 590 int k = ww_jj*lenx+ww_ii; 591 if (k >= 0 && k < lenA) { 592 float val = A[k]; 593 if (ncnt > 0) { 594 int t = 0; 595 if (val < window[t]) { 596 valsBefore[0][numBefore[0]] = val; 597 idxsBefore[0][numBefore[0]] = k; 598 numBefore[0]++; 599 continue; 600 } 601 t = ncnt-1; 602 if (val >= window[t]) { 603 valsAfter[0][numAfter[0]] = val; 604 idxsAfter[0][numAfter[0]] = k; 605 numAfter[0]++; 606 continue; 607 } 608 609 for (t=0; t<ncnt-1; t++) { 610 if (val >= window[t] && val < window[t+1]) { 611 valsToInsert[t][numToInsertAt[t]] = val; 612 idxsToInsert[t][numToInsertAt[t]] = k; 613 numToInsertAt[t]++; 614 break; 615 } 616 } 617 } 618 else if (!Float.isNaN(val)) { 619 valsBefore[0][numBefore[0]] = val; 620 idxsBefore[0][numBefore[0]] = k; 621 numBefore[0]++; 622 continue; 623 } 624 } 625 } 626 627 // insert new unsorted values into the already sorted overlap window region 628 int tcnt = 0; 629 630 for (int it=0; it<numBefore[0]; it++) { 631 sortedArray[tcnt] = valsBefore[0][it]; 632 indexes[tcnt] = idxsBefore[0][it]; 633 tcnt++; 634 } 635 636 for (int t=0; t<ncnt; t++) { 637 sortedArray[tcnt] = window[t]; 638 indexes[tcnt] = indexesB[t]; 639 tcnt++; 640 if (numToInsertAt[t] > 0) { 641 if (numToInsertAt[t] == 2) { // two item sort here to save work for QuickSort 642 float val0 = valsToInsert[t][0]; 643 float val1 = valsToInsert[t][1]; 644 645 if (val0 <= val1) { 646 sortedArray[tcnt] = val0; 647 indexes[tcnt] = idxsToInsert[t][0]; 648 tcnt++; 649 650 sortedArray[tcnt] = val1; 651 indexes[tcnt] = idxsToInsert[t][1]; 652 tcnt++; 653 } 654 else { 655 sortedArray[tcnt] = val1; 656 indexes[tcnt] = idxsToInsert[t][1]; 657 tcnt++; 658 659 sortedArray[tcnt] = val0; 660 indexes[tcnt] = idxsToInsert[t][0]; 661 tcnt++; 662 } 663 } 664 else if (numToInsertAt[t] == 1) { 665 sortedArray[tcnt] = valsToInsert[t][0]; 666 indexes[tcnt] = idxsToInsert[t][0]; 667 tcnt++; 668 } 669 else { 670 for (int it=0; it<numToInsertAt[t]; it++) { 671 sortedArray[tcnt] = valsToInsert[t][it]; 672 indexes[tcnt] = idxsToInsert[t][it]; 673 tcnt++; 674 } 675 } 676 } 677 } 678 679 for (int it=0; it<numAfter[0]; it++) { 680 sortedArray[tcnt] = valsAfter[0][it]; 681 indexes[tcnt] = idxsAfter[0][it]; 682 tcnt++; 683 } 684 685 // Now sort the new unsorted and overlap sorted points together to get the new window median 686 687 System.arraycopy(sortedArray, 0, sortedWindow, 0, tcnt); 688 if (tcnt > 0) { 689 sort_indexes = QuickSort.sort(sortedWindow, 0, tcnt-1); 690 median = sortedWindow[tcnt/2]; 691 } 692 else { 693 median = Float.NaN; 694 } 695 cnt = tcnt; 696 697 } 698 else { // full sort done once for each row (see note on zigzag above) 699 700 cnt = 0; 701 for (int w_j=-w_leny; w_j<w_leny; w_j++) { 702 for (int w_i=-w_lenx; w_i<w_lenx; w_i++) { 703 ww_jj = w_j + j; 704 ww_ii = w_i + i; 705 w_idx = (w_j+w_leny)*window_lenx + (w_i+w_lenx); 706 if ((ww_jj >= 0) && (ww_ii >=0) && (ww_jj < leny) && (ww_ii < lenx)) { 707 int k = ww_jj*lenx+ww_ii; 708 float val = A[k]; 709 if (!Float.isNaN(val)) { 710 window[cnt] = val; 711 indexes[cnt] = k; 712 cnt++; 713 } 714 } 715 } 716 } 717 718 719 System.arraycopy(window, 0, sortedWindow, 0, cnt); 720 if (cnt > 0) { 721 sort_indexes = QuickSort.sort(sortedWindow, 0, cnt-1); 722 midx = cnt/2; 723 median = sortedWindow[midx]; 724 } 725 else { 726 median = Float.NaN; 727 } 728 729 } 730 731 if (Float.isNaN(A[a_idx])) { 732 result[a_idx] = Float.NaN; 733 } 734 else { 735 result[a_idx] = median; 736 } 737 738 } 739 } 740 741 return result; 742 } 743 744 public static float[] medianFilterOrg(float[] A, int lenx, int leny, int window_lenx, int window_leny) 745 throws VisADException { 746 float[] result = new float[A.length]; 747 float[] window = new float[window_lenx*window_leny]; 748 float[] new_window = new float[window_lenx*window_leny]; 749 int[] sort_indexes = new int[window_lenx*window_leny]; 750 751 int a_idx; 752 int w_idx; 753 754 int w_lenx = window_lenx/2; 755 int w_leny = window_leny/2; 756 757 int lo; 758 int hi; 759 int ww_jj; 760 int ww_ii; 761 int cnt; 762 763 for (int j=0; j<leny; j++) { 764 for (int i=0; i<lenx; i++) { 765 a_idx = j*lenx + i; 766 cnt = 0; 767 for (int w_j=-w_leny; w_j<w_leny; w_j++) { 768 for (int w_i=-w_lenx; w_i<w_lenx; w_i++) { 769 ww_jj = w_j + j; 770 ww_ii = w_i + i; 771 w_idx = (w_j+w_leny)*window_lenx + (w_i+w_lenx); 772 if ((ww_jj >= 0) && (ww_ii >=0) && (ww_jj < leny) && (ww_ii < lenx)) { 773 window[cnt] = A[ww_jj*lenx+ww_ii]; 774 cnt++; 775 } 776 } 777 } 778 System.arraycopy(window, 0, new_window, 0, cnt); 779 //-sort_indexes = QuickSort.sort(new_window, sort_indexes); 780 sort_indexes = QuickSort.sort(new_window); 781 result[a_idx] = new_window[cnt/2]; 782 } 783 } 784 return result; 785 } 786}