/******************************************************************************* * Mission Control Technologies, Copyright (c) 2009-2012, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * * The MCT platform is 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. * * MCT includes source code licensed under additional open source licenses. See * the MCT Open Source Licenses file included with this distribution or the About * MCT Licenses dialog available at runtime from the MCT Help menu for additional * information. *******************************************************************************/ package plotter; import java.util.Arrays; /** * Implementation of {@link TickMarkCalculator} for time axes. * @author Adam Crume */ public class TimeTickMarkCalculator implements TickMarkCalculator { private static final long MINUTE = 60 * 1000; private static final long HOUR = 60 * MINUTE; private static final long DAY = 24 * HOUR; @Override public double[][] calculateTickMarks(Axis axis) { double start = axis.getStart(); double end = axis.getEnd(); double min = start; double max = end; if(min > max) { double tmp = max; max = min; min = tmp; } double diff = max - min; double spacing; double spacing2; // TODO: Clean this up if(diff > 2 * DAY) { double days = diff / DAY; // d should be days scaled to between 1 and 10 double d = days / Math.pow(10, Math.floor(Math.log10(days))); double adj; if(d < 2) { d *= 2; adj = .2; } else if(d > 5) { d *= .5; adj = .5; } else { adj = .5; } spacing = DAY * days / d; spacing2 = spacing * adj; } else if(diff > 2 * HOUR) { double hours = diff / HOUR; if(hours > 24) { spacing = 12 * HOUR; spacing2 = 6 * HOUR; } else if(hours > 12) { spacing = 6 * HOUR; spacing2 = 2 * HOUR; } else { spacing = 2 * HOUR; spacing2 = HOUR; } } else if(diff > 2 * MINUTE) { double minutes = diff / MINUTE; if(minutes > 60) { spacing = 30 * MINUTE; spacing2 = 10 * MINUTE; } else if(minutes > 30) { spacing = 15 * MINUTE; spacing2 = 5 * MINUTE; } else if(minutes > 20) { spacing = 10 * MINUTE; spacing2 = 5 * MINUTE; } else if(minutes > 10) { spacing = 5 * MINUTE; spacing2 = MINUTE; } else { spacing = 2 * MINUTE; spacing2 = MINUTE; } } else if(diff > 2 * 1000) { double seconds = diff / 1000; if(seconds > 60) { spacing = 30 * 1000; spacing2 = 10 * 1000; } else if(seconds > 30) { spacing = 15 * 1000; spacing2 = 5 * 1000; } else if(seconds > 20) { spacing = 10 * 1000; spacing2 = 5 * 1000; } else if(seconds > 10) { spacing = 5 * 1000; spacing2 = 1000; } else { spacing = 2000; spacing2 = 1000; } } else { // d should be diff scaled to between 1 and 10 double d = diff / Math.pow(10, Math.floor(Math.log10(diff))); double adj; if(d < 2) { d *= 2; adj = .2; } else if(d > 5) { d /= 2; adj = .5; } else { adj = .5; } spacing = diff / d; spacing2 = spacing * adj; } double[] majorVals; double[] minorVals; if(min >= 0) { // In this case, both ends of the axis are non-negative. Go from min to max. double startCount = Math.ceil(min / spacing); double endCount = Math.floor(max / spacing); majorVals = new double[(int)(endCount - startCount) + 1]; double value = startCount * spacing; for(int i = 0; i < majorVals.length; i++) { majorVals[i] = value; value += spacing; } startCount = Math.ceil(min / spacing2); endCount = Math.floor(max / spacing2); minorVals = new double[(int) (endCount - startCount) + 1]; value = startCount * spacing2; for(int i = 0; i < minorVals.length; i++) { minorVals[i] = value; value += spacing2; } } else if(max <= 0) { // In this case, both ends of the axis are non-positive. Go from max to min. double startCount = Math.floor(max / spacing); double endCount = Math.ceil(min / spacing); majorVals = new double[(int) (startCount - endCount) + 1]; double value = startCount * spacing; for(int i = 0; i < majorVals.length; i++) { majorVals[i] = value; value -= spacing; } startCount = Math.floor(max / spacing2); endCount = Math.ceil(min / spacing2); minorVals = new double[(int) (startCount - endCount) + 1]; value = startCount * spacing2; for(int i = 0; i < minorVals.length; i++) { minorVals[i] = value; value -= spacing2; } } else { // In this case, one end is positive and one is negative. // Start from 0 and go in both directions to minimize rounding error. // Calculate the number of major ticks. There should be a better way. int majorCount = 0; double value = 0; while(value <= max) { value += spacing; majorCount++; } value = -spacing; while(value >= min) { value -= spacing; majorCount++; } majorVals = new double[majorCount]; value = 0; int i = 0; while(value <= max) { majorVals[i] = value; i++; value += spacing; } value = -spacing; while(value >= min) { majorVals[i] = value; i++; value -= spacing; } // Calculate the number of minor ticks. There should be a better way. int minorCount = 0; value = 0; while(value <= max) { value += spacing2; minorCount++; } value = -spacing2; while(value >= min) { value -= spacing2; minorCount++; } minorVals = new double[minorCount]; value = 0; i = 0; while(value <= max) { minorVals[i] = value; i++; value += spacing2; } value = -spacing2; while(value >= min) { minorVals[i] = value; i++; value -= spacing2; } } Arrays.sort(majorVals); return new double[][] {majorVals, minorVals}; } }