PageRenderTime 23ms CodeModel.GetById 12ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/webportal/src/main/java/org/ala/spatial/data/LegendEqualArea.java

http://alageospatialportal.googlecode.com/
Java | 151 lines | 99 code | 20 blank | 32 comment | 39 complexity | 33e1e4c29f4a5c2aa83266d2f6dd85c1 MD5 | raw file
  1/*
  2 * To change this template, choose Tools | Templates
  3 * and open the template in the editor.
  4 */
  5package org.ala.spatial.data;
  6
  7import java.util.ArrayList;
  8
  9/**
 10 * generates legend using equal size of unique values in
 11 * each catagory.
 12 * 
 13 * @author Adam
 14 */
 15public class LegendEqualArea extends Legend {
 16
 17    @Override
 18    public void generate(double[] d, int divisions) {
 19        init(d, divisions);
 20        if (Double.isNaN(max)) {
 21            return;
 22        }
 23        cutoffs = new double[divisions];
 24
 25        double scaling = 1;
 26        int direction = 0;
 27        int pos = 0;
 28        while (true) {
 29            //calculate step based on remaining info
 30            int step = (int) (Math.ceil(numberOfRecords / (double) divisions) * scaling);
 31
 32            //determine if any 'unique values' require their own division
 33            ArrayList<Double> highFrequencyValues = getValuesByFrequency(d, step);
 34
 35            int count = 0;
 36            pos = 0;
 37            int i = 0;
 38            for (i = 0; i < lastValue && pos < divisions; i++) {
 39                if (count >= step
 40                        || (i + 1 < lastValue && highFrequencyValues.contains(d[i + 1]))
 41                        || highFrequencyValues.contains(d[i])
 42                        || i == lastValue - 1) {
 43                    while (i + 1 < lastValue && d[i] == d[i + 1]) {
 44                        i++;
 45                        count++;
 46                    }
 47                    if (i < lastValue) {
 48                        cutoffs[pos] = d[i];
 49                    } else {
 50                        break;
 51                    }
 52
 53                    pos++;
 54
 55                    //update step based on remaining info
 56                    step = (int) (Math.ceil((numberOfRecords - i) / (double) (divisions - pos)) * scaling);
 57
 58                    count = 0;
 59                }
 60
 61                count++;
 62            }
 63
 64            if (i != lastValue && direction >= 0) {
 65                //too many divisions, make step larger
 66                scaling *= 1.2;
 67                direction = 1;
 68            } else if (pos < divisions && numberOfUniqueValues > divisions
 69                    && direction <= 0) {
 70                //too few divisions, make step smaller
 71                scaling /= 1.2;
 72                direction = -1;
 73            } else {
 74                break;
 75            }
 76        }
 77
 78        stretch(cutoffs, divisions, pos);
 79
 80        //force top
 81        cutoffs[cutoffs.length - 1] = max;
 82    }
 83
 84    @Override
 85    public String getTypeName() {
 86        return "Equal Area";
 87    }
 88
 89    private void stretch(double[] cutoffs, int divisions, int pos) {
 90        if (pos < divisions && pos > 0) {
 91            //add spacing
 92            double step = divisions / (divisions - pos + 1.0);
 93            for (int i = 1; i < divisions - pos + 1; i++) {
 94                int min = (int) Math.round(i * step);
 95                for (int j = divisions - 1; j >= min; j--) {
 96                    cutoffs[j] = cutoffs[j - 1];
 97                }
 98            }
 99
100            //compensate for '<' method by halving the size of cutoff spans of the same value
101//            int start = 1;
102//            for (int i = 1; i < divisions; i++) {
103//                if (cutoffs[i] != cutoffs[i - 1] && (i - start) > 1) {
104//                    int mid = (i - start) / 2 + start;
105//
106//                    //fill up with the lower value
107//                    for (int j = start; j < mid; j++) {
108//                        cutoffs[j] = cutoffs[j - 1];
109//                    }
110//
111//                    start = i;
112//                }
113//            }
114
115            //set unqiue end
116            if (cutoffs[divisions - 1] == cutoffs[divisions - 2]) {
117                for (int i = divisions - 1; i > 0; i--) {
118                    if (cutoffs[i] != cutoffs[i - 1]) {
119                        for (int j = i; j < divisions - 1; j++) {
120                            cutoffs[j] = cutoffs[j - 1];
121                        }
122                        break;
123                    }
124                }
125            }
126        }
127    }
128
129    private ArrayList<Double> getValuesByFrequency(double[] d, int step) {
130        int[] uniqueValueDistribution = new int[numberOfUniqueValues];
131        double[] uniqueValues = new double[numberOfUniqueValues];
132        int p = 0;
133        uniqueValues[0] = d[0];
134        for (int i = 0; i < lastValue; i++) {
135            if (i > 0 && d[i] != d[i - 1]) {
136                p++;
137                uniqueValues[p] = d[i];
138            }
139            uniqueValueDistribution[p]++;
140        }
141
142        ArrayList<Double> list = new ArrayList<Double>();
143        for (int i = 0; i < numberOfUniqueValues; i++) {
144            if (uniqueValueDistribution[i] >= step) {
145                list.add(uniqueValues[i]);
146            }
147        }
148
149        return list;
150    }
151}