How to calculate outline of complex polygon in Android maps v2 - android

I need to fill the center of a polygon in Android maps v2 and am running into problems when the polygon is complex and has lines that cross each other. The user is able to draw on the map with their finger and then I use a map projection to convert my points to LatLng.
I need to fill the center even if it is drawn with lines that cross.
My code to draw is as follows:
PolygonOptions rectOptions = new PolygonOptions();
rectOptions.strokeColor(getResources().getColor(R.color.blue));
rectOptions.fillColor(getResources().getColor(R.color.blue_map_fill));
rectOptions.strokeWidth(4);
rectOptions.addAll(latLngs);
mMap.addPolygon(rectOptions);
Screenshot when I draw a star with the lines crossing:
Screenshot when I draw the star with only the outline:
Is there a way to calculate what LatLngs make up the outline or is there a different solution?
EDIT: The iOS version of the app I'm working on handles this perfectly..they just add all the points to a polygon and Google Maps figures it out. At this point I believe this is a bug/feature that is lacking from Android Google Maps.
EDIT: Bug report: https://code.google.com/p/gmaps-api-issues/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Introduced%20Fixed%20Summary%20Stars%20ApiType%20Internal&groupby=&sort=&id=6255

I know it's already a year gone but here is my solution.
I use the JTS library, I think you can use a client of this library as well, to create the surrounding polygon.
This method creates a new list of LatLng objects which you can use to draw the surrounding polygon of your input.
private void createSurroundingPolygon(List<LatLng> polygonPath) {
List<Coordinate> coordinates = new ArrayList<>();
for (LatLng latLng : polygonPath) {
coordinates.add(new Coordinate(latLng.longitude, latLng.latitude));
}
GeometryFactory factory = new GeometryFactory();
Geometry lineString = factory.createLineString(coordinates.toArray(new Coordinate[coordinates.size()]));
Polygon polygon = (Polygon) BufferOp.bufferOp(lineString, 0.0001);
Coordinate[] coordinatesSurroundingPolygon = polygon.getExteriorRing().getCoordinates();
List<LatLng> surroundingPolygon = new ArrayList<>();
for (int i = 0; i < coordinatesSurroundingPolygon.length; i++) {
surroundingPolygon.add(new LatLng(coordinatesSurroundingPolygon[i].y, coordinatesSurroundingPolygon[i].x));
}
drawPolygon(surroundingPolygon);
}
First it creates a new list of Coordindates. They are used to create a JTS Geometry, i.e. a LineString. You can't create a LinearRing or a Polygon directly from your coordinates list because you don't know if it is a valid (closed polygon without intersections) one. You get a Polygon when you buffer the given Geometry with a distance, in my case 0.0001. The distance is additional space which is added outside to your original polygon.
Finally with the method Polygon.getExtgeriorRing() you get the outline polygon without any intersections and crossing lines.

One possible way would be to detect where the lines collide with each other then convert those pixel positions to lat/lng points.
you would need to keep track of the first and last point which is the same in your case then check each line with all the other lines in the polygon. Also keep track of the order you find them in based on the direction you start checking (ie. clockwise/counter-clockwise). Convert all the intersection points from x,y to lat/lng.
after you found all the intersection positions then you can start at the first point and create a line the the first intersection point then the next line would be the first intersection point to your next non-intersection point(ie. the tips of the star) etc. etc. until you form a new list of all the new points then give the map that list to plot.
you can use this formula to get started http://en.wikipedia.org/wiki/Line-line_intersection
there may be some holes in my logic that i didnt think of.

Related

How to display user's movement in real time in Android MapBox SDK

How to make MapBox SDK(Android) so that when the user moves around the map, a line is drawn behind him in real time (his movement itself)
https://docs.mapbox.com/help/tutorials/android-location-listening/ shows how to track a user's location.
Every time a new Location arrives in onSuccess(), you'll:
create a Point (Point point = Point.fromLngLat(LONGITUDE, LATITUDE);) with the Location object's coordinates.
Add the Point to a list of Points to create a LineString.
LineString lineString = LineString.fromLngLats(pointList);
Use the LineString to update the LineLayer's geojson with the new LineString (see the second code snippet box in https://docs.mapbox.com/android/java/overview/geojson/#geojson-updates.
All of this is basically a combination of https://docs.mapbox.com/help/tutorials/android-location-listening and https://docs.mapbox.com/android/maps/examples/moving-icon-with-trailing-line (without the animation or PointEvaluator stuff from the second example, because you don't need it to move the device location puck).

I want to draw staight line between origin and destination using static google maps api

i am developing an android app, i want to draw a staight line between 2 point by giving those points... i want to use static google map as picture format. there is an option to draw PolyLine but that takes lots of points to join them. i have only 2 points origin and destination(Latitute and Longitute).
PolylineOptions line = new PolylineOptions().add(new LatLng(point1, point2));
mGoogleMap.addPolyline(line);
i.e. Just add the 2 points to PolylineOptions and add the PolylineOptions to google map.
Beside adding the points you can do various customizations to the line like line color, pattern, etc as explained in https://developers.google.com/maps/documentation/android-api/polygon-tutorial#add_a_polyline_to_draw_a_line_on_the_map

Calculate Distance From points in an Array

