I'm working on my study android project where I need to place 5 random markers within a 10km radius of my geolocation. Here's my function to generate random coordinates:
fun generateRandomCoordinates(min: Int, max: Int): LatLng {
val coordinates: LatLng
val currentLong: Double
val currentLat: Double
val meterCord = 0.00900900900901 / 1000
//Generate random Meters between the maximum and minimum Meters
val r = Random()
val randomMeters: Int = r.nextInt(max + min)
//then Generating Random numbers for different Methods
val randomPM: Int = r.nextInt(6)
//Then we convert the distance in meters to coordinates by Multiplying number of meters with 1 Meter Coordinate
val metersCordN = meterCord * randomMeters.toDouble()
val locationResult = fusedLocationProviderClient.lastLocation
currentLong = locationResult.result.longitude
currentLat= locationResult.result.latitude
coordinates = when (randomPM) {
0 -> LatLng(currentLat + metersCordN, currentLong + metersCordN)
1 -> LatLng(currentLat - metersCordN, currentLong - metersCordN)
2 -> LatLng(currentLat + metersCordN, currentLong - metersCordN)
3 -> LatLng(currentLat - metersCordN, currentLong + metersCordN)
4 -> LatLng(currentLat, currentLong - metersCordN)
else -> LatLng(currentLat - metersCordN, currentLong)
}
return coordinates
}
that code results with java.lang.IllegalStateException: Task is not yet complete at line currentLong = locationResult.result.longitude
I tried to use addOnCompleteListener but somehow it didn't worked out. So I tried to add Thread.sleep(50) and that works but I think that it's not how sane person should code. How can I solve this problem?
as It can take some time to update the position, you should register a callback for retrieving the current location. Note that this code only returns the last known location, if you want to get updated location continuously, you can use the requestLocationUpdates method.
fusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
// Logic to handle location object
}
}
});
Turn on your location. 2. check whether location is null or not:
fun generateRandomCoordinates(min: Int, max: Int): LatLng {
val coordinates: LatLng
val currentLong: Double
val currentLat: Double
val meterCord = 0.00900900900901 / 1000
//Generate random Meters between the maximum and minimum Meters
val r = Random()
val randomMeters: Int = r.nextInt(max + min)
//then Generating Random numbers for different Methods
val randomPM: Int = r.nextInt(6)
//Then we convert the distance in meters to coordinates by Multiplying
number of meters with 1 Meter Coordinate
val metersCordN = meterCord * randomMeters.toDouble()
val locationResult = fusedLocationProviderClient.lastLocation
if (location != null) { //<------
currentLong = locationResult.result.longitude
currentLat= locationResult.result.latitude
coordinates = when (randomPM) {
0 -> LatLng(currentLat + metersCordN, currentLong + metersCordN)
1 -> LatLng(currentLat - metersCordN, currentLong - metersCordN)
2 -> LatLng(currentLat + metersCordN, currentLong - metersCordN)
3 -> LatLng(currentLat - metersCordN, currentLong + metersCordN)
4 -> LatLng(currentLat, currentLong - metersCordN)
else -> LatLng(currentLat - metersCordN, currentLong)
}
return coordinates
} else { //<------
Toast.makeText(getActivity(), "Null location!",
Toast.LENGTH_LONG).show();
}
}
If the above code returned else part, then most likely your last location is empty (if you are using emulator!) In emulator like BlueStacks Ctrl+Shift +K (for other emulators see this post: How to emulate GPS location in the Android Emulator?) and set a location, then try your code again.
Related
how can I get the Distance out of Mapbox Navigation Route? in Double Format, I don't want to draw the route I just need to calculate the distance between two Points, I have been able to calculate the distance using Truf
Storelocation = Point.fromLngLat(Stores.latitude, Stores.longitude)
Userlocation = Point.fromLngLat(UserLocation.Latitude, UserLocation.Longitude)
Distance = TurfMeasurement.distance(Storelocation, Userlocation, TurfConstants.UNIT_KILOMETERS)
but the problem is with this method above it doesn't calculate distance within the route, it is just calculate straight line from point to point for example in Google map the distance is 9 Km, but with this method above the distance is 6 Km
private fun getRout(){
NavigationRoute.builder(this)
.accessToken(Mapbox.getAccessToken()!!)
.origin(Userlocation)
.destination(Storelocation).build().getRoute(object :Callback<DirectionsResponse> {
override fun onResponse(call: Call<DirectionsResponse>, response: Response<DirectionsResponse>) {
val rout = response ?: return
val body = rout.body() ?: return
if (body.routes().count() == 0 ){
return
}
navigationMapRoute = NavigationMapRoute(null, mapView, map)
// Get Distance
Distance = ??
}
override fun onFailure(call: Call<DirectionsResponse>, t: Throwable) {
}
})
}
Instead of this:
navigationMapRoute = NavigationMapRoute(null, mapView, map)
// Get Distance
Distance = ??
Do this:
val route = response.body().routes().get(0)
val distance = route.distance()
I am building an Android application to measure 1km from a start position while driving.
i tried this : https://github.com/quentin7b/android-location-tracker/blob/master/README.md
val settings = TrackerSettings()
.setUseNetwork(true)
.setUseGPS(true)
.setUsePassive(false)
.setTimeBetweenUpdates(1000)
.setMetersBetweenUpdates(10F)
And i change postions to get distance between to position using:
val distance = currentPosition!!.distanceTo(location)
totalDistance += distance
But the result is not precise, anyone how can give a better solution
private fun distance(
startLatitude: Double,
startLongitude: Double,
endLatitude: Double,
endLongitude: Double,
unit: String
): String {
val theta = startLongitude - endLongitude
var dist: Double = sin(deg2rad(startLatitude)) * sin(deg2rad(endLatitude)) +
cos(deg2rad(startLatitude)) * cos(deg2rad(endLatitude)) * cos(deg2rad(theta))
dist = acos(dist)
dist = rad2deg(dist)
dist *= 60 * 1.1515 //miles
if (unit == "k") {
dist *= 1.609344 // km
}
return dist.toString()
}
private fun deg2rad(deg: Double): Double {
return deg * 3.1415926535897932 / 180.0
}
private fun rad2deg(rad: Double): Double {
return rad * 180.0 / 3.1415926535897932
}
You can use android.location.Location.distanceBetween() method which does this quite well. For more info
I'm using Google Places api in my app which calculate the distance between 2 address,
the problem is that I get less distance than in google maps.
I cannot get the same accuracy as Google maps,
Most of the time distance is shorter than the result from Google Maps
private fun SetupPlacesAutocompleteFun() {
val _autocompletFragment1 = supportFragmentManager
.findFragmentById(R.id.fragmentPlaces1) as AutocompleteSupportFragment
_autocompletFragment1.setPlaceFields(_placesFields)
_autocompletFragment1.setOnPlaceSelectedListener(object:PlaceSelectionListener{
override fun onPlaceSelected(p1: Place) {
_adrees1 = p1.latLng!!
_adressString1 = p1.address!!
}
override fun onError(p1: Status) {
Toast.makeText(this#GooglePlaces_Activity,"status "+p1.statusMessage,Toast.LENGTH_LONG).show()
}
})
val _autocompletFragment2 = supportFragmentManager
.findFragmentById(R.id.fragmentPlaces2) as AutocompleteSupportFragment
_autocompletFragment2.setPlaceFields(_placesFields)
_autocompletFragment2.setOnPlaceSelectedListener(object :PlaceSelectionListener{
override fun onPlaceSelected(p2: Place) {
_adress2 =p2.latLng!!
_adressString2 = p2.address!!
}
override fun onError(p2: Status) {
Toast.makeText(this#GooglePlaces_Activity,"status "+p2.statusMessage,Toast.LENGTH_LONG).show()
}
})
}
private fun InitPlacesFun() {
Places.initialize(this,getString(R.string.Places_api))
_placcesClint = Places.createClient(this)
}
fun TestButtonFun () {
button.setOnClickListener() {
var _loc:Location= Location("start")
_loc.latitude = _adrees1.latitude
_loc.longitude = _adrees1.longitude
var _loc2:Location= Location("start")
_loc2.latitude = _adress2.latitude
_loc2.longitude = _adress2.longitude
dist = (round(((_loc.distanceTo(_loc2).toDouble()/1000))*100) /100).toDouble()
}
I have also tried this:
var _Lat1 = _adrees1.latitude
var _Lat2 = _adress2.latitude
var _Long1 = _adrees1.longitude
var _Long2 = _adress2.longitude
var _LatRes = _Lat1 - _Lat2
var _longRes = _Long1 - _Long2
var R = 6371000f; // Radius of the earth in m
var dLat = _LatRes * Math.PI / 180f;
var dLon = _longRes * Math.PI / 180f;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(_Lat1 * Math.PI / 180f) * Math.cos(_Lat2 * Math.PI / 180f) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2f * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
dist = R* c
You get less distance because you're calculating the radial distance and not the actual route distance.
Try calculating the distance using google directions API.
You can see the difference between radial distance (orange) and actual distance (blue) in the image
I've got the following Unit function:
private fun loadFilterArea() {
val query = ALIAS.AREA
val type = preferences.getInt(query, TYPEVALUES.MY_LOCATION)
val longitude: Double
val latitude: Double
when (type) {
TYPEVALUES.MY_LOCATION -> {
...
longitude = point.longitude
latitude = point.latitude
...
}
TYPEVALUES.CUSTOM_RADIUS -> {
...
longitude = point.longitude
latitude = point.latitude
...
}
TYPEVALUES.INPUT -> {
...
longitude = preferences.getFloat(ALIAS.AREA_LONGITUDE, 0f).toDouble()
latitude = preferences.getFloat(ALIAS.AREA_LATITUDE, 0f) .toDouble()
...
} else -> {
...
}
}
//... the question is here ...
//... can't be compiled cause val's are not initialized
if (longitude != null && latitude != null) {
storeKey(ALIAS.AREA_LONGITUDE, longitude)
storeKey(ALIAS.AREA_LATITUDE, latitude)
}
}
So, how can check if values longitude and latitude are initialized ?
I don't want to move them from function to global scope and use them as lateinit with further ::latitude.isInitialized, and it seems like my version of Kotlin doesn't support local lateinit variables
If it makes sense to have null values for latitude and longitude for your use case, then you can define those variables as nullable Double, e.g., var latitude: Double? = null (the same for longitude). After that, it makes sense to check if they're not null, but the variable becomes no more immutable.
In order to keep immutability, you can do something like that:
val longitude: Double?
val latitude: Double?
when (type) {
TYPEVALUES.MY_LOCATION -> {
longitude = ...
latitude = ...
...
}
TYPEVALUES.CUSTOM_RADIUS -> {
longitude = ...
latitude = ...
...
}
TYPEVALUES.INPUT -> {
...
} else -> {
latitude = null
longitude = null
}
}
Otherwise, if you want them to be non-nullable, then you need to provide a meaningful, non-null value in all branches of the when statement.
You could use the power of when to store the value directly, so that declaration and assignments are done at the same time:
val (latitude, longitude) = when (type) {
TYPEVALUES.MY_LOCATION -> Pair(0.0, 0.0)
TYPEVALUES.CUSTOM_RADIUS -> Pair(1.0, 1.0)
else -> Pair(2d, 2d)
}
//Your latitude is a double
//Your longitude is a double
I am trying to convert my result from kilometers to miles but the result I get isn't correct.
What seems to be the problem here?
when {
// TIME: To calculate your time, fill in your distance and pace
time == null -> {
val calculatedTime = distance!!.toLong() * timeToSeconds(pace.toString())
result.text = "The runner's time is ${secondsToTime(calculatedTime)}"
}
// DISTANCE: To calculate your distance, fill in your time and pace
distance == null -> {
val calculatedDistance = ((timeToSeconds(time).div(timeToSeconds
(pace.toString()))) * 0.621371).format(2)
result.text = "Distance is $calculatedDistance Miles"
}
// PACE: To calculate your pace, fill in your time and distance
pace == null -> {
// Calculate Pace
val calculatedPace: Long = timeToSeconds(time).toLong() / distance.toLong()
Log.i("PaceSeconds", calculatedPace.toString() +
secondsToTime(calculatedPace))
result.text = "The runner's pace in miles is ${secondsToTime(calculatedPace)}"
}
}
This is a rounding issue. Lets break it down:
val timeInSeconds = timeToSeconds(time)
val paceInSeconds = timeToSeconds(pace)
val timeDivPace = timeInSeconds.div(paceInSeconds)
val calculatedDistance = timeDivPace * 0.621371
Using the sample data from your comment, timeInSeconds is 612 and paceInSeconds is 83. You expect timeDivPace to be 7.373494 but it actually is 7 because a division of two integers returns an integer as result.
The fix is simple: convert either the dividend or the divisor to float, e.g.:
val timeDivPace = timeInSeconds.div(paceInSeconds.toFloat())