I have a problem removing a single polyline from my Google Map in Android.
There were other Users with similar questions but not many answers and none of them where helpful.
Inside the google dock, it's explained that you can remove a polyline with the .remove() function.
But in my case this does not work. Maybe the problem lays within the scope.
In my class I have defined:
Polyline polyline = null;
Then I have an OnClick Listener for my Map and two arrays. One with 2 Locations in it (for my polyline) and one that adds Markers when I click on the map.
if(test.size() == 2 && pol == false)
{
polylineOptions.color(Color.BLUE);
polylineOptions.addAll(test);
polyline = m_map.addPolyline(polylineOptions);
//polygonOptions.fillColor(Color.BLUE).addAll(test);
}
if(markerList.size() == 2)
{
pol = true;
polyline.remove();
}
When I click on the Map a polyline is drawn. Then I click again, and the markerList is now equal 2, it goes into the function but the polyline is not removed. Why? What can I do?
Related
1) I'm practicing stuff with graphs in order to add that feture to my app, I want the upper labels ( the xAxis base ) to be shown only where entries occur.
I haven't found a suitable solution online yet, and currently it appears on every xAxis from first entry to last entry as in the picture below:
I want it to be without the one sI deleted, as shown in the picture below:
2) and the second question I'm struggling with it is that I want to be able to draw for example in (x=5, y=7) and after it to draw at (x=1, y =3), but it wont let me add an entry with a smaller x that any other entry that already in the graph.
You have to extend from ValueFormatter class.
for more detail take a look at link
You can pick your desired logic to make the label disappear with returning "".
for example:
public String getFormattedValue(float value) {
if ((int)value <= 0) //your logic to evaluate correctness
return ""; // make lable go away
//...
}
UPDATE 2 (in Kotlin):
There is another overload for getFormattedValue which have a AxisBase parameter and you can use mEntryCount or mEntries.
override fun getFormattedValue(value: Float, axis: AxisBase?): String {
if (axis?.mEntryCount!! <= 0)
return ""
}
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.
When I tap the screen, a marker gets added to the middle of a Mapbox map. The first marker shows up as it is supposed to. However as soon as I add a second marker, the markers show up grey.
Here is the code I use to create the symbol source and the symbol layer, as well as the onMapClickListener where the features of the symbol source get updated with the new marker. All this code is in the onStyleLoaded method.
//Create the symbol source
Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_map_marker_blue, null);
Bitmap marker = BitmapUtils.getBitmapFromDrawable(drawable);
style.addImage(BLUE_MARKER_IMAGE, marker);
GeoJsonSource geoJsonSourceSymbol = new GeoJsonSource(SYMBOL_SOURCE_ID);
style.addSource(geoJsonSourceSymbol);
//Create the symbol layer
symbolLayer = new SymbolLayer(SYMBOL_LAYER_ID, SYMBOL_SOURCE_ID);
symbolLayer.setProperties(iconImage(BLUE_MARKER_IMAGE), iconOffset(new Float[] {0f, -10f}));
style.addLayer(symbolLayer);
mapboxMap.addOnMapClickListener(new MapboxMap.OnMapClickListener() {
#Override
public boolean onMapClick(#NonNull LatLng point) {
final LatLng mapTargetLatLng = mapboxMap.getCameraPosition().target;
Point mapTarget = Point.fromLngLat(mapTargetLatLng.getLongitude(),mapTargetLatLng.getLatitude());
pointList.add(mapTarget);
featureList.add(Feature.fromGeometry(mapTarget));
if (style.getLayer(SYMBOL_LAYER_ID) != null) {
GeoJsonSource geoJsonSourceSymbol = style.getSourceAs(SYMBOL_SOURCE_ID);
if (geoJsonSourceSymbol != null) {
geoJsonSourceSymbol.setGeoJson(FeatureCollection.fromFeatures(featureList));
}
}
return true;
}
});
Is there something I'm doing wrong or is it not possible to dynamically add symbols using data-driven styling?
Are you using an emulator? The Mapbox team already knows of SymbolLayer rendering issues on emulated devices:
https://github.com/mapbox/mapbox-gl-native/issues/10829
https://github.com/mapbox/mapbox-plugins-android/issues/1082
I create plots based on worldguard regions. I am looking for a good method of checking if there is no other region within a radius of 50 counts in each direction. My point is that someone does not create a plot and someone else's plot. Currently, I checked it in a strange way for me, but it practically worked.
Location p3 = p.getLocation();
p3.setX(p3.getBlockX());
p3.setY(60);
p3.setZ(p3.getBlockZ()+size);
if(region.getApplicableRegions(p3).size() == 0) {
plotsCheck.put(p.getUniqueId(), plotsCheck.get(p.getUniqueId())+1);
}
Location p3a = p.getLocation();
p3a.setX(p3a.getBlockX());
p3a.setY(60);
p3a.setZ(p3a.getBlockZ()+10);
if(region.getApplicableRegions(p3a).size() == 0) {
plotsCheck.put(p.getUniqueId(), plotsCheck.get(p.getUniqueId())+1);
}
Location p4 = p.getLocation();
p4.setX(p4.getBlockX());
p4.setY(60);
p4.setZ(p4.getBlockZ()-size);
if(region.getApplicableRegions(p4).size() == 0) {
plotsCheck.put(p.getUniqueId(), plotsCheck.get(p.getUniqueId())+1);
}
In this way, I checked if it was empty. If so, I added 1 point to the hashmap.
Unfortunately, this does not always work and ends with the fact that several plot plots belong to 2 people. Does anyone of you propose a different solution for this?
WorldGuard already has some built in features for that.
RegionContainer container = getWorldGuard().getRegionContainer();
RegionManager manager = container.get(world);
Region newRegion = //create your region somehow
manager.addRegion(newRegion);
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>(manager.getRegions().values());
List<ProtectedRegion> overlappingRegions = newRegion.getIntersectingRegions(regions);
if (overlappingRegions.size() > 0) {
//delete region newRegion
} else {
//region is valid
}
This of course works only after the region has already been created.
Code has not been tested. Just searched through the WorldGuard API wiki.
https://worldguard.enginehub.org/en/latest/developer/regions/protected-region/#finding-intersecting-regions
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>