Difference between revisions of "Distance"
From DarkWiki
(Created page with "==Java source code== <source lang="java"> package pa.common; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import o...") |
(→Java source code) |
||
| Line 2: | Line 2: | ||
<source lang="java"> | <source lang="java"> | ||
| − | |||
import com.fasterxml.jackson.annotation.JsonCreator; | import com.fasterxml.jackson.annotation.JsonCreator; | ||
Latest revision as of 09:16, 16 June 2017
Java source code
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import org.springframework.data.geo.Metrics;
import java.io.Serializable;
import java.text.DecimalFormat;
/**
* Represents a measurement of distance. When this object is serialised to/from JSON, it is done so using the
* string form.
*/
public class Distance implements Comparable<Distance>, Serializable {
private static final String NUMBER_FORMAT = "0.####";
private double value = 0;
private Units units = Units.M;
/**
* Create a zero-metre distance.
*/
public Distance() {
}
/**
* Create a distance.
*
* @param value The number of units.
* @param units The units to use.
*/
public Distance(double value, Units units) {
setValue(value);
setUnits(units);
}
/**
* Convert a spring org.springframework.data.geo.Distance into a distance. If Spring's implementation changes
* and new metrics are introduced, this method will need to be updated.
*
* @param springDistance The object to convert.
* @return A new distance.
* @throws IllegalArgumentException if the given spring distance could not be converted.
*/
public static Distance fromSpringDistance(org.springframework.data.geo.Distance springDistance) {
if (springDistance.getMetric().equals(Metrics.MILES)) {
return new Distance(springDistance.getValue(), Units.MI);
} else if (springDistance.getMetric().equals(Metrics.KILOMETERS)) {
return new Distance(springDistance.getValue(), Units.KM);
} else {
throw new IllegalArgumentException("Unsupported Metric of org.springframework.data.geo.Distance: " +
springDistance.getMetric());
}
}
/**
* Parse the input and create a distance from it. If no units are provided, metres are assumed. This is the
* method that Jackson will use to create Distance objects from a JSON value.
*
* @param text The textual version of a distance.
* @return A new distance object.
* @throws IllegalArgumentException if the given string cannot be parsed.
*/
@JsonCreator
public static Distance parse(String text) {
return parse(text, Units.M);
}
/**
* Parse the input and create a distance from it. If no units are provided, the default units are assumed.
*
* @param text The textual version of a distance.
* @param defaultUnits The units to use if none is provided.
* @return A new distance object.
* @throws IllegalArgumentException if the given string cannot be parsed.
*/
public static Distance parse(String text, Units defaultUnits) {
Units foundUnits = null;
if (text.endsWith(Units.KM.getSymbol())) foundUnits = Units.KM;
else if (text.endsWith(Units.M.getSymbol())) foundUnits = Units.M;
else if (text.endsWith(Units.MI.getSymbol())) foundUnits = Units.MI;
if (foundUnits != null) {
int index = text.lastIndexOf(foundUnits.getSymbol());
String amountString = text.substring(0, index);
try {
return new Distance(Double.parseDouble(amountString), foundUnits);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("No a valid distance: '" + text + "'");
}
} else {
try {
return new Distance(Double.parseDouble(text), defaultUnits);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("No a valid distance: '" + text + "'");
}
}
}
/**
* Convert one distance value into another.
*
* @param in The value to convert.
* @param from The origin units.
* @param to The destination units.
* @return The converted value.
*/
static double convert(double in, Units from, Units to) {
return in * from.getScaleFactor() / to.getScaleFactor();
}
/**
* Get the distance in the current units.
*
* @return The distance in the current units.
*/
public double getValue() {
return value;
}
/**
* Set the distance in the current units.
*
* @param value The distance in the current units.
*/
public void setValue(double value) {
this.value = value;
}
/**
* Get the units used by this distance.
*
* @return The units used by this distance.
*/
public Units getUnits() {
return units;
}
/**
* Set the units used by this distance (without affecting the value).
*
* @param units The units used by this distance.
*/
public void setUnits(Units units) {
this.units = units;
}
/**
* Convert this distance into one with different units.
*
* @param newUnits The desired units.
* @return The new distance, in the desired units.
*/
public Distance convertTo(Units newUnits) {
return new Distance(convert(this.value, this.units, newUnits), newUnits);
}
/**
* Add a distance to this one.
*
* @param distance The distance to add.
* @return A new distance, representing the sum of the distances, in the units of the original.
*/
public Distance add(Distance distance) {
return new Distance(this.getInternalValue() + distance.getInternalValue(), Units.M)
.convertTo(this.units);
}
/**
* Format this distance as a string. A space will be inserted between the value and the unit symbol. This method
* is called when serializing this object to a JSON value.
*
* @return The textual version of this distance.
*/
@JsonValue
public String toString() {
return new DecimalFormat(NUMBER_FORMAT).format(getValue()) + " " + getUnits().getSymbol();
}
/**
* Convert this distance into one of Spring's org.springframework.data.geo.Distance. At this point, Spring only
* supports kilometres and miles. If any other units are used, the appropriate calculation will be made and the
* Spring object will be in the KM metric.
*
* @return The distance in Spring's representation.
*/
public org.springframework.data.geo.Distance toSpringDistance() {
switch (units) {
case KM:
return new org.springframework.data.geo.Distance(
this.getValue(),
Metrics.KILOMETERS);
case MI:
return new org.springframework.data.geo.Distance(
this.getValue(),
Metrics.MILES);
default:
return new org.springframework.data.geo.Distance(
this.getInternalValue() / Units.KM.getScaleFactor(),
Metrics.KILOMETERS);
}
}
/**
* Get the value (in metres) used to compare.
*
* @return The number of metres this distance represents.
*/
double getInternalValue() {
if (units == Units.M) {
return value;
} else {
return convert(value, units, Units.M);
}
}
/**
* Compare two distances.
*
* @param o The distance to compare.
* @return Zero if they're the same, -1 if this value is smaller than the argument, +1 if larger.
*/
@Override
public int compareTo(Distance o) {
if (o == null) {
return 1;
} else {
double lhs = getInternalValue();
double rhs = o.getInternalValue();
if (lhs < rhs) {
return -1;
} else if (lhs > rhs) {
return 1;
} else {
return 0;
}
}
}
/**
* Compare two distances for equality.
*
* @param obj The object to check.
* @return True if they're the same, false otherwise.
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Distance) {
return this.getInternalValue() == ((Distance) obj).getInternalValue();
} else {
return false;
}
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result ^= 31 * Double.hashCode(value);
result ^= 31 * units.hashCode();
return result;
}
/**
* The units of distance. By default, metres are assumed.
*/
public enum Units {
/**
* Metres
*/
M("m", 1),
/**
* Kilometres
*/
KM("km", 1000),
/**
* Miles
*/
MI("mi", 1609.34);
private double scaleFactor;
private String symbol;
Units(String symbol, double scaleFactor) {
this.symbol = symbol;
this.scaleFactor = scaleFactor;
}
/**
* Get the number of metres represented by this unit.
*
* @return The number of metres represented by this unit.
*/
public double getScaleFactor() {
return scaleFactor;
}
/**
* Get the standard symbol for this unit.
*
* @return The standard symbol for this unit.
*/
public String getSymbol() {
return symbol;
}
}
}