package com.mapbox.mapboxsdk.geometry; import android.location.Location; import android.os.Parcel; import android.os.Parcelable; import com.mapbox.mapboxsdk.constants.GeoConstants; import com.mapbox.mapboxsdk.utils.MathUtils; /** * A geographical location which contains a single latitude, longitude pair, with * optional altitude. *

* Latitude and longitude are expressed as decimal degrees * in the WGS84 datum. By default, altitude is 0.0, or sea level. *

*

* Mapbox GL displays maps in the Mercator Projection and projects geographical * data automatically, so all data enters in the WGS84 datum. *

*/ public class LatLng implements ILatLng, Parcelable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public LatLng createFromParcel(Parcel in) { return new LatLng(in); } public LatLng[] newArray(int size) { return new LatLng[size]; } }; private double latitude; private double longitude; private double altitude = 0.0; /** * Construct a new latitude, longitude point at (0, 0) */ public LatLng() { this.latitude = 0.0; this.longitude = 0.0; } /** * Construct a new latitude, longitude point given float arguments * @param latitude Latitude in degrees * @param longitude Longitude in degrees */ public LatLng(double latitude, double longitude) { this.latitude = latitude; this.longitude = longitude; } /** * Construct a new latitude, longitude, altitude point given float arguments * @param latitude Latitude in degrees * @param longitude Longitude in degress * @param altitude Altitude in meters */ public LatLng(double latitude, double longitude, double altitude) { this.latitude = latitude; this.longitude = longitude; this.altitude = altitude; } /** * Transform a Location into a LatLng point * @param location Android Location */ public LatLng(Location location) { this(location.getLatitude(), location.getLongitude(), location.getAltitude()); } /** * Clone an existing latitude longitude point * @param aLatLng LatLng */ public LatLng(LatLng aLatLng) { this.latitude = aLatLng.latitude; this.longitude = aLatLng.longitude; this.altitude = aLatLng.altitude; } protected LatLng(Parcel in) { latitude = in.readDouble(); longitude = in.readDouble(); altitude = in.readDouble(); } public void setLatitude(double latitude) { this.latitude = latitude; } @Override public double getLatitude() { return latitude; } public void setLongitude(double longitude) { this.longitude = longitude; } @Override public double getLongitude() { return longitude; } public void setAltitude(double altitude) { this.altitude = altitude; } @Override public double getAltitude() { return altitude; } /** * Return a new LatLng object with a wrapped Longitude. This allows original data object * to remain unchanged. * @return New LatLng object with wrapped Longitude */ public LatLng wrap(){ LatLng wrappedVersion = new LatLng(this); double lon = wrappedVersion.getLongitude(); if (lon < GeoConstants.MIN_LONGITUDE || lon > GeoConstants.MAX_LONGITUDE) { wrappedVersion.setLongitude(MathUtils.wrap(wrappedVersion.getLongitude(), GeoConstants.MIN_LONGITUDE, GeoConstants.MAX_LONGITUDE)); } return wrappedVersion; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } LatLng latLng = (LatLng) o; return Double.compare(latLng.altitude, altitude) == 0 && Double.compare(latLng.latitude, latitude) == 0 && Double.compare(latLng.longitude, longitude) == 0; } @Override public int hashCode() { int result; long temp; temp = Double.doubleToLongBits(latitude); result = (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(longitude); result = 31 * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(altitude); result = 31 * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public String toString() { return "LatLng [latitude=" + latitude + ", longitude=" + longitude + ", altitude=" + altitude + "]"; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel out, int flags) { out.writeDouble(latitude); out.writeDouble(longitude); out.writeDouble(altitude); } /** * Calculate distance between two points * @param other Other LatLng to compare to * @return distance in meters */ public double distanceTo(LatLng other) { if(latitude == other.latitude && longitude == other.longitude){ // return 0.0 to avoid a NaN return 0.0; } final double a1 = Math.toRadians(this.latitude); final double a2 = Math.toRadians(this.longitude); final double b1 = Math.toRadians(other.getLatitude()); final double b2 = Math.toRadians(other.getLongitude()); final double cosa1 = Math.cos(a1); final double cosb1 = Math.cos(b1); final double t1 = cosa1 * Math.cos(a2) * cosb1 * Math.cos(b2); final double t2 = cosa1 * Math.sin(a2) * cosb1 * Math.sin(b2); final double t3 = Math.sin(a1) * Math.sin(b1); final double tt = Math.acos(t1 + t2 + t3); return GeoConstants.RADIUS_EARTH_METERS * tt; } }