📄 nicenumbers.java
字号:
/*
* This code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
package no.geosoft.cc.util;
import java.util.Iterator;
/**
* Find "nice numbers" within an interval. The interval is given
* by a min and a max value:
*
* <pre>
* NiceNumbers numbers = new NiceNumbers (min, max, n, false);
* for (Iterator i = numbers.iterator(); i.hasNext(); ) {
* NiceNumber number = (NiceNumber) i.next();
* :
* }
* </pre>
*
* This class is handy for producing quality annotation on graphic
* displays, for instance along an axis.
*
* @author <a href="mailto:jacob.dreyer@geosoft.no">Jacob Dreyer</a>
*/
public class NiceNumbers implements Iterator
{
private boolean isBounded_;
private double fromValue_;
private double toValue_;
private double firstValue_; // First nice number < from
private double lastValue_; // First nice number > to
private double majorStep_;
private double minorStep_;
private double minorMinorStep_;
private double step_;
private int nValues_;
private int valueNo_;
/**
* Create nice numbers in an interval.
*
* @param fromValue From value.
* @param toValue To value.
* @param nNumbersApprox Approximate number of major nice numbers to produce.
* @param isBounded True if fromValue/toValue should be end points
* and hence reported as nice numbers.
*/
public NiceNumbers (double fromValue, double toValue, int nNumbersApprox,
boolean isBounded)
{
fromValue_ = fromValue;
toValue_ = toValue;
isBounded_ = isBounded;
if (nNumbersApprox <= 0) nNumbersApprox = 1;
double step = (toValue_ - fromValue_) / nNumbersApprox;
if (step == 0.0) step = 1.0;
boolean isAscending = step > 0.0;
// Scale abs(step) to interval 1 - 10
double scaleFactor = 1.0;
while (Math.abs (step) > 10) {
step /= 10.0;
scaleFactor *= 10.0;
}
while (Math.abs (step) < 1) {
step *= 10.0;
scaleFactor /= 10.0;
}
// Find nice major step value
majorStep_ = Math.abs (step);
if (majorStep_ > 7.50) majorStep_ = 10.0;
else if (majorStep_ > 3.50) majorStep_ = 5.0;
else if (majorStep_ > 2.25) majorStep_ = 2.5;
else if (majorStep_ > 1.50) majorStep_ = 2.0;
else majorStep_ = 1.0;
// Find corresponding minor step value
if (majorStep_ == 10.0) minorStep_ = 5.0;
else if (majorStep_ == 5.0) minorStep_ = 2.5;
else if (majorStep_ == 2.5) minorStep_ = 0.5;
else if (majorStep_ == 2.0) minorStep_ = 1.0;
else minorStep_ = 0.1;
// Find corresponding minor minor step value
if (minorStep_ == 5.0) minorMinorStep_ = 1.0;
else if (minorStep_ == 2.5) minorMinorStep_ = 0.5;
else if (minorStep_ == 1.0) minorMinorStep_ = 0.1;
else if (minorStep_ == 0.5) minorMinorStep_ = 0.1;
else minorMinorStep_ = 0.0;
if (step < 0) {
majorStep_ = -majorStep_;
minorStep_ = -minorStep_;
minorMinorStep_ = -minorMinorStep_;
}
majorStep_ *= scaleFactor;
minorStep_ *= scaleFactor;
minorMinorStep_ *= scaleFactor;
// Find first nice value before fromValue
firstValue_ = ((int) (fromValue_ / majorStep_)) * majorStep_;
if ( isAscending && firstValue_ > fromValue_) firstValue_ -=majorStep_;
else if (!isAscending && firstValue_ < fromValue_) firstValue_ -=majorStep_;
// Find last nice value after toValue
lastValue_ = ((int) (toValue_ / majorStep_)) * majorStep_;
if ( isAscending && lastValue_ < toValue_) lastValue_ += majorStep_;
else if (!isAscending && lastValue_ > toValue_) lastValue_ += majorStep_;
// Find total number of values
step_ = minorMinorStep_ != 0.0 ? minorMinorStep_ :
minorStep_ != 0.0 ? minorStep_ : majorStep_;
nValues_ = (int) Math.round ((lastValue_ - firstValue_) / step_) + 1;
// Move the steps from value space to count space
majorStep_ = (double) Math.round (majorStep_ / step_);
minorStep_ = (double) Math.round (minorStep_ / step_);
minorMinorStep_ = (double) Math.round (minorMinorStep_ / step_);
}
/**
* Create nice numbers in an unbound interval.
*
* @param fromValue From value.
* @param toValue To value.
* @param nNumbersApprox Approximate number of major nice numbers to produce.
*/
public NiceNumbers (double fromValue, double toValue, int nNumbersApprox)
{
this (fromValue, toValue, nNumbersApprox, false);
}
/**
* Initiate the iteration and return the iterator object
*
* @return The iterator (which is this).
*/
public Iterator iterator()
{
valueNo_ = 0;
return this;
}
/**
* Retur true if there are more nice numbers, false otherwise.
*
* @return True if there are more nice numbers, false otherwise.
*/
public boolean hasNext()
{
return valueNo_ < nValues_;
}
/**
* Return the first nice number of the interval.
*
* @return First nice number of the interval.
*/
public double getFirstValue()
{
return isBounded_ ? fromValue_ : firstValue_;
}
/**
* Return the last nice number of the interval.
*
* @return Last nice number of the interval.
*/
public double getLastValue()
{
return isBounded_ ? toValue_ : lastValue_;
}
/**
* Return number of nice values in this interval.
*
* @return Total number of nice numbers in the interval.
*/
public int getNValues()
{
return nValues_;
}
private boolean equals (double a, double b)
{
double limit = a == 0.0 ? 0.001 : Math.abs (a) * 0.001;
return b > a - limit && b < a + limit;
}
/**
* Return the next nice number of the sequence.
*
* @return Next nice number.
*/
public Object next()
{
// Solve the bounded case
if (isBounded_) {
if (valueNo_ == 0) {
double value = firstValue_;
while ((fromValue_ < toValue_ && value <= fromValue_) ||
(fromValue_ > toValue_ && value >= fromValue_)) {
valueNo_++;
value = firstValue_ + valueNo_ * step_;
}
int rank = equals (firstValue_, fromValue_) ? 0 : 1;
return new NiceNumber (fromValue_, rank, 0.0);
}
else {
double value = firstValue_ + valueNo_ * step_;
if ((fromValue_ < toValue_ && value >= toValue_) ||
(fromValue_ > toValue_ && value <= toValue_)) {
valueNo_ = nValues_;
int rank = equals (lastValue_, toValue_) ? 0 : 1;
return new NiceNumber (toValue_, rank, 1.0);
}
}
}
double value = firstValue_ + valueNo_ * step_;
int rank;
if (valueNo_ % (int) majorStep_ == 0.0) rank = 0;
else if (valueNo_ % (int) minorStep_ == 0.0) rank = 1;
else rank = 2;
// Find position
double first = getFirstValue();
double last = getLastValue();
double position = first == last ? 0.0 : (value - first) / (last - first);
NiceNumber niceNumber = new NiceNumber (value, rank, position);
valueNo_++;
return niceNumber;
}
/**
* From Iterator. Removing nice numbers are not possible, so this method
* is left empty.
*/
public void remove()
{
// Not possible
}
/**
* Testing this class.
*
* @param args Not used.
*/
public static void main (String[] args)
{
NiceNumbers numbers = new NiceNumbers (1.01, -1.0, 4, true);
for (Iterator i = numbers.iterator(); i.hasNext(); ) {
NiceNumber niceNumber = (NiceNumber) numbers.next();
if (niceNumber.getRank() < 2)
System.out.println (niceNumber);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -