How to check distance between current position and KML points using OSMDroid? - android

So, in my project I need to check, every minute, if a user is in a given distance radius of a specified KML.
I searched methods from KmlDocument and FolderOverlay, but none of them give me a list of points or anything else to compare with my current location.
Here is how I get my KML and then apply the overlay to the map:
KmlDocument kmlDocument = new KmlDocument();
map.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE);
if (trail.isDownloaded() && UtilsClass.getInstance().isNetworkAvailable(context) && trail.getFileKmlLocalPath() != null &&
!trail.getFileKmlLocalPath().isEmpty()) {
File kmlFile = new File(trail.getFileKmlLocalPath());
if (kmlFile.exists()) {
kmlDocument.parseKMLFile(kmlFile);
} else {
kmlDocument.parseKMLUrl(trail.getFileKml());
}
} else {
kmlDocument.parseKMLUrl(trail.getFileKml());
}
FolderOverlay kmOverlay = (FolderOverlay)
kmlDocument.mKmlRoot.buildOverlay(map, null, null, kmlDocument);
map.getOverlays().add(kmOverlay);
Is there a way to accomplish what I want/need?
Thanks in advance

The list of points for each KmlPlacemark (Point, LineString, and Polygon) are in KmlPlacemark.mGeometry.mCoordinates

Related

Android - Google map clustering bug with markers not being reclustered

