Get distance and draw line between two location android google maps - java

I have a app that opens the map and zooms on my location with a marker
and then if i longClick on any place it saves that location in database
everything works fine but one thing i cannot manage is draw a line of path between two location markers.
these are three global variables
Location myLocation;
LatLng onmaplongclicklastlatlng;
private GoogleMap mMap;
mylocation is assigned by LocationListener and onmaplongclicklastlatlng is assigned when i long click on any place on the map.
placing the marker on both location is done i already have the two points i want to draw the line on.
i just need to draw a line between those two locations (my current location periodically updated in the myLocation variable)
and onmaplongclicklastlatlng changed whenever i long click on the map.
the whole code is done and i have a button that i want to use to draw the line
since i can access the two location variables from this button method, Other code need not be changed.
public void getLine(View view) {
// need to draw a line here from user gps posiution to the marker location
}
i have tried many tutorials but they do not work for some reason, any help would be really appreciated.
oh and last but not least
onmaplongclicklastlatlng
is a LatLng and
myLocation
is a Location
but they can be interchanged to fit the purpose
ex. Location maplocation = new Location(onmaplongclicklastlatlng
.latitude, onmaplongclicklastlatlng.longitude);
and
Latlng myLatLng = new LatLng(myLocation.getLatitude(), myLocation.getLongitude());
As i said any help would be really appreciated.
And let me know if anything else needed i will edit the question then.

To calculate accurate distance between two loaction you have to use Google Map Distance Matrix API. Construct your url like below.
https://maps.googleapis.com/maps/api/distancematrix/json?" +"origin=" + origin.latitude + "," + origin.longitude+ "&" +"destination=" + dest.latitude + "," + dest.longitude +"&sensor=false&units=metric&mode=driving" + "&" + key=YOUR_API_KEY
And to draw line between two location you have to first use the Google Map Direction Api, construct your url like below
https://maps.googleapis.com/maps/api/directions/json?" +"origin=" + origin.latitude + "," + origin.longitude+ "&" +"destination=" + dest.latitude + "," + dest.longitude +"&sensor=false&units=metric&mode=driving" + "&" + key=YOUR_API_KEY
above api call return a list of latlng add the list into polylines
Polyline polyline1 = googleMap.addPolyline(new PolylineOptions()
.clickable(true)
.addAll(latlngList));
hope it helps.

To add a polyline -
val polyline1 = map?.addPolyline(
PolylineOptions().clickable(true)
.add(LatLng(23.8103, 90.4125), LatLng(4.0383, 21.7587))
.geodesic(true) // this will turn this line to curve
)
// To add styles in the line
stylePolyline(polyline1)
private fun stylePolyline(polyline: Polyline?) {
polyline?.let {
it.color = ContextCompat.getColor(binding.mapPlaceholder.context, R.color.lineColor)
it.pattern = mutableListOf(Dot(), Gap(5F))
it.startCap = RoundCap()
it.jointType = JointType.ROUND
}
}

How about these:
https://github.com/zhenyanghua/MeasureTool-GoogleMaps-V3
http://zhenyanghua.github.io/google-maps/measure-tool/
Regards
PS: I am not the author of the software.

Related

cluster markers displaying inaccurately

I've tried to implement the cluster manager following this Google Developers toutorial but my markers are displaying extremely inaccurately compared to just using googleMap.addMarker();(example).
Here is an image comparison of the two
I suppose it has to do with the offset in the addClusterPoints() but when I change the divisor(60d), the only change is how far the points are spread out but still an incorrect location. I've tried changing the value of 60d and I've found that with <60d they are more spread out and >60d They are less spread out.
Could someone explain what the offset is doing and how to get the points to display accurately?
private void addClusterPoints(){
List<LatLng> locations= new ArrayList<>(getLatLongList());
for(int i=0; i < locations.size(); i++){
double offset = i /60d;
latLng = locations.get(i);
double lat = latLng.latitude + offset;
double lng = latLng.longitude + offset;
mapClusterItem offsetItem = new mapClusterItem(lat, lng, "Tile "+i, "Snippet"+i);
clusterManager.addItem(offsetItem);
}
}
As Andy commented, the issue was in the offset. I've removed the offset and the markers are displaying at their expected locations.
The Google Developers tutorial I referenced has the offset so I thought it was part of the process but it turns out it's completely unrelated. I honestly find it strange that they would decide to include that in the tutorial. The only reasoning I could think of why they would do that (since they don't provide one) would be to create some space between items that are very close together.

