mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Merge pull request #692 from tobias47n9e/feature/location-marker
Add a marker and circle of accuracy for current location
This commit is contained in:
commit
8104556c65
12 changed files with 140 additions and 44 deletions
|
|
@ -29,7 +29,7 @@ public class NearbyControllerTest {
|
|||
}
|
||||
|
||||
@Test public void testNullAttractions() {
|
||||
LatLng location = new LatLng(0, 0);
|
||||
LatLng location = new LatLng(0, 0, 0);
|
||||
|
||||
List<NearbyBaseMarker> options =
|
||||
NearbyController.loadAttractionsFromLocationToBaseMarkerOptions(
|
||||
|
|
@ -42,7 +42,7 @@ public class NearbyControllerTest {
|
|||
}
|
||||
|
||||
@Test public void testEmptyList() {
|
||||
LatLng location = new LatLng(0, 0);
|
||||
LatLng location = new LatLng(0, 0, 0);
|
||||
List<Place> emptyList = new ArrayList<>();
|
||||
|
||||
List<NearbyBaseMarker> options =
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ public class MediaDataExtractor {
|
|||
NodeList childNodes = parentNode.getChildNodes();
|
||||
double latitudeText = Double.parseDouble(childNodes.item(1).getTextContent());
|
||||
double longitudeText = Double.parseDouble(childNodes.item(2).getTextContent());
|
||||
LatLng coordinates = new LatLng(latitudeText, longitudeText);
|
||||
LatLng coordinates = new LatLng(latitudeText, longitudeText, 0);
|
||||
|
||||
return coordinates.getPrettyCoordinateString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ package fr.free.nrw.commons.location;
|
|||
|
||||
public class LatLng {
|
||||
|
||||
public final double latitude;
|
||||
public final double longitude;
|
||||
private final double latitude;
|
||||
private final double longitude;
|
||||
private final float accuracy;
|
||||
|
||||
/** Accepts latitude and longitude.
|
||||
* North and South values are cut off at 90°
|
||||
|
|
@ -11,13 +12,14 @@ public class LatLng {
|
|||
* @param latitude double value
|
||||
* @param longitude double value
|
||||
*/
|
||||
public LatLng(double latitude, double longitude) {
|
||||
public LatLng(double latitude, double longitude, float accuracy) {
|
||||
if(-180.0D <= longitude && longitude < 180.0D) {
|
||||
this.longitude = longitude;
|
||||
} else {
|
||||
this.longitude = ((longitude - 180.0D) % 360.0D + 360.0D) % 360.0D - 180.0D;
|
||||
}
|
||||
this.latitude = Math.max(-90.0D, Math.min(90.0D, latitude));
|
||||
this.accuracy = accuracy;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
|
|
@ -93,4 +95,31 @@ public class LatLng {
|
|||
return formatCoordinate(this.latitude) + " " + this.getNorthSouth() + ", "
|
||||
+ formatCoordinate(this.longitude) + " " + this.getEastWest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location accuracy in meter.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public float getAccuracy() {
|
||||
return accuracy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the longitude in degrees.
|
||||
*
|
||||
* @return double
|
||||
*/
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the latitude in degrees.
|
||||
*
|
||||
* @return double
|
||||
*/
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public class LocationServiceManager implements LocationListener {
|
|||
private String provider;
|
||||
private LocationManager locationManager;
|
||||
private LatLng latestLocation;
|
||||
private Float latestLocationAccuracy;
|
||||
|
||||
public LocationServiceManager(Context context) {
|
||||
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
|
|
@ -24,6 +25,16 @@ public class LocationServiceManager implements LocationListener {
|
|||
return latestLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the accuracy of the location. The measurement is
|
||||
* given as a radius in meter of 68 % confidence.
|
||||
*
|
||||
* @return Float
|
||||
*/
|
||||
public Float getLatestLocationAccuracy() {
|
||||
return latestLocationAccuracy;
|
||||
}
|
||||
|
||||
/** Registers a LocationManager to listen for current location.
|
||||
*/
|
||||
public void registerLocationManager() {
|
||||
|
|
@ -57,9 +68,11 @@ public class LocationServiceManager implements LocationListener {
|
|||
public void onLocationChanged(Location location) {
|
||||
double currentLatitude = location.getLatitude();
|
||||
double currentLongitude = location.getLongitude();
|
||||
Timber.d("Latitude: %f Longitude: %f", currentLatitude, currentLongitude);
|
||||
latestLocationAccuracy = location.getAccuracy();
|
||||
Timber.d("Latitude: %f Longitude: %f Accuracy %f",
|
||||
currentLatitude, currentLongitude, latestLocationAccuracy);
|
||||
|
||||
latestLocation = new LatLng(currentLatitude, currentLongitude);
|
||||
latestLocation = new LatLng(currentLatitude, currentLongitude, latestLocationAccuracy);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -109,8 +109,8 @@ public class NearbyController {
|
|||
nearbyBaseMarker.title(place.name);
|
||||
nearbyBaseMarker.position(
|
||||
new com.mapbox.mapboxsdk.geometry.LatLng(
|
||||
place.location.latitude,
|
||||
place.location.longitude));
|
||||
place.location.getLatitude(),
|
||||
place.location.getLongitude()));
|
||||
nearbyBaseMarker.place(place);
|
||||
nearbyBaseMarker.icon(icon);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class NearbyInfoDialog extends OverlayDialog {
|
|||
Bundle bundle = getArguments();
|
||||
placeTitle.setText(bundle.getString(ARG_TITLE));
|
||||
placeDescription.setText(bundle.getString(ARG_DESC));
|
||||
location = new LatLng(bundle.getDouble(ARG_LATITUDE), bundle.getDouble(ARG_LONGITUDE));
|
||||
location = new LatLng(bundle.getDouble(ARG_LATITUDE), bundle.getDouble(ARG_LONGITUDE), 0);
|
||||
getArticleLink(bundle);
|
||||
}
|
||||
|
||||
|
|
@ -122,8 +122,8 @@ public class NearbyInfoDialog extends OverlayDialog {
|
|||
Bundle bundle = new Bundle();
|
||||
bundle.putString(ARG_TITLE, place.name);
|
||||
bundle.putString(ARG_DESC, place.description);
|
||||
bundle.putDouble(ARG_LATITUDE, place.location.latitude);
|
||||
bundle.putDouble(ARG_LONGITUDE, place.location.longitude);
|
||||
bundle.putDouble(ARG_LATITUDE, place.location.getLatitude());
|
||||
bundle.putDouble(ARG_LONGITUDE, place.location.getLongitude());
|
||||
bundle.putParcelable(ARG_SITE_LINK, place.siteLinks);
|
||||
mDialog.setArguments(bundle);
|
||||
DialogUtil.showSafely(fragmentActivity, mDialog);
|
||||
|
|
@ -138,7 +138,8 @@ public class NearbyInfoDialog extends OverlayDialog {
|
|||
@OnClick(R.id.link_preview_directions_button)
|
||||
void onDirectionsClick() {
|
||||
//Open map app at given position
|
||||
Uri gmmIntentUri = Uri.parse("geo:0,0?q=" + location.latitude + "," + location.longitude);
|
||||
Uri gmmIntentUri = Uri.parse(
|
||||
"geo:0,0?q=" + location.getLatitude() + "," + location.getLongitude());
|
||||
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
|
||||
|
||||
if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) {
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ public class NearbyListFragment extends ListFragment {
|
|||
Place place = (Place) listview.getItemAtPosition(position);
|
||||
LatLng placeLatLng = place.location;
|
||||
|
||||
double latitude = placeLatLng.latitude;
|
||||
double longitude = placeLatLng.longitude;
|
||||
double latitude = placeLatLng.getLatitude();
|
||||
double longitude = placeLatLng.getLongitude();
|
||||
|
||||
Timber.d("Item at position %d has coords: Lat: %f Long: %f", position, latitude, longitude);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.nearby;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
|
@ -14,6 +15,8 @@ import com.google.gson.GsonBuilder;
|
|||
import com.google.gson.reflect.TypeToken;
|
||||
import com.mapbox.mapboxsdk.Mapbox;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.constants.Style;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
|
@ -24,6 +27,7 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
|||
import com.mapbox.services.android.telemetry.MapboxTelemetry;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
|
|
@ -79,7 +83,7 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
|||
MapboxMapOptions options = new MapboxMapOptions()
|
||||
.styleUrl(Style.OUTDOORS)
|
||||
.camera(new CameraPosition.Builder()
|
||||
.target(new LatLng(curLatLng.latitude, curLatLng.longitude))
|
||||
.target(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude()))
|
||||
.zoom(11)
|
||||
.build());
|
||||
|
||||
|
|
@ -102,6 +106,8 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
|||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
addCurrentLocationMarker(mapboxMap);
|
||||
}
|
||||
});
|
||||
if (PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean("theme",true)) {
|
||||
|
|
@ -111,6 +117,53 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a marker for the user's current position. Adds a
|
||||
* circle which uses the accuracy * 2, to draw a circle
|
||||
* which represents the user's position with an accuracy
|
||||
* of 95%.
|
||||
*/
|
||||
public void addCurrentLocationMarker(MapboxMap mapboxMap) {
|
||||
MarkerOptions currentLocationMarker = new MarkerOptions()
|
||||
.position(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude()));
|
||||
mapboxMap.addMarker(currentLocationMarker);
|
||||
|
||||
List<LatLng> circle = createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(),
|
||||
curLatLng.getAccuracy() * 2, 100);
|
||||
|
||||
mapboxMap.addPolygon(
|
||||
new PolygonOptions()
|
||||
.addAll(circle)
|
||||
.strokeColor(Color.parseColor("#55000000"))
|
||||
.fillColor(Color.parseColor("#11000000"))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a series of points that create a circle on the map.
|
||||
* Takes the center latitude, center longitude of the circle,
|
||||
* the radius in meter and the number of nodes of the circle.
|
||||
*
|
||||
* @return List List of LatLng points of the circle.
|
||||
*/
|
||||
public List<LatLng> createCircleArray(
|
||||
double centerLat, double centerLong, float radius, int nodes) {
|
||||
List<LatLng> circle = new ArrayList<>();
|
||||
float radiusKilometer = radius / 1000;
|
||||
double radiusLong = radiusKilometer
|
||||
/ (111.320 * Math.cos(centerLat * Math.PI / 180));
|
||||
double radiusLat = radiusKilometer / 110.574;
|
||||
|
||||
for (int i = 0; i < nodes; i++) {
|
||||
double theta = ((double) i / (double) nodes) * (2 * Math.PI);
|
||||
double nodeLongitude = centerLong + radiusLong * Math.cos(theta);
|
||||
double nodeLatitude = centerLat + radiusLat * Math.sin(theta);
|
||||
circle.add(new LatLng(nodeLatitude, nodeLongitude));
|
||||
}
|
||||
|
||||
return circle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ public class NearbyPlaces {
|
|||
|
||||
String query = wikidataQuery
|
||||
.replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
|
||||
.replace("${LAT}", String.format(Locale.ROOT, "%.4f", cur.latitude))
|
||||
.replace("${LONG}", String.format(Locale.ROOT, "%.4f", cur.longitude))
|
||||
.replace("${LAT}", String.format(Locale.ROOT, "%.4f", cur.getLatitude()))
|
||||
.replace("${LONG}", String.format(Locale.ROOT, "%.4f", cur.getLongitude()))
|
||||
.replace("${LANG}", lang);
|
||||
|
||||
Timber.v("# Wikidata query: \n" + query);
|
||||
|
|
@ -125,7 +125,7 @@ public class NearbyPlaces {
|
|||
type, // list
|
||||
type, // details
|
||||
Uri.parse(icon),
|
||||
new LatLng(latitude, longitude),
|
||||
new LatLng(latitude, longitude, 0),
|
||||
new Sitelinks.Builder()
|
||||
.setWikipediaLink(wikipediaSitelink)
|
||||
.setCommonsLink(commonsSitelink)
|
||||
|
|
@ -187,7 +187,7 @@ public class NearbyPlaces {
|
|||
type, // list
|
||||
type, // details
|
||||
null,
|
||||
new LatLng(latitude, longitude),
|
||||
new LatLng(latitude, longitude, 0),
|
||||
new Sitelinks.Builder().build()
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ public class LengthUtils {
|
|||
}
|
||||
|
||||
private static double computeAngleBetween(LatLng from, LatLng to) {
|
||||
return distanceRadians(Math.toRadians(from.latitude),
|
||||
Math.toRadians(from.longitude),
|
||||
Math.toRadians(to.latitude),
|
||||
Math.toRadians(to.longitude));
|
||||
return distanceRadians(Math.toRadians(from.getLatitude()),
|
||||
Math.toRadians(from.getLongitude()),
|
||||
Math.toRadians(to.getLatitude()),
|
||||
Math.toRadians(to.getLongitude()));
|
||||
}
|
||||
|
||||
private static double distanceRadians(double lat1, double lng1, double lat2, double lng2) {
|
||||
|
|
|
|||
|
|
@ -9,55 +9,55 @@ import org.junit.Test;
|
|||
|
||||
public class LatLngTests {
|
||||
@Test public void testZeroZero() {
|
||||
LatLng place = new LatLng(0, 0);
|
||||
LatLng place = new LatLng(0, 0, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("0.0 N, 0.0 E"));
|
||||
}
|
||||
|
||||
@Test public void testAntipode() {
|
||||
LatLng place = new LatLng(0, 180);
|
||||
LatLng place = new LatLng(0, 180, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("0.0 N, 180.0 W"));
|
||||
}
|
||||
|
||||
@Test public void testNorthPole() {
|
||||
LatLng place = new LatLng(90, 0);
|
||||
LatLng place = new LatLng(90, 0, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("90.0 N, 0.0 E"));
|
||||
}
|
||||
|
||||
@Test public void testSouthPole() {
|
||||
LatLng place = new LatLng(-90, 0);
|
||||
LatLng place = new LatLng(-90, 0, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("90.0 S, 0.0 E"));
|
||||
}
|
||||
|
||||
@Test public void testLargerNumbers() {
|
||||
LatLng place = new LatLng(120, 380);
|
||||
LatLng place = new LatLng(120, 380, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("90.0 N, 20.0 E"));
|
||||
}
|
||||
|
||||
@Test public void testNegativeNumbers() {
|
||||
LatLng place = new LatLng(-120, -30);
|
||||
LatLng place = new LatLng(-120, -30, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("90.0 S, 30.0 W"));
|
||||
}
|
||||
|
||||
@Test public void testTooBigWestValue() {
|
||||
LatLng place = new LatLng(20, -190);
|
||||
LatLng place = new LatLng(20, -190, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("20.0 N, 170.0 E"));
|
||||
}
|
||||
|
||||
@Test public void testRounding() {
|
||||
LatLng place = new LatLng(0.1234567, -0.33333333);
|
||||
LatLng place = new LatLng(0.1234567, -0.33333333, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("0.1235 N, 0.3333 W"));
|
||||
}
|
||||
|
||||
@Test public void testRoundingAgain() {
|
||||
LatLng place = new LatLng(-0.000001, -0.999999);
|
||||
LatLng place = new LatLng(-0.000001, -0.999999, 0);
|
||||
String prettyString = place.getPrettyCoordinateString();
|
||||
Assert.assertThat(prettyString, is("0.0 S, 1.0 W"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,36 +10,36 @@ import org.junit.Test;
|
|||
|
||||
public class LengthUtilsTest {
|
||||
@Test public void testZeroDistance() {
|
||||
LatLng pointA = new LatLng(0, 0);
|
||||
LatLng pointB = new LatLng(0, 0);
|
||||
LatLng pointA = new LatLng(0, 0, 0);
|
||||
LatLng pointB = new LatLng(0, 0, 0);
|
||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
||||
Assert.assertThat(distance, is("0m"));
|
||||
}
|
||||
|
||||
@Test public void testOneDegreeOnEquator() {
|
||||
LatLng pointA = new LatLng(0, 0);
|
||||
LatLng pointB = new LatLng(0, 1);
|
||||
LatLng pointA = new LatLng(0, 0, 0);
|
||||
LatLng pointB = new LatLng(0, 1, 0);
|
||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
||||
Assert.assertThat(distance, is("111.2km"));
|
||||
}
|
||||
|
||||
@Test public void testOneDegreeFortyFiveDegrees() {
|
||||
LatLng pointA = new LatLng(45, 0);
|
||||
LatLng pointB = new LatLng(45, 1);
|
||||
LatLng pointA = new LatLng(45, 0, 0);
|
||||
LatLng pointB = new LatLng(45, 1, 0);
|
||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
||||
Assert.assertThat(distance, is("78.6km"));
|
||||
}
|
||||
|
||||
@Test public void testOneDegreeSouthPole() {
|
||||
LatLng pointA = new LatLng(-90, 0);
|
||||
LatLng pointB = new LatLng(-90, 1);
|
||||
LatLng pointA = new LatLng(-90, 0, 0);
|
||||
LatLng pointB = new LatLng(-90, 1, 0);
|
||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
||||
Assert.assertThat(distance, is("0m"));
|
||||
}
|
||||
|
||||
@Test public void testPoleToPole() {
|
||||
LatLng pointA = new LatLng(90, 0);
|
||||
LatLng pointB = new LatLng(-90, 0);
|
||||
LatLng pointA = new LatLng(90, 0, 0);
|
||||
LatLng pointB = new LatLng(-90, 0, 0);
|
||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
||||
Assert.assertThat(distance, is("20,015.1km"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue