Rev 3408 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2008 Steve Ratcliffe
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
*
* Author: Steve Ratcliffe
* Create date: 07-Dec-2008
*/
package uk.me.parabola.mkgmap.osmstyle.eval;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import uk.me.parabola.mkgmap.scan.SyntaxException;
/**
* Converting quantities from one unit to another.
*
* @author Steve Ratcliffe
*/
public class UnitConversions
{
private static final Pattern CODE_RE =
Pattern.
compile("(.*)=>(.*)");
private static final Map<UnitType,
Map<String,
Double>> CONVERSIONS =
new HashMap<>();
private static final Map<String,
Double> LENGTH_FACTORS =
new HashMap<>();
private static final Map<String,
Double> SPEED_FACTORS =
new HashMap<>();
static {
Map<String,
Double> m = LENGTH_FACTORS
;
m.
put("m",
1.0);
m.
put("km",
1000.0);
m.
put("ft",
0.3048);
m.
put("mi",
1_609.344
);
CONVERSIONS.
put(UnitType.
LENGTH, LENGTH_FACTORS
);
m = SPEED_FACTORS
;
m.
put("kmh",
1.0);
m.
put("km/h",
1.0);
m.
put("kmph",
1.0);
m.
put("mph",
1.60934);
m.
put("knots",
1.852);
CONVERSIONS.
put(UnitType.
SPEED, SPEED_FACTORS
);
}
/** The type of unit, speed, length etc. */
private final UnitType unitType
;
/** The target unit */
private final String target
;
/** The factor to convert from the default source unit to the target */
private final double defaultFactor
;
/**
* Create a converter between the units given in the {@code code} argument.
*
* This will be something like m=>ft to convert from meters to feet. If the input is a plain
* value such as 10, then the input is in meters and it is converted to feet. If the
* input already has a unit, eg 10ft, then the conversion will be from that unit to
* the target unit. So in this case, since the input is already in feet, then result is 10.
*
* @param code A specifier from=>to.
*/
public static UnitConversions createConversion
(String code
) {
Matcher matcher = CODE_RE.
matcher(code
);
if (!matcher.
matches())
throw new SyntaxException
(String.
format("Unrecognised unit conversion: '%s'", code
));
String source = matcher.
group(1);
String target = matcher.
group(2);
return new UnitConversions
(source, target
);
}
private UnitConversions
(String source,
String target
) {
this.
target = target
;
UnitType type = getType
(source
);
if (type
!=
null && type == getType
(target
)) {
unitType = type
;
defaultFactor = getConversion
(source
);
} else {
unitType =
null;
defaultFactor =
1;
}
}
/**
* The conversion factor; multiply by this value to convert to the target unit.
* @param source If this is not null, then use this as the source unit.
* @return The factor to multiply the value by to convert from the source to target units.
*/
public Double convertFactor
(String source
) {
// The value has no unit, so use the default one. We already know the conversion factor for the
// default source unit, so just return it.
if (source ==
null)
return defaultFactor
;
if (unitType ==
null)
return null;
return getConversion
(source
);
}
public double convertFrom
(String source
) {
assert source
!=
null && unitType
!=
null;
if (CONVERSIONS.
get(unitType
).
containsKey(source
))
return getConversion
(source
);
else
return 0;
}
public boolean isValid
() {
return unitType
!=
null;
}
/**
* Find the unit type that corresponds to the unit abbreviation.
*
* For example for km, this would be LENGTH.
* @param source A unit specifier.
* @return The type of unit.
*/
private static UnitType getType
(String source
) {
for (UnitType t : UnitType.
values()) {
Map<String,
Double> map = CONVERSIONS.
get(t
);
for (String unit : map.
keySet()) {
if (unit.
equals(source
))
return t
;
}
}
return null;
}
private double getFactor
(String unit
) {
assert isValid
();
Double d = CONVERSIONS.
get(unitType
).
get(unit
);
return d ==
null? 0: d
;
}
private Double getConversion
(String source
) {
Double in = getInFactor
(unitType, source
);
if (in ==
null)
return null;
double out = getOutFactor
(unitType, target
);
return in
* out
;
}
private static Double getInFactor
(UnitType type,
String source
) {
if (source.
isEmpty())
return 1.0;
Map<String,
Double> map = CONVERSIONS.
get(type
);
assert map
!=
null;
return map.
get(source
);
}
private static double getOutFactor
(UnitType type,
String target
) {
return 1.0 / getInFactor
(type, target
);
}
public double getDefaultFactor
() {
return defaultFactor
;
}
public static enum UnitType
{
LENGTH,
SPEED,
}
}