package net.sf.openrocket.unit;
import java.util.ArrayList;
public class GeneralUnit extends Unit {
@SuppressWarnings("unused")
private final int significantNumbers;
private final int decimalRounding;
// Values smaller that this are rounded using decimal rounding
// [pre-calculated as 10^(significantNumbers-1)]
private final double decimalLimit;
// Pre-calculated as 10^significantNumbers
private final double significantNumbersLimit;
public GeneralUnit(double multiplier, String unit) {
this(multiplier, unit, 2, 10);
}
public GeneralUnit(double multiplier, String unit, int significantNumbers) {
this(multiplier, unit, significantNumbers, 10);
}
public GeneralUnit(double multiplier, String unit, int significantNumbers, int decimalRounding) {
super(multiplier, unit);
assert(significantNumbers>0);
assert(decimalRounding>0);
this.significantNumbers = significantNumbers;
this.decimalRounding = decimalRounding;
double d=1;
double e=10;
for (int i=1; i<significantNumbers; i++) {
d *= 10.0;
e *= 10.0;
}
decimalLimit = d;
significantNumbersLimit = e;
}
@Override
public double round(double value) {
if (value < decimalLimit) {
// Round to closest 1/decimalRounding
return Math.rint(value*decimalRounding)/decimalRounding;
} else {
// Round to given amount of significant numbers
double m = 1;
while (value >= significantNumbersLimit) {
m *= 10.0;
value /= 10.0;
}
return Math.rint(value)*m;
}
}
// TODO: LOW: untested
// start, end and scale in this units
// @Override
public ArrayList<Tick> getTicks(double start, double end, double scale) {
ArrayList<Tick> ticks = new ArrayList<Tick>();
@SuppressWarnings("unused")
double delta;
@SuppressWarnings("unused")
int normal, major;
// TODO: LOW: more fine-grained (e.g. 0||||5||||10||||15||||20)
if (scale <= 1.0/decimalRounding) {
delta = 1.0/decimalRounding;
normal = 1;
major = decimalRounding;
} else if (scale <= 1.0) {
delta = 1.0/decimalRounding;
normal = decimalRounding;
major = decimalRounding*10;
} else {
double r = scale;
delta = 1;
while (r > 10) {
r /= 10;
delta *= 10;
}
normal = 10;
major = 100; // TODO: LOW: More fine-grained with 5
}
// double v = Math.ceil(start/delta)*delta;
// int n = (int)Math.round(v/delta);
// while (v <= end) {
// if (n%major == 0)
// ticks.add(new Tick(v,Tick.MAJOR));
// else if (n%normal == 0)
// ticks.add(new Tick(v,Tick.NORMAL));
// else
// ticks.add(new Tick(v,Tick.MINOR));
// v += delta;
// n++;
// }
return ticks;
}
@Override
public Tick[] getTicks(double start, double end, double minor, double major) {
// Convert values
start = toUnit(start);
end = toUnit(end);
minor = toUnit(minor);
major = toUnit(major);
if (minor <= 0 || major <= 0 || major < minor) {
throw new IllegalArgumentException("getTicks called with minor="+minor+" major="+major);
}
ArrayList<Tick> ticks = new ArrayList<Tick>();
int mod2,mod3,mod4; // Moduli for minor-notable, major-nonnotable, major-notable
double minstep;
// Find the smallest possible step size
double one=1;
while (one > minor)
one /= 10;
while (one < minor)
one *= 10;
// one is the smallest round-ten that is larger than minor
if (one/2 >= minor) {
// smallest step is round-five
minstep = one/2;
mod2 = 2; // Changed later if clashes with major ticks
} else {
minstep = one;
mod2 = 10; // Changed later if clashes with major ticks
}
// Find step size for major ticks
one = 1;
while (one > major)
one /= 10;
while (one < major)
one *= 10;
if (one/2 >= major) {
// major step is round-five, major-notable is next round-ten
double majorstep = one/2;
mod3 = (int)Math.round(majorstep/minstep);
mod4 = mod3*2;
} else {
// major step is round-ten, major-notable is next round-ten
mod3 = (int)Math.round(one/minstep);
mod4 = mod3*10;
}
// Check for clashes between minor-notable and major-nonnotable
if (mod3 == mod2) {
if (mod2==2)
mod2 = 1; // Every minor tick is notable
else
mod2 = 5; // Every fifth minor tick is notable
}
// Calculate starting position
int pos = (int)Math.ceil(start/minstep);
// System.out.println("mod2="+mod2+" mod3="+mod3+" mod4="+mod4);
while (pos*minstep <= end) {
double unitValue = pos*minstep;
double value = fromUnit(unitValue);
if (pos%mod4 == 0)
ticks.add(new Tick(value,unitValue,true,true));
else if (pos%mod3 == 0)
ticks.add(new Tick(value,unitValue,true,false));
else if (pos%mod2 == 0)
ticks.add(new Tick(value,unitValue,false,true));
else
ticks.add(new Tick(value,unitValue,false,false));
pos++;
}
return ticks.toArray(new Tick[0]);
}
@Override
public double getNextValue(double value) {
// TODO: HIGH: Auto-generated method stub
return value+1;
}
@Override
public double getPreviousValue(double value) {
// TODO: HIGH: Auto-generated method stub
return value-1;
}
///// TESTING:
private static void printTicks(double start, double end, double minor, double major) {
Tick[] ticks = Unit.NOUNIT.getTicks(start, end, minor, major);
String str = "Ticks for ("+start+","+end+","+minor+","+major+"):";
for (int i=0; i<ticks.length; i++) {
str += " "+ticks[i].value;
if (ticks[i].major) {
if (ticks[i].notable)
str += "*";
else
str += "o";
} else {
if (ticks[i].notable)
str += "_";
else
str += " ";
}
}
System.out.println(str);
}
public static void main(String[] arg) {
printTicks(0,100,1,10);
printTicks(4.7,11.0,0.15,0.7);
}
}