summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOsana Babayan <32496536+osana@users.noreply.github.com>2018-07-27 09:31:33 -0700
committerGitHub <noreply@github.com>2018-07-27 09:31:33 -0700
commitf05199e2d94a085c615aea96c867280e88a6ef6e (patch)
treeb5291b00bb91ba5e8489afc5460e890641378655
parentd4b3befecbde6c19e804707a9aeadc37ae6bd16d (diff)
downloadqtlocation-mapboxgl-f05199e2d94a085c615aea96c867280e88a6ef6e.tar.gz
VisibleRegion on rotated bounds (#12135) (#12255)
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java138
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/VisibleRegionTest.kt48
2 files changed, 148 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..3ecf7354c4 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;
@@ -124,54 +126,114 @@ public class Projection {
bottom = nativeMapView.getHeight() - contentPadding[3];
}
+ LatLng center = fromScreenLocation(new PointF(left + (right - left) / 2, top + (bottom - top) / 2));
+
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);
- }
+ List<LatLng> latLngs = new ArrayList<>();
+ 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 east = 0;
+ double west = 0;
+ double north = GeometryConstants.MIN_LATITUDE;
+ double south = GeometryConstants.MAX_LATITUDE;
- double south = boundsPoints.get(2).getLatitude();
- if (south > boundsPoints.get(3).getLatitude()) {
- south = boundsPoints.get(3).getLatitude();
+ 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.getLatitude());
+ double lat2 = degreesToRadians(latLng2.getLatitude());
+
+ 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;
}
/**
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/VisibleRegionTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/VisibleRegionTest.kt
index f09a5eff00..f0d62dd370 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/VisibleRegionTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/VisibleRegionTest.kt
@@ -2,6 +2,8 @@ package com.mapbox.mapboxsdk.testapp.maps
import android.graphics.PointF
import android.support.test.espresso.UiController
+import com.mapbox.mapboxsdk.camera.CameraPosition
+import com.mapbox.mapboxsdk.camera.CameraUpdate
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.MapView
@@ -336,6 +338,52 @@ class VisibleRegionTest : BaseActivityTest() {
}
}
+ @Test
+ fun visibleRotatedRegionTest() {
+ validateTestSetup()
+ invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
+ val d = Math.min(mapboxMap.width, mapboxMap.height) / 4;
+ val latLngs = listOf(
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
+ )
+
+
+ for (bearing in 45 until 360 step 45) {
+ mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()));
+ val visibleRegion = mapboxMap.projection.visibleRegion
+ assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
+ }
+ }
+ }
+
+ @Test
+ fun visibleRotatedRegionOverDatelineTest() {
+ validateTestSetup()
+ invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
+ val d = Math.min(mapboxMap.width, mapboxMap.height) / 4;
+ val latLngs = listOf(
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
+ )
+
+
+ for (bearing in 45 until 360 step 45) {
+ mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()));
+ val visibleRegion = mapboxMap.projection.visibleRegion
+ assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
+ }
+ }
+ }
+
private fun MapboxMap.getLatLngFromScreenCoords(x: Float, y: Float): LatLng {
return this.projection.fromScreenLocation(PointF(x, y))
}