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.
Related
Situation: The tank has a Shot() method and a code that checks if the bullet hits the obstacle after being fired. The bullet flies up the X-coordinate. The do...while loop checks how far the bullet can travel without obstacles. After that, the animation of the bullet flight itself takes place through TranslateTransition. And the last loop goes through all the game obstacles and checks for contact through intersects and, if successful, removes the obstacle.
do {
y = (int) (bulletObj.getImageBullet().getTranslateX() + register) / PlayField.BRICK_SIZE;
x = (int) bulletObj.getImageBullet().getTranslateY() / PlayField.BRICK_SIZE;
line = LevelData.LevelOne[x][y];
register += 1;
} while (line.equals("0"));
System.out.println(System.currentTimeMillis()); // 1643642047472 ms.
bulletTranslate = new TranslateTransition();
bulletTranslate.setFromX(bulletObj.getImageBullet().getTranslateX());
bulletTranslate.setToX(bulletObj.getImageBullet().getTranslateX() + register - 18);
bulletTranslate.setNode(bulletObj.getImageBullet());
bulletTranslate.setDuration(Duration.millis(register)); // Let register = 300 мs.
bulletTranslate.play();
System.out.println(System.currentTimeMillis()); // 1643642047474 ms.
bulletObj.getImageBullet().setTranslateX(bulletObj.getImageBullet().getTranslateX() + register - 18);
for (GameObject platform: PlayField.platforms) {
if (platform.getImage().getBoundsInParent().intersects(bulletObj.getImageBullet().getBoundsInParent()))
{
System.out.println(System.currentTimeMillis()); // 1643642047474 ms.
tankRoot.getChildren().remove(platform.getImage());
PlayField.platforms.remove(platform);
LevelData.LevelOne[x][y] = "0";
break;
}
}
Everything works as expected, but there is only one problem.
The problem is that the obstacle objects are removed faster than the animation bullets pass.
And it is necessary that after contact they are deleted simultaneously.
How to solve the problem?
Before the shot
After the shot, the object disappeared during the flight of the bullet
P.S Sorry, I used google translate.
As #jewelsea suggested, you need to supply a minimal reproducible example to get some proper help.
Having said that, based on the code you provided, below is my initial analysis. Note that this is a rough analysis by reading the code.. so everything is just an assumption ;)
The first part of the code (do-while) is to determine the distance the bullet needs to travel (determining the value of register)
The second part is to initiate animation of bullet to translate from its current position (using the register value).
The third part is to set the final translate value to the bullet and the final part is to check if the bounds are intersected and delete the node.
I think the thrid part (below line of code) is not needed and could be the cause for your issue. You are updating the value to the end value and immediately checking if it is intersected.. which will be true and will delete instantly.
bulletObj.getImageBullet().setTranslateX(bulletObj.getImageBullet().getTranslateX() + register - 18);
Try moving your 'for' loop code to onFinished of translation. Something like..
bulletTranslate = new TranslateTransition();
bulletTranslate.setFromX(bulletObj.getImageBullet().getTranslateX());
bulletTranslate.setToX(bulletObj.getImageBullet().getTranslateX() + register - 18);
bulletTranslate.setNode(bulletObj.getImageBullet());
bulletTranslate.setDuration(Duration.millis(register)); // Let register = 300 мs.
bulletTranslate.setOnFinished(e->{
for (GameObject platform: PlayField.platforms) {
if (platform.getImage().getBoundsInParent().intersects(bulletObj.getImageBullet().getBoundsInParent()))
{
tankRoot.getChildren().remove(platform.getImage());
PlayField.platforms.remove(platform);
LevelData.LevelOne[x][y] = "0";
break;
}
}
});
bulletTranslate.play();
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.
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>
I am trying out the GraphView Library for creating charts on Android. It looks quite decent, but I am wondering if there is a way to add some space between the tick labels and the graph itself. As you can see, there is basically none:
I use the following code to set up the graph (very similar to the example):
GraphView graph = (GraphView)view.findViewById(R.id.graph);
LineGraphSeries<DataPoint> series = new LineGraphSeries<DataPoint>(new DataPoint[] {
new DataPoint(0, 1),
new DataPoint(1, 5),
new DataPoint(2, 3)
});
graph.addSeries(series);
I tried using graph.getGridLabelRenderer().setPadding(), but that just added padding around the whole graph.
So, is there a way to put some padding around those labels?
yes it is possible in the current version in github (will be released in 4.0.1).
There is the method:
graph.getGridLabelRenderer().setLabelsSpace(x)
Follow this example to give your graph a custom label formatter. By doing so, you can at least add space padding to your y-axis labels (if not newline spacing to your x-axis labels).
// GraphView 4.x
graph.getGridLabelRenderer().setLabelFormatter(
new DefaultLabelFormatter() {
#Override
public String formatLabel(double value, boolean isValueX) {
if (isValueX) {
// show normal x values
return super.formatLabel(value, isValueX);
} else {
// show currency for y values
return super.formatLabel(value, isValueX) + " €";
}
}
}
);
I pulled this example from the GraphView documentation.
Otherwise, I found it interesting that someone chose this answer as the best response for a similar question.