diff options
author | osana <osana.babayan@mapbox.com> | 2018-06-28 14:07:49 -0400 |
---|---|---|
committer | “osana” <osana.babayan@mapbox.com> | 2018-07-24 16:34:55 -0700 |
commit | 13332421c618496d5565d701128c6bb427414556 (patch) | |
tree | e1a3af19b51791d50cff7c0449473ad1bd4c207d /platform | |
parent | cdd35536417fe16cc60e225f1bd7462f4242e795 (diff) | |
download | qtlocation-mapboxgl-upstream/osana-vis-region-rotated.tar.gz |
VisibleRegion on rotated bounds (#12135)upstream/osana-vis-region-rotated
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java | 140 |
1 files changed, 102 insertions, 38 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java index 5580dcf99e..38b5bf946a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -4,6 +4,8 @@ import android.graphics.PointF; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.constants.GeometryConstants; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.geometry.ProjectedMeters; @@ -12,6 +14,7 @@ import com.mapbox.mapboxsdk.geometry.VisibleRegion; import java.util.ArrayList; import java.util.List; + /** * A projection is used to translate between on screen location and geographic coordinates on * the surface of the Earth. Screen location is in screen pixels (not display pixels) @@ -124,54 +127,115 @@ public class Projection { bottom = nativeMapView.getHeight() - contentPadding[3]; } + LatLng center = fromScreenLocation(new PointF(left + (right - left) / 2, top + (bottom - top) / 2)); + + List<LatLng> latLngs = new ArrayList<>(); + LatLng topLeft = fromScreenLocation(new PointF(left, top)); LatLng topRight = fromScreenLocation(new PointF(right, top)); LatLng bottomRight = fromScreenLocation(new PointF(right, bottom)); LatLng bottomLeft = fromScreenLocation(new PointF(left, bottom)); - // Map can be rotated, find correct LatLngBounds that encompasses the visible region (that might be rotated) - List<LatLng> boundsPoints = new ArrayList<>(); - boundsPoints.add(topLeft); - boundsPoints.add(topRight); - boundsPoints.add(bottomRight); - boundsPoints.add(bottomLeft); - - // order so that two most northern point are put first - while ((boundsPoints.get(0).getLatitude() < boundsPoints.get(3).getLatitude()) - || (boundsPoints.get(1).getLatitude() < boundsPoints.get(2).getLatitude())) { - LatLng first = boundsPoints.remove(0); - boundsPoints.add(first); - } + latLngs.add(topRight); + latLngs.add(bottomRight); + latLngs.add(bottomLeft); + latLngs.add(topLeft); - double north = boundsPoints.get(0).getLatitude(); - if (north < boundsPoints.get(1).getLatitude()) { - north = boundsPoints.get(1).getLatitude(); - } + double maxEastLonSpan = 0; + double maxWestLonSpan = 0; - double south = boundsPoints.get(2).getLatitude(); - if (south > boundsPoints.get(3).getLatitude()) { - south = boundsPoints.get(3).getLatitude(); + double east = 0; + double west = 0; + double north = GeometryConstants.MIN_LATITUDE; + double south = GeometryConstants.MAX_LATITUDE; + + for (LatLng latLng : latLngs) { + double bearing = bearing(center, latLng); + + if (bearing >= 0) { + double span = getLongitudeSpan(latLng.getLongitude(), center.getLongitude()); + if (span > maxEastLonSpan) { + maxEastLonSpan = span; + east = latLng.getLongitude(); + } + } else { + double span = getLongitudeSpan(center.getLongitude(), latLng.getLongitude()); + if (span > maxWestLonSpan) { + maxWestLonSpan = span; + west = latLng.getLongitude(); + } + } + + if (north < latLng.getLatitude()) { + north = latLng.getLatitude(); + } + if (south > latLng.getLatitude()) { + south = latLng.getLatitude(); + } } - double firstLon = boundsPoints.get(0).getLongitude(); - double secondLon = boundsPoints.get(1).getLongitude(); - double thridLon = boundsPoints.get(2).getLongitude(); - double fourthLon = boundsPoints.get(3).getLongitude(); - - // if it does not go over the date line - if (secondLon > fourthLon && firstLon < thridLon) { - return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, - LatLngBounds.from(north, - secondLon > thridLon ? secondLon : thridLon, - south, - firstLon < fourthLon ? firstLon : fourthLon)); - } else { - return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, - LatLngBounds.from(north, - secondLon < thridLon ? secondLon : thridLon, - south, - firstLon > fourthLon ? firstLon : fourthLon)); + return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, + LatLngBounds.from(north, east, south, west)); + } + + /** + * Takes two {@link Point}s and finds the geographic bearing between them. + * + * @param latLng1 the first point used for calculating the bearing + * @param latLng2 the second point used for calculating the bearing + * @return bearing in decimal degrees + * @see <a href="http://turfjs.org/docs/#bearing">Turf Bearing documentation</a> + */ + static double bearing(@NonNull LatLng latLng1, @NonNull LatLng latLng2) { + + double lon1 = degreesToRadians(latLng1.getLongitude()); + double lon2 = degreesToRadians(latLng2.getLongitude()); + double lat1 = degreesToRadians(latLng1.getLongitude()); + double lat2 = degreesToRadians(latLng2.getLongitude()); + + double value1 = Math.sin(lon2 - lon1) * Math.cos(lat2); + double value2 = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) + * Math.cos(lat2) * Math.cos(lon2 - lon1); + + return radiansToDegrees(Math.atan2(value1, value2)); + } + + /** + * Converts an angle in degrees to radians. + * + * @param degrees angle between 0 and 360 degrees + * @return angle in radians + */ + static double degreesToRadians(double degrees) { + double radians = degrees % 360; + return radians * Math.PI / 180; + } + + /** + * Converts an angle in radians to degrees. + * + * @param radians angle in radians + * @return degrees between 0 and 360 degrees + */ + static double radiansToDegrees(double radians) { + double degrees = radians % (2 * Math.PI); + return degrees * 180 / Math.PI; + } + + /** + * Get the absolute distance, in degrees, between the west and + * east boundaries of this LatLngBounds + * + * @return Span distance + */ + static double getLongitudeSpan(double east, double west) { + double longSpan = Math.abs(east - west); + if (east > west) { + return longSpan; } + + // shortest span contains antimeridian + return GeometryConstants.LONGITUDE_SPAN - longSpan; } /** |