[projection] add bulk conversion of geographic coordinates to screen coordinates with reusable objects (#91)
This commit is contained in:
@@ -7,6 +7,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
|
||||
### Features
|
||||
- Introduce OfflineManager.runPackDatabaseAutomatically(boolean) and remove the redundant OfflineRegion.deleteAndSkipPackDatabase() method [#78](https://github.com/mapbox/mapbox-gl-native-android/pull/78)
|
||||
- Expose getter for the view used for rendering OpenGL content on [#87](https://github.com/mapbox/mapbox-gl-native-android/pull/87)
|
||||
- Bulk conversion of geographic coordinates to screen coordinate using reusable double arrays. [#91](https://github.com/mapbox/mapbox-gl-native-android/pull/91)
|
||||
|
||||
### Performance improvements
|
||||
- Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950))
|
||||
|
||||
@@ -193,8 +193,12 @@ interface NativeMap {
|
||||
@NonNull
|
||||
PointF pixelForLatLng(@NonNull LatLng latLng);
|
||||
|
||||
void pixelsForLatLngs(@NonNull double[] input, @NonNull double[] output);
|
||||
|
||||
LatLng latLngForPixel(@NonNull PointF pixel);
|
||||
|
||||
void latLngsForPixels(@NonNull double[] input, @NonNull double[] output);
|
||||
|
||||
//
|
||||
// Utils API
|
||||
//
|
||||
|
||||
@@ -651,6 +651,13 @@ final class NativeMapView implements NativeMap {
|
||||
return pointF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pixelsForLatLngs(@NonNull double[] input, @NonNull double[] output) {
|
||||
if (!checkState("pixelsForLatLngs")) {
|
||||
nativePixelsForLatLngs(input, output, pixelRatio);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LatLng latLngForPixel(@NonNull PointF pixel) {
|
||||
if (checkState("latLngForPixel")) {
|
||||
@@ -659,6 +666,14 @@ final class NativeMapView implements NativeMap {
|
||||
return nativeLatLngForPixel(pixel.x / pixelRatio, pixel.y / pixelRatio);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void latLngsForPixels(@NonNull double[] input, @NonNull double[] output) {
|
||||
if (!checkState("latLngsForPixels")) {
|
||||
nativeLatLngsForPixels(input, output, pixelRatio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) {
|
||||
if (checkState("getTopOffsetPixelsForAnnotationSymbol")) {
|
||||
@@ -1275,10 +1290,16 @@ final class NativeMapView implements NativeMap {
|
||||
@Keep
|
||||
private native PointF nativePixelForLatLng(double lat, double lon);
|
||||
|
||||
@Keep
|
||||
private native void nativePixelsForLatLngs(double[] input, double[] output, float pixelRatio);
|
||||
|
||||
@NonNull
|
||||
@Keep
|
||||
private native LatLng nativeLatLngForPixel(float x, float y);
|
||||
|
||||
@Keep
|
||||
private native void nativeLatLngsForPixels(double[] input, double[] output, float pixelRatio);
|
||||
|
||||
@Keep
|
||||
private native double nativeGetTopOffsetPixelsForAnnotationSymbol(String symbolName);
|
||||
|
||||
|
||||
@@ -95,6 +95,19 @@ public class Projection {
|
||||
return nativeMapView.latLngForPixel(point);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the geographic locations that corresponds to screen locations.
|
||||
* The screen locations are specified in screen pixels (not display pixels) relative to the
|
||||
* top left of the map (not the top left of the whole screen).
|
||||
*
|
||||
* @param input an array of input values representing screen coordinates
|
||||
* @param output an array of output values representing geographic locations
|
||||
*/
|
||||
public void fromScreenLocations(@NonNull double[] input, @NonNull double[] output) {
|
||||
nativeMapView.latLngsForPixels(input, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a projection of the viewing frustum for converting between screen coordinates and
|
||||
* geo-latitude/longitude coordinates.
|
||||
@@ -263,6 +276,18 @@ public class Projection {
|
||||
return nativeMapView.pixelForLatLng(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a screen locations that corresponds to a geographical coordinates.
|
||||
* The screen locations are in screen pixels (not display pixels) relative to the top left
|
||||
* of the map (not of the whole screen).
|
||||
*
|
||||
* @param input an array of input values representing geographic locations
|
||||
* @param output an array of output values representing screen coordinates
|
||||
*/
|
||||
public void toScreenLocations(@NonNull double[] input, @NonNull double[] output) {
|
||||
nativeMapView.pixelsForLatLngs(input, output);
|
||||
}
|
||||
|
||||
float getHeight() {
|
||||
return mapView.getHeight();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.mapbox.mapboxsdk.testapp.maps
|
||||
|
||||
import android.graphics.PointF
|
||||
import android.support.test.rule.ActivityTestRule
|
||||
import android.support.test.runner.AndroidJUnit4
|
||||
import com.mapbox.mapboxsdk.AppCenter
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng
|
||||
import com.mapbox.mapboxsdk.maps.MapView
|
||||
import com.mapbox.mapboxsdk.testapp.R
|
||||
import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ScreenCoordinateConversion : AppCenter() {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(DeviceIndependentTestActivity::class.java)
|
||||
|
||||
private lateinit var mapView: MapView
|
||||
private lateinit var latch: CountDownLatch
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
latch = CountDownLatch(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToScreenCoordinates() {
|
||||
rule.runOnUiThread {
|
||||
mapView = rule.activity.findViewById(R.id.mapView)
|
||||
val expected = doubleArrayOf(261.6888889445351, 253.15541110551123, 267.37777788907033, 247.4627648056528)
|
||||
val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
mapView.getMapAsync {
|
||||
val projection = it.projection
|
||||
projection.toScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual)
|
||||
// check all values
|
||||
assertTrue(expected.contentEquals(actual))
|
||||
// check first coordinate value
|
||||
val pointFirst = PointF(expected[0].toFloat(), expected[1].toFloat())
|
||||
val convertedFirst = projection.toScreenLocation(LatLng(1.0, 2.0))
|
||||
assertEquals(
|
||||
pointFirst.x, convertedFirst.x, DELTA_FLOAT
|
||||
)
|
||||
assertEquals(
|
||||
pointFirst.y, convertedFirst.y, DELTA_FLOAT
|
||||
)
|
||||
|
||||
// check second latlng value
|
||||
val pointSecond = PointF(expected[2].toFloat(), expected[3].toFloat())
|
||||
val convertedSecond = projection.toScreenLocation(LatLng(3.0, 4.0))
|
||||
assertEquals(
|
||||
pointSecond.x, convertedSecond.x, DELTA_FLOAT
|
||||
)
|
||||
assertEquals(
|
||||
pointSecond.y, convertedSecond.y, DELTA_FLOAT
|
||||
)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
latch.await(10, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFromScreenCoordinates() {
|
||||
rule.runOnUiThread {
|
||||
mapView = rule.activity.findViewById(R.id.mapView)
|
||||
val expected = doubleArrayOf(66.2314571265913, -89.64843662311537, 65.94647142295494, -88.94531162999371)
|
||||
val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
mapView.getMapAsync {
|
||||
val projection = it.projection
|
||||
projection.fromScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual)
|
||||
// check all values at once
|
||||
assertTrue(expected.contentEquals(actual))
|
||||
|
||||
// check first latlng value
|
||||
val latLngFirst = LatLng(expected[0], expected[1])
|
||||
val convertedFirst = projection.fromScreenLocation(PointF(1.0f, 2.0f))
|
||||
assertEquals(
|
||||
latLngFirst.latitude, convertedFirst.latitude, DELTA_DOUBLE
|
||||
)
|
||||
assertEquals(
|
||||
latLngFirst.longitude, convertedFirst.longitude, DELTA_DOUBLE
|
||||
)
|
||||
|
||||
// check second latlng value
|
||||
val latLngSecond = LatLng(expected[2], expected[3])
|
||||
val convertedSecond = projection.fromScreenLocation(PointF(3.0f, 4.0f))
|
||||
assertEquals(
|
||||
latLngSecond.latitude, convertedSecond.latitude, DELTA_DOUBLE
|
||||
)
|
||||
assertEquals(
|
||||
latLngSecond.longitude, convertedSecond.longitude, DELTA_DOUBLE
|
||||
)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
latch.await(10, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DELTA_DOUBLE = 0.000001
|
||||
const val DELTA_FLOAT = 0.000001f
|
||||
}
|
||||
}
|
||||
2
vendor/mapbox-gl-native
vendored
2
vendor/mapbox-gl-native
vendored
Submodule vendor/mapbox-gl-native updated: e373d8a592...1ac3e9e9c2
Reference in New Issue
Block a user