How to remove a symbol from a map

I am currently creating a map which updates based on users selection and displays 5 location closest to them. This works however when the user changes their selection the map updates and displays the 5 NEW locations as well as the 5 OLD locations.
I am not sure how to remove the old symbols.
public void displayResults(ArrayList allLocation) {
SymbolManager sm = new SymbolManager(mapView,map,styleMap);
sm.deleteAll();
SymList.clear();
sm.setIconAllowOverlap(true);
sm.setIconIgnorePlacement(true);
int count = 1;
for (LocationDetails a : allLocation
) {
// gets the distance from user to Location
double LocationLat = Double.parseDouble(a.getLatitude());
double LocationLng = Double.parseDouble(a.getLongitude());
float[] disResult = new float[1];
Location.distanceBetween(lat, lng, LocationLat, LocationLng, disResult);
results.append(count + ": " + a.getName() + " " + "\n");
distanceResults.append(Math.round(disResult[0]) + "m" + "\n");
SymbolOptions symbolOptions = new SymbolOptions()
.withLatLng(new LatLng(LocationLat, LocationLng))
.withIconImage("marker-11")
.withTextField(""+count)
.withIconColor("black")
.withIconSize(2.5f);
SymList.add(symbolOptions);
count++;
}
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(SymList.get(0).getLatLng())
.include(SymList.get(1).getLatLng())
.include(SymList.get(2).getLatLng())
.include(SymList.get(3).getLatLng())
.include(SymList.get(4).getLatLng())
.build();
map.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 50), 2000);
for(SymbolOptions a : SymList){
sm.create(a);
}
SymList.clear();
}
I have been using mapbox for 3 months. After hours of research I discovered that on Android the only way to remove a Symbol or any element on the map was to reload all the elements from scratch. Unfortunately, there is currently no method to remove a single element.
So I suggest you create a container class in which to save your items.
If your use case only requires showing about five markers on the map at a time, it might be easier to use native sources and SymbolLayers rather than relying on the abstraction provided by the SymbolManager.
For example, this icon updates based on API response Android demo shows how to add a GeoJSON source and corresponding layer to the map, then update said source to get a different visual result. Basically all of the logic you will need is encapsulated here, but your GeoJSON will be a FeatureCollection of multiple (namely, 5) features rather than just one point.
So, you can set up your symbols similarly to how it's done in the linked example:
private void initSpaceStationSymbolLayer(#NonNull Style style) {
style.addImage("space-station-icon-id",
BitmapFactory.decodeResource(
this.getResources(), R.drawable.iss));
style.addSource(new GeoJsonSource("source-id"));
style.addLayer(new SymbolLayer("layer-id", "source-id").withProperties(
iconImage("space-station-icon-id"),
iconIgnorePlacement(true),
iconAllowOverlap(true),
iconSize(.7f)
));
}
, and then update the source's GeoJSON to the new locations closest to the user's position, similar to the updateMarkerPostion method:
private void updateMarkerPosition(LatLng position) {
// This method is where we update the marker position once we have new coordinates. First we
// check if this is the first time we are executing this handler, the best way to do this is
// check if marker is null;
if (map.getStyle() != null) {
GeoJsonSource spaceStationSource = map.getStyle().getSourceAs("source-id");
if (spaceStationSource != null) {
spaceStationSource.setGeoJson(FeatureCollection.fromFeature(
Feature.fromGeometry(Point.fromLngLat(position.getLongitude(), position.getLatitude()))));
}
}
// Lastly, animate the camera to the new position so the user
// wont have to search for the marker and then return.
map.animateCamera(CameraUpdateFactory.newLatLng(position));
}
A few modifications will need to be made, of course, but this option might be more direct for your implementation specifically.

Want to know about google map pop ups or snippet upon exact location

