org.elasticsearch.common.unit.DistanceUnit Maven / Gradle / Ivy
The newest version!
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.common.unit;
import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import java.io.IOException;
/**
* The DistanceUnit enumerates several units for measuring distances. These units
* provide methods for converting strings and methods to convert units among each
* others. Some methods like {@link DistanceUnit#getEarthCircumference} refer to
* the earth ellipsoid defined in {@link GeoUtils}. The default unit used within
* this project is METERS
which is defined by DEFAULT
*/
public enum DistanceUnit implements Writeable {
INCH(0.0254, "in", "inch"),
YARD(0.9144, "yd", "yards"),
FEET(0.3048, "ft", "feet"),
KILOMETERS(1000.0, "km", "kilometers"),
NAUTICALMILES(1852.0, "NM", "nmi", "nauticalmiles"),
MILLIMETERS(0.001, "mm", "millimeters"),
CENTIMETERS(0.01, "cm", "centimeters"),
// 'm' is a suffix of 'nmi' so it must follow 'nmi'
MILES(1609.344, "mi", "miles"),
// since 'm' is suffix of other unit
// it must be the last entry of unit
// names ending with 'm'. otherwise
// parsing would fail
METERS(1, "m", "meters");
public static final DistanceUnit DEFAULT = METERS;
private double meters;
private final String[] names;
DistanceUnit(double meters, String...names) {
this.meters = meters;
this.names = names;
}
/**
* Measures the circumference of earth in this unit
*
* @return length of earth circumference in this unit
*/
public double getEarthCircumference() {
return GeoUtils.EARTH_EQUATOR / meters;
}
/**
* Measures the radius of earth in this unit
*
* @return length of earth radius in this unit
*/
public double getEarthRadius() {
return GeoUtils.EARTH_SEMI_MAJOR_AXIS / meters;
}
/**
* Measures a longitude in this unit
*
* @return length of a longitude degree in this unit
*/
public double getDistancePerDegree() {
return GeoUtils.EARTH_EQUATOR / (360.0 * meters);
}
/**
* Convert a value into meters
*
* @param distance distance in this unit
* @return value in meters
*/
public double toMeters(double distance) {
return convert(distance, this, DistanceUnit.METERS);
}
/**
* Convert a value given in meters to a value of this unit
*
* @param distance distance in meters
* @return value in this unit
*/
public double fromMeters(double distance) {
return convert(distance, DistanceUnit.METERS, this);
}
/**
* Convert a given value into another unit
*
* @param distance value in this unit
* @param unit source unit
* @return value in this unit
*/
public double convert(double distance, DistanceUnit unit) {
return convert(distance, unit, this);
}
/**
* Convert a value to a distance string
*
* @param distance value to convert
* @return String representation of the distance
*/
public String toString(double distance) {
return distance + toString();
}
@Override
public String toString() {
return names[0];
}
/**
* Converts the given distance from the given DistanceUnit, to the given DistanceUnit
*
* @param distance Distance to convert
* @param from Unit to convert the distance from
* @param to Unit of distance to convert to
* @return Given distance converted to the distance in the given unit
*/
public static double convert(double distance, DistanceUnit from, DistanceUnit to) {
if (from == to) {
return distance;
} else {
return distance * from.meters / to.meters;
}
}
/**
* Parses a given distance and converts it to the specified unit.
*
* @param distance String defining a distance (value and unit)
* @param defaultUnit unit assumed if none is defined
* @param to unit of result
* @return parsed distance
*/
public static double parse(String distance, DistanceUnit defaultUnit, DistanceUnit to) {
Distance dist = Distance.parseDistance(distance, defaultUnit);
return convert(dist.value, dist.unit, to);
}
/**
* Parses a given distance and converts it to this unit.
*
* @param distance String defining a distance (value and unit)
* @param defaultUnit unit to expect if none if provided
* @return parsed distance
*/
public double parse(String distance, DistanceUnit defaultUnit) {
return parse(distance, defaultUnit, this);
}
/**
* Convert a String to a {@link DistanceUnit}
*
* @param unit name of the unit
* @return unit matching the given name
* @throws IllegalArgumentException if no unit matches the given name
*/
public static DistanceUnit fromString(String unit) {
for (DistanceUnit dunit : values()) {
for (String name : dunit.names) {
if(name.equals(unit)) {
return dunit;
}
}
}
throw new IllegalArgumentException("No distance unit match [" + unit + "]");
}
/**
* Parses the suffix of a given distance string and return the corresponding {@link DistanceUnit}
*
* @param distance string representing a distance
* @param defaultUnit default unit to use, if no unit is provided by the string
* @return unit of the given distance
*/
public static DistanceUnit parseUnit(String distance, DistanceUnit defaultUnit) {
for (DistanceUnit unit : values()) {
for (String name : unit.names) {
if(distance.endsWith(name)) {
return unit;
}
}
}
return defaultUnit;
}
/**
* This class implements a value+unit tuple.
*/
public static class Distance implements Comparable {
public final double value;
public final DistanceUnit unit;
public Distance(double value, DistanceUnit unit) {
super();
this.value = value;
this.unit = unit;
}
/**
* Converts a {@link Distance} value given in a specific {@link DistanceUnit} into
* a value equal to the specified value but in a other {@link DistanceUnit}.
*
* @param unit unit of the result
* @return converted distance
*/
public Distance convert(DistanceUnit unit) {
if(this.unit == unit) {
return this;
} else {
return new Distance(DistanceUnit.convert(value, this.unit, unit), unit);
}
}
@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
} else if (obj instanceof Distance) {
Distance other = (Distance) obj;
return DistanceUnit.convert(value, unit, other.unit) == other.value;
} else {
return false;
}
}
@Override
public int hashCode() {
return Double.valueOf(value * unit.meters).hashCode();
}
@Override
public int compareTo(Distance o) {
return Double.compare(value, DistanceUnit.convert(o.value, o.unit, unit));
}
@Override
public String toString() {
return unit.toString(value);
}
/**
* Parse a {@link Distance} from a given String. If no unit is given
* DistanceUnit.DEFAULT
will be used
*
* @param distance String defining a {@link Distance}
* @return parsed {@link Distance}
*/
public static Distance parseDistance(String distance) {
return parseDistance(distance, DEFAULT);
}
/**
* Parse a {@link Distance} from a given String
*
* @param distance String defining a {@link Distance}
* @param defaultUnit {@link DistanceUnit} to be assumed
* if not unit is provided in the first argument
* @return parsed {@link Distance}
*/
private static Distance parseDistance(String distance, DistanceUnit defaultUnit) {
for (DistanceUnit unit : values()) {
for (String name : unit.names) {
if(distance.endsWith(name)) {
return new Distance(Double.parseDouble(distance.substring(0, distance.length() - name.length())), unit);
}
}
}
return new Distance(Double.parseDouble(distance), defaultUnit);
}
}
/**
* Read a {@link DistanceUnit} from a {@link StreamInput}.
*
* @param in {@link StreamInput} to read the {@link DistanceUnit} from
* @return {@link DistanceUnit} read from the {@link StreamInput}
* @throws IOException if no unit can be read from the {@link StreamInput}
* @throws IllegalArgumentException if no matching {@link DistanceUnit} can be found
*/
public static DistanceUnit readFromStream(StreamInput in) throws IOException {
byte b = in.readByte();
if (b < 0 || b >= values().length) {
throw new IllegalArgumentException("No type for distance unit matching [" + b + "]");
}
return values()[b];
}
/**
* Write a {@link DistanceUnit} to a {@link StreamOutput}.
*
* @param out {@link StreamOutput} to write to
*/
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeByte((byte) this.ordinal());
}
}