updated PointType to match openHAB 1.8 codebase
Signed-off-by: Kai Kreuzer <kai@openhab.org>pull/11/head
parent
2f7be5a2e1
commit
081b1f4b70
|
@ -13,6 +13,7 @@ import java.util.Formatter;
|
|||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.ComplexType;
|
||||
import org.openhab.core.types.PrimitiveType;
|
||||
|
@ -26,142 +27,213 @@ import org.openhab.core.types.State;
|
|||
*/
|
||||
public class PointType implements ComplexType, Command, State {
|
||||
|
||||
public static final double EARTH_GRAVITATIONAL_CONSTANT = 3.986004418e14;
|
||||
public static final double WGS84_a = 6378137; // The equatorial radius of
|
||||
// WGS84 ellipsoid (6378137
|
||||
// m).
|
||||
private BigDecimal latitude; // in decimal degrees
|
||||
private BigDecimal longitude; // in decimal degrees
|
||||
private BigDecimal altitude = BigDecimal.ZERO; // in decimal meters
|
||||
// constants for the constituents
|
||||
static final public String KEY_LATITUDE = "lat";
|
||||
static final public String KEY_LONGITUDE = "long";
|
||||
static final public String KEY_ALTITUDE = "alt";
|
||||
private static final BigDecimal circle = new BigDecimal(360);
|
||||
private static final BigDecimal flat = new BigDecimal(180);
|
||||
private static final BigDecimal right = new BigDecimal(90);
|
||||
public static final PointType EMPTY = new PointType(new DecimalType(0),
|
||||
new DecimalType(0));
|
||||
public static final double EARTH_GRAVITATIONAL_CONSTANT = 3.986004418e14;
|
||||
public static final double WGS84_a = 6378137; // The equatorial radius of
|
||||
// WGS84 ellipsoid (6378137
|
||||
// m).
|
||||
private BigDecimal latitude = BigDecimal.ZERO; // in decimal degrees
|
||||
private BigDecimal longitude = BigDecimal.ZERO; // in decimal degrees
|
||||
private BigDecimal altitude = BigDecimal.ZERO; // in decimal meters
|
||||
// constants for the constituents
|
||||
static final public String KEY_LATITUDE = "lat";
|
||||
static final public String KEY_LONGITUDE = "long";
|
||||
static final public String KEY_ALTITUDE = "alt";
|
||||
private static final BigDecimal circle = new BigDecimal(360);
|
||||
private static final BigDecimal flat = new BigDecimal(180);
|
||||
private static final BigDecimal right = new BigDecimal(90);
|
||||
public static final PointType EMPTY = new PointType(new DecimalType(0), new DecimalType(0));
|
||||
|
||||
public PointType(DecimalType latitude, DecimalType longitude) {
|
||||
canonicalize(latitude, longitude);
|
||||
}
|
||||
/**
|
||||
* Default constructor creates a point at sea level where the equator
|
||||
* (0° latitude) and the prime meridian (0° longitude) intersect. (A
|
||||
* nullary constructor is needed by
|
||||
* {@link org.openhab.core.internal.items.ItemUpdater#receiveUpdate})
|
||||
*/
|
||||
@SuppressWarnings("restriction")
|
||||
public PointType() {
|
||||
}
|
||||
|
||||
public PointType(DecimalType latitude, DecimalType longitude,
|
||||
DecimalType altitude) {
|
||||
this(latitude, longitude);
|
||||
setAltitude(altitude);
|
||||
}
|
||||
public PointType(DecimalType latitude, DecimalType longitude) {
|
||||
canonicalize(latitude, longitude);
|
||||
}
|
||||
|
||||
public PointType(StringType latitude, StringType longitude) {
|
||||
this(new DecimalType(latitude.toString()), new DecimalType(
|
||||
longitude.toString()));
|
||||
}
|
||||
public PointType(DecimalType latitude, DecimalType longitude, DecimalType altitude) {
|
||||
this(latitude, longitude);
|
||||
setAltitude(altitude);
|
||||
}
|
||||
|
||||
public PointType(StringType latitude, StringType longitude,
|
||||
StringType altitude) {
|
||||
this(new DecimalType(latitude.toString()), new DecimalType(
|
||||
longitude.toString()), new DecimalType(altitude.toString()));
|
||||
}
|
||||
public PointType(StringType latitude, StringType longitude) {
|
||||
this(new DecimalType(latitude.toString()), new DecimalType(longitude.toString()));
|
||||
}
|
||||
|
||||
public PointType(String value) {
|
||||
if (!value.isEmpty()) {
|
||||
String[] elements = value.split(",");
|
||||
if (elements.length >= 2) {
|
||||
canonicalize(new DecimalType(elements[0]), new DecimalType(
|
||||
elements[1]));
|
||||
if (elements.length == 3) {
|
||||
setAltitude(new DecimalType(elements[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public PointType(StringType latitude, StringType longitude, StringType altitude) {
|
||||
this(new DecimalType(latitude.toString()), new DecimalType(longitude.toString()),
|
||||
new DecimalType(altitude.toString()));
|
||||
}
|
||||
|
||||
public DecimalType getLatitude() {
|
||||
return new DecimalType(latitude);
|
||||
}
|
||||
public PointType(String value) {
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
String[] elements = value.split(",");
|
||||
if (elements.length >= 2) {
|
||||
canonicalize(new DecimalType(elements[0]), new DecimalType(elements[1]));
|
||||
if (elements.length == 3) {
|
||||
setAltitude(new DecimalType(elements[2]));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(value + " is not a valid PointType syntax");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Constructor argument must not be blank");
|
||||
}
|
||||
}
|
||||
|
||||
public DecimalType getLongitude() {
|
||||
return new DecimalType(longitude);
|
||||
}
|
||||
public DecimalType getLatitude() {
|
||||
return new DecimalType(latitude);
|
||||
}
|
||||
|
||||
public DecimalType getAltitude() {
|
||||
return new DecimalType(altitude);
|
||||
}
|
||||
public DecimalType getLongitude() {
|
||||
return new DecimalType(longitude);
|
||||
}
|
||||
|
||||
public void setAltitude(DecimalType altitude) {
|
||||
this.altitude = altitude.toBigDecimal();
|
||||
}
|
||||
public DecimalType getAltitude() {
|
||||
return new DecimalType(altitude);
|
||||
}
|
||||
|
||||
public DecimalType getGravity() {
|
||||
double latRad = Math.toRadians(latitude.doubleValue());
|
||||
double deltaG = -2000.0 * (altitude.doubleValue() / 1000)
|
||||
* EARTH_GRAVITATIONAL_CONSTANT / (Math.pow(WGS84_a, 3.0));
|
||||
double sin2lat = Math.sin(latRad) * Math.sin(latRad);
|
||||
double sin22lat = Math.sin(2.0 * latRad) * Math.sin(2.0 * latRad);
|
||||
double result = (9.780327 * (1.0 + 5.3024e-3 * sin2lat - 5.8e-6 * sin22lat) + deltaG);
|
||||
return new DecimalType(result);
|
||||
}
|
||||
public void setAltitude(DecimalType altitude) {
|
||||
this.altitude = altitude.toBigDecimal();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats the value of this type according to a pattern (@see
|
||||
* {@link Formatter}). One single value of this type can be referenced by
|
||||
* the pattern using an index. The item order is defined by the natural
|
||||
* (alphabetical) order of their keys.
|
||||
* </p>
|
||||
*
|
||||
* @param pattern
|
||||
* the pattern to use containing indexes to reference the single
|
||||
* elements of this type.
|
||||
*/
|
||||
@Override
|
||||
public String format(String pattern) {
|
||||
return String.format(pattern, getConstituents().values().toArray());
|
||||
}
|
||||
public DecimalType getGravity() {
|
||||
double latRad = Math.toRadians(latitude.doubleValue());
|
||||
double deltaG = -2000.0 * (altitude.doubleValue() / 1000) * EARTH_GRAVITATIONAL_CONSTANT
|
||||
/ (Math.pow(WGS84_a, 3.0));
|
||||
double sin2lat = Math.sin(latRad) * Math.sin(latRad);
|
||||
double sin22lat = Math.sin(2.0 * latRad) * Math.sin(2.0 * latRad);
|
||||
double result = (9.780327 * (1.0 + 5.3024e-3 * sin2lat - 5.8e-6 * sin22lat) + deltaG);
|
||||
return new DecimalType(result);
|
||||
}
|
||||
|
||||
public PointType valueOf(String value) {
|
||||
return new PointType(value);
|
||||
}
|
||||
/**
|
||||
* Return the distance in meters from otherPoint, ignoring altitude. This algorithm also
|
||||
* ignores the oblate spheroid shape of Earth and assumes a perfect sphere, so results
|
||||
* are inexact.
|
||||
*
|
||||
* @param otherPoint
|
||||
* @return distance in meters
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Haversine_formula">Haversine formula</a>
|
||||
*/
|
||||
public DecimalType distanceFrom(PointType otherPoint) {
|
||||
double dLat = Math.toRadians(otherPoint.latitude.doubleValue() - this.latitude.doubleValue());
|
||||
double dLong = Math.toRadians(otherPoint.longitude.doubleValue() - this.longitude.doubleValue());
|
||||
double a = Math.pow(Math.sin(dLat / 2D), 2D) + Math.cos(Math.toRadians(this.latitude.doubleValue()))
|
||||
* Math.cos(Math.toRadians(otherPoint.latitude.doubleValue())) * Math.pow(Math.sin(dLong / 2D), 2D);
|
||||
double c = 2D * Math.atan2(Math.sqrt(a), Math.sqrt(1D - a));
|
||||
return new DecimalType(WGS84_a * c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%1$.2f°N, %2$.2f°W, %3$.2f m", latitude, longitude, altitude);
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* Formats the value of this type according to a pattern (@see
|
||||
* {@link Formatter}). One single value of this type can be referenced by
|
||||
* the pattern using an index. The item order is defined by the natural
|
||||
* (alphabetical) order of their keys.
|
||||
* </p>
|
||||
*
|
||||
* @param pattern
|
||||
* the pattern to use containing indexes to reference the single
|
||||
* elements of this type.
|
||||
*/
|
||||
@Override
|
||||
public String format(String pattern) {
|
||||
return String.format(pattern, getConstituents().values().toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<String, PrimitiveType> getConstituents() {
|
||||
SortedMap<String, PrimitiveType> result = new TreeMap<String, PrimitiveType>();
|
||||
result.put(KEY_LATITUDE, getLatitude());
|
||||
result.put(KEY_LONGITUDE, getLongitude());
|
||||
result.put(KEY_ALTITUDE, getAltitude());
|
||||
return result;
|
||||
}
|
||||
public static PointType valueOf(String value) {
|
||||
return new PointType(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize the current latitude and longitude values such that:
|
||||
*
|
||||
* <pre>
|
||||
* -90 <= latitude <= +90 - 180 < longitude <= +180
|
||||
* </pre>
|
||||
*/
|
||||
private void canonicalize(DecimalType aLat, DecimalType aLon) {
|
||||
latitude = flat.add(aLat.toBigDecimal()).remainder(circle);
|
||||
longitude = aLon.toBigDecimal();
|
||||
if (latitude.compareTo(BigDecimal.ZERO) == -1)
|
||||
latitude.add(circle);
|
||||
latitude = latitude.subtract(flat);
|
||||
if (latitude.compareTo(right) == 1) {
|
||||
latitude = flat.subtract(latitude);
|
||||
longitude = longitude.add(flat);
|
||||
} else if (latitude.compareTo(right.negate()) == -1) {
|
||||
latitude = flat.negate().subtract(latitude);
|
||||
longitude = longitude.add(flat);
|
||||
}
|
||||
longitude = flat.add(longitude).remainder(circle);
|
||||
if (longitude.compareTo(BigDecimal.ZERO) <= 0)
|
||||
longitude = longitude.add(circle);
|
||||
longitude = longitude.subtract(flat);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(latitude.toPlainString());
|
||||
sb.append(',');
|
||||
sb.append(longitude.toPlainString());
|
||||
if (!altitude.equals(BigDecimal.ZERO)) {
|
||||
sb.append(',');
|
||||
sb.append(altitude.toPlainString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public SortedMap<String, PrimitiveType> getConstituents() {
|
||||
SortedMap<String, PrimitiveType> result = new TreeMap<String, PrimitiveType>();
|
||||
result.put(KEY_LATITUDE, getLatitude());
|
||||
result.put(KEY_LONGITUDE, getLongitude());
|
||||
result.put(KEY_ALTITUDE, getAltitude());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize the current latitude and longitude values such that:
|
||||
*
|
||||
* <pre>
|
||||
* -90 <= latitude <= +90 - 180 < longitude <= +180
|
||||
* </pre>
|
||||
*/
|
||||
private void canonicalize(DecimalType aLat, DecimalType aLon) {
|
||||
latitude = flat.add(aLat.toBigDecimal()).remainder(circle);
|
||||
longitude = aLon.toBigDecimal();
|
||||
if (latitude.compareTo(BigDecimal.ZERO) == -1) {
|
||||
latitude.add(circle);
|
||||
}
|
||||
latitude = latitude.subtract(flat);
|
||||
if (latitude.compareTo(right) == 1) {
|
||||
latitude = flat.subtract(latitude);
|
||||
longitude = longitude.add(flat);
|
||||
} else if (latitude.compareTo(right.negate()) == -1) {
|
||||
latitude = flat.negate().subtract(latitude);
|
||||
longitude = longitude.add(flat);
|
||||
}
|
||||
longitude = flat.add(longitude).remainder(circle);
|
||||
if (longitude.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
longitude = longitude.add(circle);
|
||||
}
|
||||
longitude = longitude.subtract(flat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int tmp = 10000 * (getLatitude() == null ? 0 : getLatitude().hashCode());
|
||||
tmp += 100 * (getLongitude() == null ? 0 : getLongitude().hashCode());
|
||||
tmp += (getAltitude() == null ? 0 : getAltitude().hashCode());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof PointType)) {
|
||||
return false;
|
||||
}
|
||||
PointType other = (PointType) obj;
|
||||
if ((getLatitude() != null && other.getLatitude() == null)
|
||||
|| (getLatitude() == null && other.getLatitude() != null)
|
||||
|| (getLongitude() != null && other.getLongitude() == null)
|
||||
|| (getLongitude() == null && other.getLongitude() != null)
|
||||
|| (getAltitude() != null && other.getAltitude() == null)
|
||||
|| (getAltitude() == null && other.getAltitude() != null)) {
|
||||
return false;
|
||||
}
|
||||
if (!getLatitude().equals(other.getLatitude()) || !getLongitude().equals(other.getLongitude())
|
||||
|| !getAltitude().equals(other.getAltitude())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue