001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2020, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * --------------
028 * LogFormat.java
029 * --------------
030 * (C) Copyright 2007-2020, by Object Refinery Limited and Contributors.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 */
036
037package org.jfree.chart.util;
038
039import java.text.DecimalFormat;
040import java.text.FieldPosition;
041import java.text.NumberFormat;
042import java.text.ParsePosition;
043
044/**
045 * A number formatter for logarithmic values.  This formatter does not support
046 * parsing.
047 *
048 * @since 1.0.7
049 */
050public class LogFormat extends NumberFormat {
051
052    /** The log base value. */
053    private double base;
054
055    /** The natural logarithm of the base value. */
056    private double baseLog;
057
058    /** The label for the log base (for example, "e"). */
059    private String baseLabel;
060
061    /**
062     * The label for the power symbol.
063     *
064     * @since 1.0.10
065     */
066    private String powerLabel;
067
068    /** A flag that controls whether or not the base is shown. */
069    private boolean showBase;
070
071    /** The number formatter for the exponent. */
072    private NumberFormat formatter = new DecimalFormat("0.0#");
073
074    /**
075     * Creates a new instance using base 10.
076     *
077     * @since 1.0.13
078     */
079    public LogFormat() {
080        this(10.0, "10", true);
081    }
082
083    /**
084     * Creates a new instance.
085     *
086     * @param base  the base.
087     * @param baseLabel  the base label ({@code null} not permitted).
088     * @param showBase  a flag that controls whether or not the base value is
089     *                  shown.
090     */
091    public LogFormat(double base, String baseLabel, boolean showBase) {
092        this(base, baseLabel, "^", showBase);
093    }
094
095    /**
096     * Creates a new instance.
097     *
098     * @param base  the base.
099     * @param baseLabel  the base label ({@code null} not permitted).
100     * @param powerLabel  the power label ({@code null} not permitted).
101     * @param showBase  a flag that controls whether or not the base value is
102     *                  shown.
103     *
104     * @since 1.0.10
105     */
106    public LogFormat(double base, String baseLabel, String powerLabel,
107            boolean showBase) {
108        Args.nullNotPermitted(baseLabel, "baseLabel");
109        Args.nullNotPermitted(powerLabel, "powerLabel");
110        this.base = base;
111        this.baseLog = Math.log(this.base);
112        this.baseLabel = baseLabel;
113        this.showBase = showBase;
114        this.powerLabel = powerLabel;
115    }
116
117    /**
118     * Returns the number format used for the exponent.
119     *
120     * @return The number format (never {@code null}).
121     *
122     * @since 1.0.13.
123     */
124    public NumberFormat getExponentFormat() {
125        return (NumberFormat) this.formatter.clone();
126    }
127
128    /**
129     * Sets the number format used for the exponent.
130     *
131     * @param format  the formatter ({@code null} not permitted).
132     *
133     * @since 1.0.13
134     */
135    public void setExponentFormat(NumberFormat format) {
136        Args.nullNotPermitted(format, "format");
137        this.formatter = format;
138    }
139
140    /**
141     * Calculates the log of a given value.
142     *
143     * @param value  the value.
144     *
145     * @return The log of the value.
146     */
147    private double calculateLog(double value) {
148        return Math.log(value) / this.baseLog;
149    }
150
151    /**
152     * Returns a formatted representation of the specified number.
153     *
154     * @param number  the number.
155     * @param toAppendTo  the string buffer to append to.
156     * @param pos  the position.
157     *
158     * @return A string buffer containing the formatted value.
159     */
160    @Override
161    public StringBuffer format(double number, StringBuffer toAppendTo,
162            FieldPosition pos) {
163        StringBuffer result = new StringBuffer();
164        if (this.showBase) {
165            result.append(this.baseLabel);
166            result.append(this.powerLabel);
167        }
168        result.append(this.formatter.format(calculateLog(number)));
169        return result;
170    }
171
172    /**
173     * Formats the specified number as a hexadecimal string.  The decimal
174     * fraction is ignored.
175     *
176     * @param number  the number to format.
177     * @param toAppendTo  the buffer to append to (ignored here).
178     * @param pos  the field position (ignored here).
179     *
180     * @return The string buffer.
181     */
182    @Override
183    public StringBuffer format(long number, StringBuffer toAppendTo,
184            FieldPosition pos) {
185        StringBuffer result = new StringBuffer();
186        if (this.showBase) {
187            result.append(this.baseLabel);
188            result.append(this.powerLabel);
189        }
190        result.append(this.formatter.format(calculateLog(number)));
191        return result;
192    }
193
194    /**
195     * Parsing is not implemented, so this method always returns
196     * {@code null}.
197     *
198     * @param source  ignored.
199     * @param parsePosition  ignored.
200     *
201     * @return Always {@code null}.
202     */
203    @Override
204    public Number parse (String source, ParsePosition parsePosition) {
205        return null; // don't bother with parsing
206    }
207
208    /**
209     * Tests this formatter for equality with an arbitrary object.
210     *
211     * @param obj  the object ({@code null} permitted).
212     *
213     * @return A boolean.
214     */
215    @Override
216    public boolean equals(Object obj) {
217        if (obj == this) {
218            return true;
219        }
220        if (!(obj instanceof LogFormat)) {
221            return false;
222        }
223        LogFormat that = (LogFormat) obj;
224        if (this.base != that.base) {
225            return false;
226        }
227        if (!this.baseLabel.equals(that.baseLabel)) {
228            return false;
229        }
230        if (this.baseLog != that.baseLog) {
231            return false;
232        }
233        if (this.showBase != that.showBase) {
234            return false;
235        }
236        if (!this.formatter.equals(that.formatter)) {
237            return false;
238        }
239        return super.equals(obj);
240    }
241
242    /**
243     * Returns a clone of this instance.
244     *
245     * @return A clone.
246     */
247    @Override
248    public Object clone() {
249        LogFormat clone = (LogFormat) super.clone();
250        clone.formatter = (NumberFormat) this.formatter.clone();
251        return clone;
252    }
253
254}