/******************************************************************************* * Copyright 2012 Geoscience Australia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package au.gov.ga.earthsci.worldwind.common.util; /** * A helper class used to calculate grid spacings etc. * * @author James Navin (james.navin@ga.gov.au) */ public class GridHelper { private static final int DEFAULT_GRID_SIZE = 20; /** A container class that holds calculated grid properties */ public static class GridProperties { /** The value of the first grid line */ private double firstGridLineValue; /** The value change per grid line */ private double valueChangePerGridLine; /** The number of decimal places the value change is accurate to */ private int numberDecimalPlaces; public GridProperties(double firstGridLineValue, double valueChangePerGridLine, int numberOfDecimalPlaces) { this.firstGridLineValue = firstGridLineValue; this.valueChangePerGridLine = valueChangePerGridLine; this.numberDecimalPlaces = numberOfDecimalPlaces; } public double getFirstGridLineValue() { return firstGridLineValue; } public double getValueChangePerGridLine() { return valueChangePerGridLine; } public int getNumberDecimalPlaces() { return numberDecimalPlaces; } @Override public String toString() { return "Grid[Start: " + firstGridLineValue + ", Value change: " + valueChangePerGridLine + ", Number decimal places: " + numberDecimalPlaces + "]"; } } /** A builder class to use for building grids */ public static class GridBuilder { private int gridSize = DEFAULT_GRID_SIZE; private Integer numPixels; private Range<Double> valueRange; public GridBuilder ofSize(int maxGridSize) { this.gridSize = maxGridSize; return this; } public GridBuilder toFitIn(int numPixels) { this.numPixels = numPixels; return this; } public GridBuilder forValueRange(Range<Double> valueRange) { this.valueRange = valueRange; return this; } public GridProperties build() { if (numPixels == null || valueRange == null) { throw new IllegalStateException("Not enough information provided to build a grid. Please use the builder methods to provide required information"); } return calculateGridProperties(); } private GridProperties calculateGridProperties() { int pixelsPerGridLine = Integer.MAX_VALUE; double valueChangePerGridLine = Math.pow(10, (int)Math.log10(valueRange.getMaxValue())+1); double valueDelta = valueRange.getMaxValue() - valueRange.getMinValue(); double[] dividers = new double[]{1, 0.5, 0.2}; int numDecimalPlaces = 0; // Incrementally decrease the value change until it falls within the grid size while (pixelsPerGridLine > gridSize) { for (double d : dividers) { double candidateValueChange = valueChangePerGridLine * d; // Adjust for the <1 dividers if (d < 1 && candidateValueChange < 1) { numDecimalPlaces++; } pixelsPerGridLine = (int)((numPixels / valueDelta) * candidateValueChange); if (pixelsPerGridLine <= gridSize) { valueChangePerGridLine = candidateValueChange; break; } if (d < 1 && candidateValueChange < 1) { numDecimalPlaces--; } } if (pixelsPerGridLine <= gridSize) { break; } valueChangePerGridLine *= 0.1; if (valueChangePerGridLine < 1) { numDecimalPlaces++; } } double start = valueRange.getMinValue(); double floor = Math.floor(start / valueChangePerGridLine); double firstGridLineValue = valueChangePerGridLine * floor; return new GridProperties(firstGridLineValue, valueChangePerGridLine, numDecimalPlaces); } } /** Use the builder methods to create grids */ private GridHelper(){} public static GridBuilder createGrid() { return new GridBuilder(); } }