I want to develop an app on google map that could notify me with some information set by the user when I am close to the exact location. So can I get a link for this that How can I get pop-ups when I am at the exact(user) location?
You'll first need to enable a location manager to start getting the user's current location. Then, every time the user's location updates, the location manager calls the onLocationChanged() method. Here, you would want to check the distance between the user's current location and the destination location. If they are within whatever distance you choose, then you can display your map marker. Here is a little example of how to do that:
#Override
public void onLocationChanged(Location location) {
float distanceInMeters = destLocation.distanceTo(location);
// Distance in miles
double distance_to_dest = (distanceInMeters/1609.344);
int distance_to_dest_int = (int)(distance_to_dest * 100);
distance_to_dest = ((double)distance_to_dest_int/100.00);
tvMilesToGo.setText(String.format("%.2f", distance_to_dest) + "mi");
// About 1/10th of a mile
if ((distanceInMeters > 149) && (distanceInMeters < 176)) {
// I played an alarm sound when close to the target destination
//if (alarmPlayer.isPlaying()) {
// alarmPlayer.stop();
//}
//alarmPlayer.start();
Marker marker = mMap.addMarker(new MarkerOptions()
.position(new LatLng(destLocation.getLatitude(), destLocation.getLongitude()))
.title(“Arrived”)
.snippet(“You have arrived at your destination!”)
.icon(red_descriptor));
Marker.showInfoWindow;
}
}
Note, in your case, you would probably only ever want to add a marker once, so, you would probably want to set a flag such as markerIsVisible = true once you add it to the map, and then check before adding the marker if (markerIsVisible == false) {add the marker, markerIsVisible = true}

How do I go about using a users location when they are in a certain place? The place would trigger an action based on location

