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    }