I'm developing an Android app that tracks the users location. I have it running locally so my LatLng are getting stored in an array :
ArrayList<LatLng> points = new ArrayList<>();
In onLocationChanged it then uses this to draw a poly line, this all works perfect for me. I want to calculate the distance of the entire journey. Is there a way to do this using my array?
You could make a loop that go through your array and compute the distance between two consecutive points. Then add every distance computed to obtain the whole trip distance. This should look like this (in pseudo code) :
totalDistance;
for(points in listOfPoints){
nextPoint = listOfPoints.indexof(point + 1);
distance = computeDistance(point, nextPoint);
totalDistance.add(distance);
}
For calculation distance between location points, you need at least two points.
Calculation can be found here:
https://stackoverflow.com/a/365853/1537916

Android HERE: How to draw part of route

I have calculated route for 10 waypoints. If i simply create new MapRoute it will draw full route from first to last waypoint. Is it possible to draw part of route, from first to second waypoint?
I use 3.4.0.165 HERE SDK version. I have found this answer, but it for previous version.
I have tried to draw only first subleg in this way:
int duration = route.getTta(Route.TrafficPenaltyMode.AVOID_LONG_TERM_CLOSURES, 0).getDuration();
RouteElements routeElementsFromDuration = route.getRouteElementsFromDuration(0, duration);
MapPolyline mapPolyline = new MapPolyline(routeElementsFromDuration.getGeometry());
map.addMapObject(mapPolyline);
But when map tilt enabled polyline drawn somewhere above roads, and if i change scale polyline change position relative to map tile objects.
Is there a reason you can't create a new route with your two waypoints? If you're using a stopover waypoint, you will be required to pass through the waypoint no matter what. Thus calculating the route between the first and second waypoint will provide you with the same route as the subset of the full route. If you're using a via waypoint, you can't count on drawing a subset of the route since it could change any minute given you are allowed to deviate away from the next waypoint at which point it will be ignored.
Currently it is not possible, workaround - calculate route between each point and draw required part.

Efficient algorithm to find which part of Polyline contains within another Polyline

I am trying to compare a Polyline - overview_polyline ruturned by Google Directions API with a set of already existing Polylines and see which part of the new polyline already contains within one of these polylines. For me polyline is a driving route representation, retrieved from Google Directions API. It is basically any route anywhere in the world. Thou for simplification we can always find routes, which belong to a concrete city or a country and compare only thise. Also, at the moment it may be at most 250kms long. Here is some example:
It doesn't matter which route is existing here and which is new. In any case I would like to get the result, that this routes are similar (ok, may be they are not 90% similar, but lets assume they are).
At the moment I am using brute forcing to compare new polyline one by one with an existing polyline. Before that I am splitting polylines into points using this algorithm and compare each point to see, if there is a match. I treat points to be the same if distance between this points is less then 100 meters.
If I found that there is already some polyline, which mostly covers new polyline, I stop processing.
It looks like this:
Polyline findExistingPolyline(Polyline[] polylines, Polyline polyline) {
LatLng[] polylinePoints = PolylineDecoder.toLatLng(polyline);
for (Polyline existing: polylines) {
LatLng[] existingPoints = PolylineDecoder.toLatLng(existing);
if (isMostlyCovered(existingPoints , polylinePoints)) {
return existing;
}
}
return null;
}
boolean isMostlyCovered(LatLng[] existingPoints, LatLng[] polylinePoints) {
int initialSize = polylinePoints.length;
for (LatLng point: polylinePoints) {
for (LatLng existingPoint: existingPoints) {
if (distanceBetween(existingPoint, point) <= 100) {
polylinePoints.remove();// I actually use iterator, here it is just demosnstration
}
}
}
// check how many points are left and decide if polyline is mostly covered
// if 90% of the points is removed - existing polylines covers new polyline
return (polylinePoints.length * 100 / initialSize) <= 10;
}
Obviously, this algorithm sucks (especially in its worst case, when there is no match for new polyline) as there are two many cycles and may be too many points to compare.
So, I was wondering, if there is more efficient approach to compare polylines with each other.
You seem to compare only the points of the polylines, not the lines in between. That means that a straight line and the same line with an additional center point won't match. Or am I missing something? (If my assumption is right, that's the weak point in your method, I think.)
The distance calculation you use involves ellipsoid trigonometry and probably is expensive. You don't need exact measures here, though, you just want to match two nodes. If you need to cover a well-known range that's not close to a pole, you could consider lat/lon as flat coordinates, maybe with a correction to the longitude.
boolean isWithin100m(LatLng a, LatLng b) {
double dy = (a.lat - b.lat) * R * pi / 180.0;
if (dy < -100 || dy > 100) return false;
double dmid = 0.5 * (a.lat + b.lat) * pi / 180.0;
double dx = (a.lng - b.lng) * R * pi / 180.0 / cos(dmid);
return dx*dx + dy*dy <= 10000.0;
}
Here, R is Earth's radius. That method should be faster than your exact solution. If the cosines of your northernmost and southernmost points are similar, you could even leave them out and just add a fixed avarage cosine as constant factor to the longitude.
Also, you decode your new polyline with every comparison. You could do that only once in findExistingPolyline and pass a LatLng[] to isMostlyCovered. If you can precalculate data for your existing polylines, storing them as LatLng[] would also help. Keeping the extreme latitudes and longitudes for each polyline and maybe a line length can help you to rule out obvious mismatches early on.
Maybe you should even go beyond that: Along with longitude and latitude, store Earth-Centered, Earth-fixed coordinates and keep them in a k-d Tree for easy closest-neighbour lookup. That's my bet for the best speedup of your algorithm, at the cost of extra data.
And it's probably better not to create a new list for each polyline and then delete from it but to keep the lists intact and keep a local "used" set which should be quicker to look up than deleting points.

Categories

Resources