Edit: Show what the mapManager.filter() method does.
I have an Android app with ~20k markers being draw on the map and with filters option so the markers are being drawn and remove a lot.
I'm currently using this clustering library because it's way more efficient for displaying a large amount of markers than the classic google map library. But it's not supported and hasn't been updated since 3 years and i haven't found any alternatives.
Here is a video of the bug.
Here is my code that is call when i click on an filtering option in my app:
private void filter(){
//currentMapManager contain all the filters option and also the array list
//of the unfiltered markers (~20,000 markers)
//it's filter method retrieve the current filtering option enable (marker type, and other specs)
//And return markers from the full arraylist that match those filters options.
ArrayList<MarkerModel> filteredList = currentMapManager.filter(currentMapManager.getAllMarkers());
if (clusterManager != null) {
clusterManager.setItems(new ArrayList<>());
clusterManager.onCameraIdle();
clusterManager.setItems(filteredList);
clusterManager.onCameraIdle();
}
Here the mapManager.filter() method.
public ArrayList<MarkerModel> filter(List<MarkerModel> currentMarkers) {
ArrayList<Object> filtersArray = filters.getFilters();
/* filtersArray is an array like this :
* ['type', ['typeFilter1', 'typeFilter2'],
* 'date', dateTimestamp,
* 'withPictures', true,
* ....]
*/
return filter(currentMarkers, filtersArray);
}
private ArrayList<MarkerModel> filter(List<MarkerModel> currentMarkers,
ArrayList<Object> fieldsAndValues) {
if (fieldsAndValues.size() % 2 == 1) {
throw new IllegalArgumentException("Missing value in call to filterList().
There must be an even number of arguments that alternate between
field names and values");
} else {
//Here the arraylist that we are returning
ArrayList<MarkerModel> filteredMarkers = new ArrayList<>();
List<Object> argumentList = new ArrayList();
Collections.addAll(argumentList, fieldsAndValues);
if (!currentMarkers.isEmpty()) {
for (int j = 0; j < currentMarkers.size(); j++) {
MarkerModel marker = currentMarkers.get(j);
boolean isInFilter = true;
//Check fieldsAndValue filters...
//If isInFilter stay to true we
filteredMarkers.add(marker);
}
}
return filteredMarkers;
}
}
I think the problem is that the cluster library is not supposed to have so much redrawn and it broke at some point from reading and working on 20k items arraylist.
I have look through all the forks branch of this library and look/try to understand the library source code but hasn't find any solution at my problem...
If you need other part of my source code to understand more tell me i will add it.
Thanks a lot if you can help me i have been struggling a lot with this issue...

I need to sort the latitude and longitude. which is nearer to my current location

This is how i calculate the Distance between my list.
my code is below
public void calc(){
for(int i = 0; i < mSearchResultModelsToGetAppointments.size(); i++){
Location newLocation = new Location("");
newLocation.setLatitude(gpsTracker.getLatitude());
newLocation.setLongitude(gpsTracker.getLongitude());
if(String.valueOf(gpsTracker.getLatitude()).equalsIgnoreCase("0.0") || String.valueOf(gpsTracker.getLongitude()).equalsIgnoreCase("0.0")) {
} else{
Location oldLocation = new Location("");
oldLocation.setLatitude(mSearchResultModelUnderProcess.getLatitude());
oldLocation.setLongitude(mSearchResultModelUnderProcess.getLongitude());
float distanceInMeters = newLocation.distanceTo(oldLocation)/1000;
if(distanceInMeters < 2820){
getAdapter().notifyDataSetChanged();
getAdapter().removeItem(i);
getAdapter().notifyDataSetChanged();
}
}
}
}
This is how i display the location now.
If you do not want use any external library, I would suggest following way.
Create your own custom Location Class with attributes lat and lng, and additionally attribute called distance which measures from your current location till the point. here you can find how to find distance between 2 points
This class should implement Comparable interface and override its compare function. Inside this function, you can create your own sorting logic based on distance
here you can find how to use comparable interface, Let me know if you have still problem
Happy coding

is it possible to ignore some markers when using GoogleMaps onMarkerClickListener, so the click listener isn't even triggered?

In the map below I have three markers, the red one is the users current position while the green ones are the clickable markers.
Clicking the bottom one is not a problem. But clicking the one the user is close to is a different matter as the position marker is in the way. So for that one the user usually has to click 2 - 8 times before the green one is touched.
Is there a way to define that some markers are not clickable so they dont trigger the onMarkerClickListener?
I am aware that I can change the z-index and put the position marker below but it wont be nice for the user if he can't see his own position when close to another marker.
Another solution can think of but dont like is to intercept the click for the user marker and then go through a list of the other markers and find possible matches and trigger a click myself. I'd prefer an existing solution.
So what I have ended up doing is adding the object the marker represents to its tag. Then in onMarkerClickListener I check the marker type by the tag object. Like so (kotlin):
map.setOnMarkerClickListener { marker ->
val mapEvent: MapEvent?
mapEvent =
if (marker.tag is MapEvent) {
marker.tag as MapEvent?
} else {
val clickedMarker = getClickedMarker(from = map)
if (clickedMarker != null)
clickedMarker.tag as MapEvent?
else
return#setOnMarkerClickListener false
}
markerClicked(this#MainActivity, mapEvent)
true
}
If the object is of type MapEvent I call markerClicked() if the clicked marker is not of type MapEvent I go through a list of all markers to see if the clicked marker is inside the radius of any of the MapEvent markers. If so I use that marker and call markerClicked().
This is how I sort through the list of markers:
fun getClickedMarker(from: GoogleMap): Marker? {
if (!::userMarker.isInitialized)
return null
var clickWidth = ContextCompat.getDrawable(App.context, R.drawable.ic_map_permanent)!!.intrinsicWidth
clickWidth += (clickWidth / 3)
val g0 = from.projection.fromScreenLocation(Point(0, 0))
val g1 = from.projection.fromScreenLocation(Point(clickWidth, clickWidth))
val latRadius = (g1.latitude - g0.latitude) / 2
val lonRadius = (g1.longitude - g0.longitude) / 2
return try {
eventMarkers.single {
it.position!!.latitude - latRadius > userMarker.position.latitude && // west
it.position!!.latitude + latRadius < userMarker.position.latitude && // east
it.position!!.longitude + lonRadius > userMarker.position.longitude && // north
it.position!!.longitude - lonRadius < userMarker.position.longitude // south
}
} catch (e: Exception) {
null
}
}
Please comment if anything is unclear. I hope this might help anyone else!

CameraUpdateFactory zoom not working

private void setCurrentLocationMarker(LatLng currLatLng) {
if (currLatLng == null) {
Toast.makeText(getActivity(), "Check Internet Connection", Toast.LENGTH_SHORT).show();
return;
}
mMap.moveCamera(CameraUpdateFactory.newLatLng(currLatLng));
mMap.animateCamera(CameraUpdateFactory.zoomBy(R.integer.camera_zoom_value));
setMarkerAtCentre(mMap.getCameraPosition().target);
}
private void setMarkerAtCentre(LatLng cameraCentre){
if(cameraCentre == null) return;
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(cameraCentre);
markerOptions.icon(BitmapDescriptorFactory.defaultMarker());
markerOptions.title("Your Position");
sourceMarker = mMap.addMarker(markerOptions);
}
Above two are the functions for setting the marker to desired latitude and longitude and placing the camera focusing the location.
Everything is working fine.
But the problem which I face here is with the zoom
mMap.animateCamera(CameraUpdateFactory.zoomBy(R.integer.camera_zoom_value));
I may place any value for the zoom.
<integer name="camera_zoom_value">2</integer>
But the zoom which I get always is the maximum one i.e. the largest possible zoom, which is kinda issue here.
Can anyone help me out? Thanks in advance.
your are passing the resource integer directly without using getResources().getInteger() so the value passed is some long integer > 20 leading to maximum zoom. Fix that and it will work.

Selecting correct ArcGisFeatureLayer to query onSingleTap event?

My problem: I'm working on a Android (ArcGis) Attribute Editor following the sample code from their tutorials. The problem occurs when I have more than 1 ArcGisDynamicLayer and, more important, more than 1 ArcGisFeatureLayer.
My question: What is the (correct) approach to IDENTIFY the right Feature Layer to query when I tap on a "field" displayed on the map?
I read a similar question (Arcgis SDK for Android - Query multiple feature layers), but I didn't understand how to use IdentifyTask using only a single tap.
EDIT: I tried to get the graphics that I tapped on to compare it to the graphics from every feature layer. If they are equal, that's the feature layer that I'm looking for. But that's not working, because my feature layers don't seem to have any graphics.
mapView.setOnSingleTapListener(new OnSingleTapListener() {
public void onSingleTap(float x, float y) {
/*...construct query...*/
Graphic g = null;
for (Layer layer : mapView.getLayers()) {
if (layer instanceof ArcGISFeatureLayer) {
ArcGISFeatureLayer fLayer = (ArcGISFeatureLayer) layer;
// Get the Graphic at location x,y
final int[] ids = fLayer.getGraphicIDs(x, y, 10, 1);
if (ids != null && ids.length != 0) {
g = fLayer.getGraphic(ids[0]);
System.out.println("Graphic: " + g);
}
}
/*...loop through every FeatureLayer and verify like :...*/
for(...)
if(layer.getGraphic(g.getUid()) != null && && g.equals(layer.getGraphic(g.getUid()))) {
/* call the select features method and implement the callbacklistener */
/* rest of the story */
}
}

Categories

Resources