package org.microg.networklocation.data; import android.location.Location; public class LocationSpec<T extends PropSpec> { private static final double EARTH_RADIUS = 6367; private T source; private boolean undefined = true; private boolean remote = true; private boolean submitted = false; private double latitude = 0; private double longitude = 0; private double altitude = 0; private boolean hasAltitude = false; private double accuracy = 0; LocationSpec(T source, Location location) { this.source = source; latitude = location.getLatitude(); longitude = location.getLongitude(); altitude = location.getAltitude(); accuracy = location.getAccuracy(); } public LocationSpec(T source, double latitude, double longitude, double accuracy) { this(latitude, longitude, accuracy); this.source = source; } public LocationSpec(T source, double latitude, double longitude, double accuracy, double altitude) { this(source, latitude, longitude, accuracy); this.altitude = altitude; if (altitude != 0) { hasAltitude = true; } } private LocationSpec(double latitude, double longitude, double accuracy) { this.latitude = latitude; this.longitude = longitude; this.accuracy = accuracy; if (((latitude != 0) || (longitude != 0)) && (accuracy != 0)) { undefined = false; } } private LocationSpec(double latitude, double longitude, double accuracy, double altitude, boolean remote, boolean submitted) { this(latitude, longitude, accuracy, altitude); this.remote = remote; this.submitted = submitted; } public LocationSpec(double latitude, double longitude, double accuracy, double altitude, int bools) { this(latitude, longitude, accuracy, altitude); setBools(bools); } LocationSpec(T source) { this.source = source; undefined = true; } private LocationSpec(double latitude, double longitude, double accuracy, double altitude) { this(latitude, longitude, accuracy); this.altitude = altitude; } private static int boolToInt(boolean b, int s) { return b ? (1 << s) : 0; } private static int boolToInt(boolean b) { return boolToInt(b, 0); } private static double degToRad(double deg) { return (deg * Math.PI) / 180; } private static boolean intToBool(int i, int s) { return ((i >> s) & 1) == 1; } public <S extends PropSpec> double distanceTo(LocationSpec<S> other) { return distanceTo(other.getLatitude(), other.getLongitude()); } private double distanceTo(double latitude, double longitude) { double lat1 = degToRad(getLatitude()); double lon1 = degToRad(getLongitude()); double lat2 = degToRad(latitude); double lon2 = degToRad(longitude); double dLat = lat2 - lat1; double dLon = lon2 - lon1; double cordLength = Math.pow(Math.sin(dLat / 2), 2) + (Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dLon / 2), 2)); double centralAngle = 2 * Math.atan2(Math.sqrt(cordLength), Math.sqrt(1 - cordLength)); return EARTH_RADIUS * centralAngle; } public double distanceTo(Location location) { return distanceTo(location.getLatitude(), location.getLongitude()); } public double getAccuracy() { return accuracy; } public double getAltitude() { return altitude; } public int getBools() { return boolToInt(hasAltitude, 3) + boolToInt(undefined, 2) + boolToInt(remote, 1) + boolToInt(submitted); } private void setBools(int bools) { hasAltitude = intToBool(bools, 3); undefined = intToBool(bools, 2); remote = intToBool(bools, 1); submitted = intToBool(bools, 0); } public double getLatitude() { return latitude; } public double getLongitude() { return longitude; } public T getSource() { return source; } public void setSource(T source) { this.source = source; } public boolean isRemote() { return remote; } public boolean isSubmitted() { return submitted; } public boolean isUndefined() { return undefined; } @Override public String toString() { return "LocationSpec{" + "source=" + source + ", latitude=" + latitude + ", longitude=" + longitude + ", altitude=" + altitude + ", accuracy=" + accuracy + ", bools=" + getBools() + '}'; } }