001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2022, by David Gilbert. All rights reserved. 006 * 007 * https://github.com/jfree/orson-charts 008 * 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation, either version 3 of the License, or 012 * (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 023 * Other names may be trademarks of their respective owners.] 024 * 025 * If you do not wish to be bound by the terms of the GPL, an alternative 026 * commercial license can be purchased. For details, please see visit the 027 * Orson Charts home page: 028 * 029 * http://www.object-refinery.com/orsoncharts/index.html 030 * 031 */ 032 033package org.jfree.chart3d.axis; 034 035import java.io.Serializable; 036import java.text.DecimalFormat; 037import java.text.Format; 038import org.jfree.chart3d.internal.Args; 039 040/** 041 * A {@link TickSelector} implementation that selects tick units in multiples 042 * of 1, 2 and 5 and only displays integer values. 043 * <br><br> 044 * NOTE: This class is serializable, but the serialization format is subject 045 * to change in future releases and should not be relied upon for persisting 046 * instances of this class. 047 * 048 * @since 1.5 049 */ 050@SuppressWarnings("serial") 051public class IntegerTickSelector implements TickSelector, Serializable { 052 053 private int power = 0; 054 055 private int factor = 1; 056 057 /** 058 * Creates a new instance. 059 */ 060 public IntegerTickSelector() { 061 this.power = 0; 062 this.factor = 1; 063 } 064 065 /** 066 * Selects and returns a standard tick size that is greater than or equal to 067 * the specified reference value and, ideally, as close to it as possible 068 * (to minimise the number of iterations used by axes to determine the tick 069 * size to use). After a call to this method, the 070 * {@link #getCurrentTickSize()} method should return the selected tick 071 * size (there is a "pointer" to this tick size), the {@link #next()} 072 * method should move the pointer to the next (larger) standard tick size, 073 * and the {@link #previous()} method should move the pointer to the 074 * previous (smaller) standard tick size. 075 * 076 * @param reference the reference value (must be positive and finite). 077 * 078 * @return The selected tick size. 079 */ 080 @Override 081 public double select(double reference) { 082 Args.finitePositiveRequired(reference, "reference"); 083 this.power = (int) Math.ceil(Math.log10(reference)); 084 this.factor = 1; 085 return getCurrentTickSize(); 086 } 087 088 /** 089 * Move the cursor to the next (larger) tick size, if there is one. 090 * Returns {@code true} in the case that the cursor is moved, and 091 * {@code false} where there are a finite number of tick sizes and the 092 * current tick size is the largest available. 093 */ 094 @Override 095 public boolean next() { 096 if (factor == 1) { 097 factor = 2; 098 return true; 099 } 100 if (factor == 2) { 101 factor = 5; 102 return true; 103 } 104 if (factor == 5) { 105 power++; 106 factor = 1; 107 return true; 108 } 109 throw new IllegalStateException("We should never get here."); 110 } 111 112 /** 113 * Move the cursor to the previous (smaller) tick size, if there is one. 114 * Returns {@code true} in the case that the cursor is moved, and 115 * {@code false} where there are a finite number of tick sizes and the 116 * current tick size is the smallest available. 117 */ 118 @Override 119 public boolean previous() { 120 if (factor == 1) { 121 if (power == 0) { 122 return false; 123 } 124 factor = 5; 125 power--; 126 return true; 127 } 128 if (factor == 2) { 129 factor = 1; 130 return true; 131 } 132 if (factor == 5) { 133 factor = 2; 134 return true; 135 } 136 throw new IllegalStateException("We should never get here."); 137 } 138 139 @Override 140 public double getCurrentTickSize() { 141 return this.factor * Math.pow(10.0, this.power); 142 } 143 144 private final DecimalFormat df0 = new DecimalFormat("#,##0"); 145 146 @Override 147 public Format getCurrentTickLabelFormat() { 148 if (power >= 0 && power <= 6) { 149 return df0; 150 } 151 return new DecimalFormat("0.0000E0"); 152 } 153 154 /** 155 * Tests this instance for equality with an arbitrary object. 156 * 157 * @param obj the object ({@code null} permitted). 158 * 159 * @return A boolean. 160 */ 161 @Override 162 public boolean equals(Object obj) { 163 if (obj == this) { 164 return true; 165 } 166 if (!(obj instanceof IntegerTickSelector)) { 167 return false; 168 } 169 return true; 170 } 171 172}