001 /*
002 * $Id: HistogramField.java,v 1.11 2012/02/19 17:35:40 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2012
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 *
012 * All Rights Reserved
013 *
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.
016 *
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 *
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025 * GNU Lesser Public License for more details.
026 *
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program. If not, see http://www.gnu.org/licenses.
029 */
030 package edu.wisc.ssec.mcidasv.data.hydra;
031
032 import visad.*;
033
034 public class HistogramField {
035
036 Linear2DSet histSet;
037 Linear1DSet set0;
038 Linear1DSet set1;
039 int len0;
040 int len1;
041 int[] count;
042 int[][] indexes;
043 FlatField field_0;
044 FlatField field_1;
045 FlatField mask_field;
046 float[][] maskRange;
047 Class rangeType;
048
049 public HistogramField(FlatField field_0, FlatField field_1,
050 FlatField mask_field,
051 int n_bins, int bin_size)
052 throws Exception {
053 this.field_0 = field_0;
054 this.field_1 = field_1;
055 this.mask_field = mask_field;
056 maskRange = mask_field.getFloats(false);
057
058 Set[] rangeSets = field_0.getRangeSets();
059 Set rngSet = rangeSets[0];
060
061 if (rngSet instanceof FloatSet) {
062 rangeType = Float.TYPE;
063 } else if (rngSet instanceof DoubleSet) {
064 rangeType = Double.TYPE;
065 } else if (rngSet instanceof IntegerSet) {
066 rangeType = Integer.TYPE;
067 }
068
069 double[] minmax_0 = {Double.MAX_VALUE, -Double.MAX_VALUE};
070 double[] minmax_1 = {Double.MAX_VALUE, -Double.MAX_VALUE};
071
072
073 if (rangeType == Integer.TYPE) {
074 //Ghansham: Dont do any allocation here. Do based on the individual ranges of fieldX and fieldY respectively
075 } else {
076 indexes = new int[n_bins * n_bins][bin_size];
077 count = new int[n_bins * n_bins];
078 }
079
080
081 double[][] val = new double[2][1];
082 int[] histIdx = null;
083
084 if (rangeType == Double.TYPE) {
085 double[][] vals_0 = field_0.getValues(false);
086 double[][] vals_1 = field_1.getValues(false);
087 int n_samples = vals_0[0].length;
088 for (int k = 0; k < n_samples; k++) {
089 double v0 = vals_0[0][k];
090 if (v0 < minmax_0[0]) {
091 minmax_0[0] = v0;
092 } else if (v0 > minmax_0[1]) {
093 minmax_0[1] = v0;
094 }
095
096 double v1 = vals_1[0][k];
097 if (v1 < minmax_1[0]) {
098 minmax_1[0] = v1;
099 } else if (v1 > minmax_1[1]) {
100 minmax_1[1] = v1;
101 }
102 }
103
104 histSet = new Linear2DSet(minmax_0[0], minmax_0[1], n_bins,
105 minmax_1[0], minmax_1[1], n_bins);
106
107 for (int k = 0; k < n_samples; k++) {
108 val[0][0] = vals_0[0][k];
109 val[1][0] = vals_1[0][k];
110 histIdx = histSet.doubleToIndex(val);
111 if (histIdx[0] >= 0) {
112 int len = indexes[histIdx[0]].length;
113 if (count[histIdx[0]] > len - 1) { //-grow array
114 int[] tmp = new int[len + bin_size];
115 System.arraycopy(indexes[histIdx[0]], 0, tmp, 0, len);
116 indexes[histIdx[0]] = tmp;
117 }
118 indexes[histIdx[0]][count[histIdx[0]]++] = k;
119 }
120 }
121 } else if (rangeType == Float.TYPE) {
122 float[][] vals_0 = field_0.getFloats(false);
123 float[][] vals_1 = field_1.getFloats(false);
124 int n_samples = vals_0[0].length;
125 for (int k = 0; k < n_samples; k++) {
126 double v0 = vals_0[0][k];
127 if (v0 < minmax_0[0]) {
128 minmax_0[0] = v0;
129 } else if (v0 > minmax_0[1]) {
130 minmax_0[1] = v0;
131 }
132 double v1 = vals_1[0][k];
133 if (v1 < minmax_1[0]) {
134 minmax_1[0] = v1;
135 } else if (v1 > minmax_1[1]) {
136 minmax_1[1] = v1;
137 }
138
139 }
140 histSet = new Linear2DSet(minmax_0[0], minmax_0[1], n_bins, minmax_1[0], minmax_1[1], n_bins);
141 for (int k = 0; k < n_samples; k++) {
142 val[0][0] = vals_0[0][k];
143 val[1][0] = vals_1[0][k];
144 histIdx = histSet.doubleToIndex(val);
145 if (histIdx[0] >= 0) {
146 int len = indexes[histIdx[0]].length;
147 if (count[histIdx[0]] > len - 1) { //-grow array
148
149 int[] tmp = new int[len + bin_size];
150 System.arraycopy(indexes[histIdx[0]], 0, tmp, 0, len);
151 indexes[histIdx[0]] = tmp;
152 }
153 indexes[histIdx[0]][count[histIdx[0]]++] = k;
154 }
155 }
156 } else if (rangeType == Integer.TYPE) {
157 float[][] vals_0 = field_0.getFloats(false);
158 float[][] vals_1 = field_1.getFloats(false);
159 int n_samples = vals_0[0].length;
160 for (int k = 0; k < n_samples; k++) {
161 double v0 = vals_0[0][k];
162 if (v0 < minmax_0[0]) {
163 minmax_0[0] = v0;
164 } else if (v0 > minmax_0[1]) {
165 minmax_0[1] = v0;
166 }
167 double v1 = vals_1[0][k];
168 if (v1 < minmax_1[0]) {
169 minmax_1[0] = v1;
170 } else if (v1 > minmax_1[1]) {
171 minmax_1[1] = v1;
172 }
173 }
174
175
176 int startX = (int) minmax_0[0];
177 int endX = (int) minmax_0[1];
178 int startY = (int) minmax_1[0];
179 int endY = (int) minmax_1[1];
180 int lenX = endX - startX + 1;
181 int lenY = endY - startY + 1;
182 histSet = new Linear2DSet(startX, endX, lenX, startY, endY, lenY);
183
184
185
186 //Ghansham:Allocate here based on length of lenghts of XField and YField
187 indexes = new int[lenY * lenX][]; //Ghansham:Dont allocate here if not required.
188 count = new int[lenY * lenX];
189
190 //First calculate frequency of each grey count.
191 for (int k = 0; k < n_samples; k++) {
192 val[0][0] = vals_0[0][k];
193 val[1][0] = vals_1[0][k];
194 histIdx = histSet.doubleToIndex(val);
195 if (histIdx[0] >= 0) {
196 count[histIdx[0]]++;
197 }
198 }
199
200 for (int k = 0; k < n_samples; k++) {
201 val[0][0] = vals_0[0][k];
202 val[1][0] = vals_1[0][k];
203 histIdx = histSet.doubleToIndex(val);
204 if (histIdx[0] >= 0) {
205 if (indexes[histIdx[0]] == null) { //Tricky stuff is here: encountering a particular grey count first time.
206 indexes[histIdx[0]] = new int[count[histIdx[0]]]; //Allocating the values based on the frequency of this grey count (calculate earlier). No extra allocation at all
207 count[histIdx[0]] = 0; //Resetting the frequency to 0.
208 }
209 indexes[histIdx[0]][count[histIdx[0]]++] = k;
210 }
211 }
212 }
213
214
215 set0 = histSet.getLinear1DComponent(0);
216 set1 = histSet.getLinear1DComponent(1);
217 len0 = set0.getLength();
218 len1 = set1.getLength();
219 }
220
221 public void markMaskFieldByRange(double[] lowhi_0, double[] lowhi_1, float maskVal)
222 throws Exception {
223
224 int[] hist0 = set0.doubleToIndex(new double[][] {{lowhi_0[0], lowhi_0[1]}});
225 int[] hist1 = set1.doubleToIndex(new double[][] {{lowhi_1[0], lowhi_1[1]}});
226
227 if (hist0[0] < 0) {
228 if (lowhi_0[0] < lowhi_0[1]) {
229 hist0[0] = 0;
230 } else {
231 hist0[0] = len0 - 1;
232 }
233 }
234 if (hist0[1] < 0) {
235 if (lowhi_0[0] < lowhi_0[1]) {
236 hist0[1] = len0 - 1;
237 } else {
238 hist0[1] = 0;
239 }
240 }
241
242 if (hist1[0] < 0) {
243 if (lowhi_1[0] < lowhi_1[1]) {
244 hist1[0] = 0;
245 } else {
246 hist1[0] = len1 - 1;
247 }
248 }
249 if (hist1[1] < 0) {
250 if (lowhi_1[0] < lowhi_1[1]) {
251 hist1[1] = len1 - 1;
252 } else {
253 hist1[1] = 0;
254 }
255 }
256
257 int h00, h01, h10, h11;
258
259
260 h10 = hist1[1];
261 h11 = hist1[0];
262 if (hist1[0] < hist1[1]) {
263 h10 = hist1[0];
264 h11 = hist1[1];
265 }
266
267 h00 = hist0[1];
268 h01 = hist0[0];
269 if (hist0[0] < hist0[1]) {
270 h00 = hist0[0];
271 h01 = hist0[1];
272 }
273
274 for (int k = 0; k < maskRange[0].length; k++) {
275 if (maskRange[0][k] == maskVal) {
276 maskRange[0][k] = Float.NaN;
277 }
278 }
279
280
281
282 int lenX = set0.getLengthX();
283
284 for (int j = h10; j <= h11; j++) {
285 int col_factor = j * lenX;
286 for (int i = h00; i <= h01; i++) {
287 int idx = col_factor + i;
288 for (int k = 0; k < count[idx]; k++) {
289 maskRange[0][indexes[idx][k]] = maskVal;
290 }
291 }
292 }
293
294 mask_field.setSamples(maskRange, false);
295 }
296
297 public void markMaskFieldByCurve(float[][] curve, float maskVal) throws Exception {
298 float[][] samples0 = set0.getSamples();
299 float[][] samples1 = set1.getSamples();
300
301 boolean[][] checked = null;
302 boolean[][] inside = null;
303
304
305 if (rangeType == Integer.TYPE) { //Dealing with rangeSet constructed fields separately.
306 float[][] vals_0 = field_0.getFloats(false);
307 float[][] vals_1 = field_1.getFloats(false);
308 int lenX = set0.getLength();
309 int lenY = set1.getLength();
310 checked = new boolean[lenX][lenY];
311 inside = new boolean[lenX][lenY];
312 for (int jj = 0; jj < lenX; jj++) {
313 java.util.Arrays.fill(checked[jj], false);
314 java.util.Arrays.fill(inside[jj], false);
315 }
316 for (int jj = 0; jj < lenY - 1; jj++) {
317 for (int ii = 0; ii < lenX - 1; ii++) {
318 int idx = jj * lenX + ii; //Calclualting the index value in the start only.
319 if (count[idx] > 0) { //No need to do go further if the frequency of particular grey count is zero.
320 int inside_cnt = 0;
321 if (!checked[ii][jj]) {
322 float x = samples0[0][ii];
323 float y = samples1[0][jj];
324 if (DelaunayCustom.inside(curve, x, y)) {
325 inside_cnt++;
326 inside[ii][jj] = true;
327 }
328 checked[ii][jj] = true;
329 } else if (inside[ii][jj]) {
330 inside_cnt++;
331 }
332
333 if (!checked[ii + 1][jj]) {
334 float x = samples0[0][ii + 1];
335 float y = samples1[0][jj];
336 if (DelaunayCustom.inside(curve, x, y)) {
337 inside_cnt++;
338 inside[ii + 1][jj] = true;
339 }
340 checked[ii + 1][jj] = true;
341 } else if (inside[ii + 1][jj]) {
342 inside_cnt++;
343 }
344
345 if (!checked[ii][jj + 1]) {
346 float x = samples0[0][ii];
347 float y = samples1[0][jj + 1];
348 if (DelaunayCustom.inside(curve, x, y)) {
349 inside_cnt++;
350 inside[ii][jj + 1] = true;
351 }
352 checked[ii][jj + 1] = true;
353 } else if (inside[ii][jj + 1]) {
354 inside_cnt++;
355 }
356
357 if (!checked[ii + 1][jj + 1]) {
358 float x = samples0[0][ii + 1];
359 float y = samples1[0][jj + 1];
360 if (DelaunayCustom.inside(curve, x, y)) {
361 inside_cnt++;
362 inside[ii + 1][jj + 1] = true;
363 }
364 checked[ii + 1][jj + 1] = true;
365 } else if (inside[ii + 1][jj + 1]) {
366 inside_cnt++;
367 }
368
369 if (inside_cnt == 0) {
370 continue;
371 } else if (inside_cnt == 4) {
372 for (int k = 0; k < count[idx]; k++) {
373 maskRange[0][indexes[idx][k]] = maskVal;
374 }
375 } else if (inside_cnt > 0 && inside_cnt < 4) {
376 for (int k = 0; k < count[idx]; k++) {
377 float xx = vals_0[0][indexes[idx][k]];
378 float yy = vals_1[0][indexes[idx][k]];
379 if (DelaunayCustom.inside(curve, xx, yy)) {
380 maskRange[0][indexes[idx][k]] = maskVal;
381 }
382 }
383 }
384 }
385 }
386 }
387 } else {
388 int len = set0.getLength();
389 checked = new boolean[len][len];
390 inside = new boolean[len][len];
391 for (int jj = 0; jj < len; jj++) {
392 java.util.Arrays.fill(checked[jj], false);
393 java.util.Arrays.fill(inside[jj], false);
394 }
395 for (int jj = 0; jj < len - 1; jj++) {
396 for (int ii = 0; ii < len - 1; ii++) {
397 int idx = jj * set0.getLengthX() + ii; //Calclualting the index value in the start only.
398 if (count[idx] > 0) { //No need to do go further if the frequency of particular value is zero.
399 int inside_cnt = 0;
400 if (!checked[ii][jj]) {
401 float x = samples0[0][ii];
402 float y = samples1[0][jj];
403 if (DelaunayCustom.inside(curve, x, y)) {
404 inside_cnt++;
405 inside[ii][jj] = true;
406 }
407 checked[ii][jj] = true;
408 } else if (inside[ii][jj]) {
409 inside_cnt++;
410 }
411
412 if (!checked[ii + 1][jj]) {
413 float x = samples0[0][ii + 1];
414 float y = samples1[0][jj];
415 if (DelaunayCustom.inside(curve, x, y)) {
416 inside_cnt++;
417 inside[ii + 1][jj] = true;
418 }
419 checked[ii + 1][jj] = true;
420 } else if (inside[ii + 1][jj]) {
421 inside_cnt++;
422 }
423
424 if (!checked[ii][jj + 1]) {
425 float x = samples0[0][ii];
426 float y = samples1[0][jj + 1];
427 if (DelaunayCustom.inside(curve, x, y)) {
428 inside_cnt++;
429 inside[ii][jj + 1] = true;
430 }
431 checked[ii][jj + 1] = true;
432 } else if (inside[ii][jj + 1]) {
433 inside_cnt++;
434 }
435
436 if (!checked[ii + 1][jj + 1]) {
437 float x = samples0[0][ii + 1];
438 float y = samples1[0][jj + 1];
439 if (DelaunayCustom.inside(curve, x, y)) {
440 inside_cnt++;
441 inside[ii + 1][jj + 1] = true;
442 }
443 checked[ii + 1][jj + 1] = true;
444 } else if (inside[ii + 1][jj + 1]) {
445 inside_cnt++;
446 }
447 if (inside_cnt == 0) {
448 continue;
449 }
450
451 if (rangeType == Float.TYPE) {
452 float[][] vals_0 = field_0.getFloats(false);
453 float[][] vals_1 = field_1.getFloats(false);
454 if (inside_cnt == 4) {
455
456 for (int k = 0; k < count[idx]; k++) {
457 maskRange[0][indexes[idx][k]] = maskVal;
458 }
459 }
460 if (inside_cnt > 0 && inside_cnt < 4) {
461
462 for (int k = 0; k < count[idx]; k++) {
463 float xx = vals_0[0][indexes[idx][k]];
464 float yy = vals_1[0][indexes[idx][k]];
465 if (DelaunayCustom.inside(curve, xx, yy)) {
466 maskRange[0][indexes[idx][k]] = maskVal;
467 }
468 }
469 }
470 } else if (rangeType == Double.TYPE) {
471 double[][] vals_0 = field_0.getValues(false);
472 double[][] vals_1 = field_1.getValues(false);
473 if (inside_cnt == 4) {
474 for (int k = 0; k < count[idx]; k++) {
475 maskRange[0][indexes[idx][k]] = maskVal;
476 }
477 }
478 if (inside_cnt > 0 && inside_cnt < 4) {
479
480 for (int k = 0; k < count[idx]; k++) {
481 double xx = vals_0[0][indexes[idx][k]];
482 double yy = vals_1[0][indexes[idx][k]];
483 if (DelaunayCustom.inside(curve, (float) xx, (float) yy)) {
484 maskRange[0][indexes[idx][k]] = maskVal;
485 }
486 }
487 }
488 }
489 }
490 }
491 }
492 }
493
494 mask_field.setSamples(maskRange, false);
495 }
496
497 public void clearMaskField(float maskVal) {
498 for (int k = 0; k < maskRange[0].length; k++) {
499 if (maskRange[0][k] == maskVal) {
500 maskRange[0][k] = Float.NaN;
501 }
502 }
503 }
504
505 public void resetMaskField(float maskVal) throws Exception {
506 clearMaskField(maskVal);
507 mask_field.setSamples(maskRange, false);
508 }
509 }