I'm trying to create an app for android with little experience programming. I want to use a phones gps to determine a place on google maps then cause an action to happen. The action would be based on the location and I'd also like to have the user designate locations to cause an action.
If there are any resources or websites you can point me to I would really appreciate it.
I'm currently only using android studio, is there anything else I need?
first, you need the current user location. You can follow the steps offered here to obtain it. The locationmanager provides a method onLocationChanged(Location loc) which then is triggered automatically when the location changes. You can implement your "actions" here. Im not quite sure if I have understood what the designation of locations by the user would have to trigger.
If you want to trigger a specific "action", you can implement the method onMapClicked(Location loc) by setting an onMapClickListener to your map.
Depending on how your "predefined places" are built, you have different possibilities.
1) Are those places points? --> you can calculate the euclidian (or spherical) distances, and related to that distance decide if you want to trigger something or not.
2) are those places 2d rectangles? --> use LatLngBounds and its contains(LatLng point) method to decide if the userlocation or user-designated-location is inside
3) are those places any polygons? here is a good example on how to create such a place. there is also a contains() method.
4) Are your places not predefined? We need more information on what you want to do in this case.
edit based upon ur comment :
so you there are 2 things your app should do:
1) do some action (just like popping up a message), when the user is entering a "place" or comming near to a "place"
2) give the user the possibily to create such a place by himself.
secondary can be done by adding a onMapClickListener to your map.
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
// latLng is the lcoation, tapped by the user on the map. lets save it
chosen_location = new LatLng(latLng.latitude, latLng.longitude);
}
});
}
This will save the single points, tabbed by a user on a map. If you wanna go further later for polygons, you can add this point to an ArrayList of points. However, you probably want the user to add more information about that point. Make use of EditText to let the user e.g. enter a description of that point (or later polygon), and finally, when clicking a button to "save that entered place", you can add it to an ArrayList. You probably also gonna have a server-backend in order to update and retrieve a list of places created by multiple people from anywhere.
but for now, lets go on and check if the user came nearTo such a point or entered such a polygon:
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 35000, 10, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
// the users location changed (e.g. he moved some meters)
current_location = new LatLng(location.getLatitude(), location.getLongitude());
// somehow get all the places ( i guess a server backend is recommended )
// for now, lets say all the places are already obtained into an Arraylist called places:
ArrayList<LatLng> places = new ArrayList<LatLng>;
// Go check for each of the places, if the users current location is near to such a point
for (LatLng place : places) {
if (distance(place,current_location)<100) {
LatLng near_place = place;
// here we are! near_place is near the users current location, lets do some action
Log.d("app","Users location (" + current_location.latitude +","+current_location.longitude+") is near to a place with coordinates "+near_place.latitude+","+near_place.longitude+").");
}
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
});
}
and here is a method to calculate (spherical) distance in meters between to LatLng objects:
/**
* method calculate distance between two LatLng points in meter
*/
public float distance(double lat_a, double lng_a, double lat_b, double lng_b) {
double earthRadius = 3958.75;
double latDiff = Math.toRadians(lat_b - lat_a);
double lngDiff = Math.toRadians(lng_b - lng_a);
double a = Math.sin(latDiff / 2) * Math.sin(latDiff / 2) +
Math.cos(Math.toRadians(lat_a)) * Math.cos(Math.toRadians(lat_b)) *
Math.sin(lngDiff / 2) * Math.sin(lngDiff / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = earthRadius * c;
int meterConversion = 1609;
return new Double(distance * meterConversion).floatValue();
}

Recognizing when the user is driving, walking, biking

I am trying to find the most reliable way to identify if the user is driving, walking, biking or is stationary. I am going to use this in an Android application. I would prefer to avoid GPS as much as possible.
Please let me know what algorithms worked for you, their advantages and disadvatages. Thanks!
Google has an API for this in Google Play Services. Check out https://developer.android.com/reference/com/google/android/gms/location/ActivityRecognitionApi.html
I wouldn't suggest coding it on your own, its not easy (I had a version about a year before Google did, it was buggy and battery draining).
You probably will never get a completely accurate result, but a reasonable estimate could be determined using
- GPS to identify speed
- Is the charger plugged in
- is the phone off, or on screensaver
- is the movement detector going off a lot - likely walking but may be driving on dirt road
I was playing with a simplistic version of this as follows (sorry code is in Python)
def inspect_phone(self):
self.phone_gps_lat = 137.0000 # get from phone
self.phone_gps_lng = 100.0000 # get from phone
self.phone_moving = False # get from phone
self.phone_move_dist_2_mn = 4
self.phone_on_charge = True
self.screen_saver = False
#-------------------------------
phone_status = ''
if self.phone_on_charge == True:
phone_status += 'Phone is charging'
if self.phone_moving == True:
phone_status += ', driving in Car'
else:
phone_status += ', sitting still'
else:
if self.screen_saver == False:
phone_status += 'Phone is being used'
else:
phone_status += 'Phone is off'
if self.phone_moving == True:
if self.phone_move_dist_2_mn < 5:
phone_status += ', going for Walk'
elif self.phone_move_dist_2_mn > 500:
phone_status += ', flying on Plane'
else:
phone_status += ', riding on ' + transport['Public']
return phone_status
I have made a small logic to get the best polylines for each activity and optimize the draw, since we need certain quantity of latitudes and longitudes in order to draw the best track that the user has made.
Lets say when the user press to start a new activity it will prompt 3 options, run, walk or biking.
This method takes what the user has selected and updates the locationRequest for each one.
public void setTrackActivity(long interval, long fastInterval) {
//Update the locationRequest intervals for each different Activity
mLocationRequest.setInterval(interval);
mLocationRequest.setFastestInterval(fastInterval);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
For walking I set the locationRequest intervals within 6 seconds
delay for each request.
For runing I set the locationRequest intervals within 2 seconds delay
for each request.
For runing I set the locationRequest intervals within 1 second delay
for each request.
Then, to save up more polylines when drawing the map, I take the same concept. If an user is walking it will trace a polyline each 30 polylines that have been made
public void drawTrack(GoogleMap googleMap) {
googleMap.clear(); //Clearing markers and polylines
PolylineOptions polyline_options = new PolylineOptions().addAll(mLinkedList)
.color(ContextCompat.getColor(mContext, R.color.colorAccent)).width(Constants.POLYLINE_WIDTH).geodesic(true);
// Adding the polyline to the map
Polyline polyline = googleMap.addPolyline(polyline_options);
// set the zindex so that the poly line stays on top of my tile overlays
polyline.setZIndex(1000);
// we add each polyline to an array of polylines
mPolylinesArray.add(polyline);
// We add the latest latlang points we got
mLatLngArray.add(mLinkedList.getLast());
//If we have made 30 polylines we store 1 line starting from that first point to the last, so we can save 28 polylines and draw one instead of having so many points for lets say 10 meters, this value must change depending on the activity, if biking, runing or walking
if (mLatLngArray.size() % 30 == 0) {
// First we delete all polylines saved at the array
for (Polyline pline : mPolylinesArray) {
pline.remove();
}
// We create a new polyline based on the first and last latlang from the 30 we took
Polyline routeSoFar = googleMap.addPolyline(new PolylineOptions().color(Color.GREEN).width(Constants.POLYLINE_WIDTH).geodesic(true));
// Draw the polyline
routeSoFar.setPoints(mLatLngArray);
// set the zindex so that the poly line stays on top of my tile overlays
routeSoFar.setZIndex(1000);
// Clear polyline array
mPolylinesArray.clear();
// Add polyline to array
mPolylinesArray.add(routeSoFar);
}
}
Where mLinkedList is an LinkedList<LatLng> so we can have the first and last element (if you want to draw a custom marker when activity starts and when activity finish )
mPolylinesArray is an array of Polylines ArrayList<Polyline>

Categories

Resources