PageRenderTime 31ms CodeModel.GetById 17ms app.highlight 11ms RepoModel.GetById 0ms app.codeStats 0ms

/alaspatial/src/main/java/org/ala/spatial/analysis/legend/LegendEqualArea.java

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