How to get the area of the polygons from wiki mapia api - geolocation

I'm Using wiki mapia api to get the geo information.
Wiki Mapia
http://api.wikimapia.org/?key=example&function=place.getnearest&lat=12.9605459&lon=77.5649618&count=50&format=json&category=15417.
this api returning, location name lat,lng,min lat lng, max lat lng , polygon.
Like that i need polygon area. anyone used this api kindly suggest me how to get the area parameter .

Without using the api, and only using the points returned by the api you may apply the following algorithm (specified here in pseudocode):
function polygonArea(X, Y, numPoints)
{
area = 0; // Accumulates area
j = numPoints-1; // The last vertex is the previous one to first
for (i=0; i<numPoints; i++)
{
area = area + (X[j]+X[i]) * (Y[j]-Y[i]);
j = i; //j is previous vertex to i
}
return area/2;
}

Related

How do I increase the maximum number of Markers in Vaadin Maps?

In Vaadin Maps (Vaadin 23) I'm finding that only a certain number of markers are displayed on the map. How do I for example show up to say 500 markers (as in 500 locations in the code below)?
locations.stream().forEach(location -> {
Coordinate coordinate = Coordinate.fromLonLat(Double.parseDouble(location.getLon()), Double.parseDouble(location.getLat()));
MarkerFeature customerMarker = new MarkerFeature(coordinate);
map.getFeatureLayer().addFeature(customerMarker);
});
thanks for checking out the new Map component.
There shouldn't be any limit to the number of markers that you can add, neither from the Vaadin component, nor the underlying OpenLayers library.
Here is an example that displays 500 markers:
int numMarkers = 500;
double x = 0;
double y = 0;
for (int i = 0; i < numMarkers; i++) {
// Display ten rows of fifty markers
if (i % 50 == 0) {
y += 1000;
x = 0;
} else {
x += 1000;
}
Coordinate coordinate = new Coordinate(x, y);
MarkerFeature marker = new MarkerFeature(coordinate);
map.getFeatureLayer().addFeature(marker);
}
One thing you could check is whether all locations actually have unique coordinates, maybe there are some overlaps. For example the Coordinate.fromLonLat method you use trims values if longitude/latitude are out of bounds, which would put multiple markers in the same location in that case.
Apart from that you can always open an issue with a reproduction, and we'll take a look.

Calculate area covered by a polygon on earth

I am trying to calculate the area covered by a polygon on a map in square kilometers.
Based on the code from [1] and the corresponding paper [2] I have this code:
double area = 0;
auto coords = QList<QGeoCoordinate>{(QGeoCoordinate(50.542908183, 6.2521438908), QGeoCoordinate(50.250550175, 6.2521438908), QGeoCoordinate(50.250550175, 6.4901310043), QGeoCoordinate(50.542908183, 6.4901310043))};
for(int i=0; i<coords.size()-1; i++)
{
const auto &p1 = coords[i];
const auto &p2 = coords[i+1];
area += qDegreesToRadians(p2.longitude() - p1.longitude()) *
(2 + qSin(qDegreesToRadians(p2.latitude())) +
qSin(qDegreesToRadians(p1.latitude())));
}
area = area * 6378137.0 * 6378137.0 / 2.0;
qDebug() << "Area:" << (area/1000000);
qDebug() << coords;
But the calculated area is completely wrong. Also moving the polyon's vertices around results in strange results: Depending on the vertex the calculated area gets smaller althought the polgon's area is increased and vice verse. The calculated area also seems to depend on which vertex is used as start vertex.
Interestingly the signed are of a ring algorithm (getArea from [1]) returns correct results, meaning that the calculated area increases/decreases when the polygon's size is changed.
The code for calculating the area on a sphere was also used elsewhere so I am pretty sure that something is wrong with my implementation.
[1] https://github.com/openlayers/openlayers/blob/v2.13.1/lib/OpenLayers/Geometry/LinearRing.js#L251
[2] https://trs.jpl.nasa.gov/bitstream/handle/2014/40409/JPL%20Pub%2007-3%20%20w%20Errata.pdf?sequence=3&isAllowed=y
[3] Polygon area calculation using Latitude and Longitude generated from Cartesian space and a world file
I still could not find the error in my code but switching to the ringArea method from https://github.com/mapbox/geojson-area/blob/master/index.js works.

What is the best way to interpolate points between coordinates in google path? Is this approach correct?

Am trying to plot Polyline on Googlemap to show the position of driver/delivery boy to user like in Uber.
I use google directions API get overview Polyline and draw it on map. Now I get the driver location from our own server and in order to update the user location on map I iterate through the co-ordinates in GMSPath which I obtained by decoding the over-view Polyline as
if let jsonArray = jsonResult["routes"].array, jsonArray.count > 0 {
for json in jsonArray {
if let polyline = json["overview_polyline"]["points"].string {
self.possibleOverViewPolylines.append(polyline)
}
}
}
self.currentPolyline = self.possibleOverViewPolylines[0]
self.path = GMSMutablePath.init(fromEncodedPath: self.currentPolyline)
self.polyline = GMSPolyline(path: self.path)
Google usually returns multiple routes when sent alternative=true so I cache all the overview_polyline and use the first one as current over line.
Now from reading and trial-error I have figured out that there can be error in lat-long of driver captured and it might range from 5-50meters. So once I get the driver location I iterate through entire coordinates in path to find the closest point in map and snap driver to that location
var overallDistance: CLLocationDistance = 50
for index in 0 ..< strongSelf.path.count() {
let coordinate = strongSelf.path.coordinate(at: UInt(index))
let distance = location.distance(to: coordinate)
if distance < overallDistance {
foundIndex = Int(index)
overallDistance = distance
}
}
if overallDistance >= 50 {
debugPrint("\(location)")
evaluateAlternativeRoutes()
}
else {
updatepolyline(location: strongSelf.path.coordinate(at: UInt(foundIndex)))
}
update Polyline as
self?.polyline.map = nil
while strongSelf.path.coordinate(at: UInt(0)).latitude != location.latitude && strongSelf.path.coordinate(at: UInt(0)).longitude != location.longitude {
self?.path.removeCoordinate(at: 0)
}
if strongSelf.path.coordinate(at: 0).latitude == location.latitude && strongSelf.path.coordinate(at: UInt(0)).longitude == location.longitude {
self?.path.removeCoordinate(at: 0)
}
self?.polyline = GMSPolyline(path: strongSelf.path)
Finally alternative routes are evaluated as
var overallDistance: CLLocationDistance = 50
var foundIndex = -1
for (polylineIndex,polyline) in strongSelf.possibleOverViewPolylines.enumerated() {
if let path = GMSMutablePath.init(fromEncodedPath: polyline) {
for index in 0 ..< path.count() {
let coordinate = path.coordinate(at: UInt(index))
let distance = location.distance(to: coordinate)
if distance < overallDistance {
foundIndex = polylineIndex
overallDistance = distance
}
}
}
}
if foundIndex != -1 {
self?.path = GMSMutablePath.init(fromEncodedPath: strongSelf.possibleOverViewPolylines[foundIndex])
}
else {
//make routes API call again
}
If none of the alternative routes available matches the driver location, driver might be taking a whole different route so I make routes API call again with driver location
Why So many optimisation?
Google's routes APIs are costly and calling google routes API unnecessarily will add financial burden as well as screw up the whole user experience, hence want to make most of the calculations locally
But above code works sub-optimally :( It works but not great :|
Issues with this approach
Issue 1:
Method assumes the possible error rate in drivers location is 50m max, and when I evaluate all the distance to points in path are checked against this 50, but unfortunately coordinates in google paths are not equally distributed, on a lengthy straight road, distance between 2 subsequent points in path's coordinates can be up to 200m. I tested it with
for i in 0 ..< self.path.count() {
if i == 0 {
debugPrint(self.path.coordinate(at: i))
}
else {
debugPrint("distance between \(self.path.coordinate(at: (i - 1))) and \(self.path.coordinate(at: (i))) is \(self.path.coordinate(at: (i - 1)).distance(to: self.path.coordinate(at: (i))))")
}
}
So logic of comparing drivers location to all points in path with 50m as cap logic fails there.
Solution I can think of
If I can interpolate the points between any two coordinates in google path with a regular interval of 50m, and raise the cap to 100m (50m distance between two points in path, 50m for error in lat-long) that should give fairly better chance for me to reduce number of API calls
What I have tried?
I tried solving it with linear interpolation using
No need to tell the result is disastrous, because equation assumes a Cartesian plane and earth is not flat :|
So finally What the heck are you asking?
Is it a correct approach to interpolate the points between two coordinates of google path to achieve what am trying to achieve?
If yes, what is the better interpolation algorithm I should be using? Clearly linear doesn't make much sense :(
Please help, thanks in advance
Google itself has provided various methods for interpolating within GMSGeometryUtils module. I think what you need for interpolating could be the:
https://developers.google.com/maps/documentation/ios-sdk/reference/group___geometry_utils.html#gad0c5870bd9d182d22310f84a77888124
GMSGeometryInterpolate uses shortest path between 'from' and 'to' coordinate that you provide at a given fraction, and GMSPath indeed connects shortest paths between each sub-sequential coordinates you provide so it should be sufficient.

Find distance of location to route in Google Maps SDK

I´m developing an iPhone app, and I need some help with this case:
I need to check, if user leave google maps route (GMSPolyline) and if distance from user location to nearest point of route is more than 40 meters -- I need to rebuild route.
I can't find the right algorithm to detect if distance from user to route is more than 40 meters.
I've tried to use this method to find projection of user location (converted to CGPoint by CGPointMake) on route :
+ (CGPoint)projectionOfPoint:(CGPoint)origPoint toSegmentP1:(CGPoint)p1 p2:(CGPoint)p2 {
// for case line is parallel to x axis
if (p2.y == p1.y) {
return CGPointMake(origPoint.x, p1.y);
// for case line is parallel to y axis
} else if (p2.x == p1.x) {
return CGPointMake(p1.x, origPoint.y);
}
// line from segment
CGFloat kKoefLine1 = (p2.x - p1.x)/(p2.y - p1.y);
CGFloat bKoefLine1 = p1.y - kKoefLine1*p1.x;
// perpendicular line
CGFloat kKoefLine2 = -1/kKoefLine1;
CGFloat bKoefLine2 = origPoint.y - kKoefLine2*origPoint.x;
// cross point
CGFloat krossX = (bKoefLine2 - bKoefLine1)/(kKoefLine1 - kKoefLine2);
CGFloat krossY = kKoefLine2*krossX + bKoefLine2;
return CGPointMake(krossX, krossY);}
Then I calculate distance from returned projection (converted to CLLocation) and user location, but it doesn't works.
P.S.: I will be thankful if solution would be written on swift.
There is a GMSGeometryIsLocationOnPath function in the GMSGeometryUtils module in the Google Maps SDK.
You should be able to use that to calculate what you need.
Pseudocode (not tested):
let currentLocation: CLLocationCoordinate2D = ...
let routePath: GMSPath = routePolyline.path
let geodesic = true
let tolerance: CLLocationDistance = 40
let within40Meters = GMSGeometryIsLocationOnPath(currentLocation, routePath, geodesic, tolerance)
for swift 5.0 and based on #Arthur answer I wrote follwoing function
func isInRoute(posLL: CLLocationCoordinate2D, path: GMSPath) -> Bool
{
let geodesic = true
let tolerance: CLLocationDistance = 40
let within40Meters = GMSGeometryIsLocationOnPathTolerance(posLL, path, geodesic, tolerance)
return within40Meters
}
While I don't recall much about the GMS SDK off the top of my head, before I give you an answer, I will say that nobody on here will write your code for you. That's your job and should be done on your time. You haven't given any background as to how far you've gotten in terms of calculating routes, whether or not you've figured out how to calculate distance at all, etc.
With that being said, routes on Google Maps are comprised of "legs", which denote a path to take before a turn is made in efforts to reach the end destination. By querying your "route" dictionary, you can extract an array of dictionaries where each element (which is a dictionary) contains metadata about a "leg". You can then loop through that array, go through each dictionary and extract the "distance" value, and sum them to a single "distance" var.
You can recalculate this as often as needed and use a conditional to check whether or not the leg distance sum is < 40M, else rebuild.
link to an article that should help (I didn't have the time to go through the entire thing for you, so do your due diligence and research) here.

How to determine the next POI in a navigation route?

I have a route (MKPolyline derived from an MKRoute retrieved from Apple's MKDirections API) and a bunch of points of interest (array of MKAnnotations) that are close to the route.
I would like to know how to select the next POI the user is going to meet following the route, in order to present it through a UI.
Two different approaches come to mind, but none of them is really adequate:
The first one would be to mark the POIs as checked each time you get close enough to them, and simply display the first unmarked POI in the array (we'll assume that they are correctly ordered). The problem is that if for a reason or another one of the POIs is not checked, then the app will forever display it instead of displaying the actual next POI coming. This situation can arise e.g. if the user followed a slightly different route than the one suggested, that didn't come close enough to the POI to get it checked; or the user starts the navigation after the first POI; etc.
The second one one would be to select the POI closest to the user (probably also with a marking system to avoid presenting the POI you just checked). But this would only work for routes straight enough: sometimes in mountain zones or other sinuous routes you can get closer to a point that you will actually cross later. I expect this situation to happen actually quite often.
Any idea?
When I had to implement a turn-by-turn in one of our apps I used what you describe as first bullet. To figure out if user diverged from original polyline I calculated distance between current position and line segments each time I read a new position. Once I detected I was NOT following the path, I re-calculated the route while showing a "Recalculating..." message for user.
This is my code
- (BOOL)isCoordinate:(CLLocationCoordinate2D)coordinate closeToPolyline:(MKPolyline *)polyline {
CLLocationCoordinate2D polylineCoordinates[polyline.pointCount];
[polyline getCoordinates:polylineCoordinates range:NSMakeRange(0, polyline.pointCount)];
for (int i = 0; i < polyline.pointCount - 1; i++) {
CLLocationCoordinate2D a = polylineCoordinates[i];
CLLocationCoordinate2D b = polylineCoordinates[i + 1];
double distance = [self distanceToPoint:MKMapPointForCoordinate(coordinate) fromLineSegmentBetween:MKMapPointForCoordinate(a) and:MKMapPointForCoordinate(b)];
if (distance < 25) {
return YES;
}
}
return NO;
}
- (double)distanceToPoint:(MKMapPoint)p fromLineSegmentBetween:(MKMapPoint)l1 and:(MKMapPoint)l2 {
double A = p.x - l1.x;
double B = p.y - l1.y;
double C = l2.x - l1.x;
double D = l2.y - l1.y;
double dot = A * C + B * D;
double len_sq = C * C + D * D;
double param = dot / len_sq;
double xx, yy;
if (param < 0 || (l1.x == l2.x && l1.y == l2.y)) {
xx = l1.x;
yy = l1.y;
}
else if (param > 1) {
xx = l2.x;
yy = l2.y;
}
else {
xx = l1.x + param * C;
yy = l1.y + param * D;
}
return MKMetersBetweenMapPoints(p, MKMapPointMake(xx, yy));
}
Then I call - (BOOL)isCoordinate:(CLLocationCoordinate2D)coordinate closeToPolyline:(MKPolyline *)polyline { with coordinate being users current location and polyline being path from your MKDirections.
In my case I wouldn't allow more than 25 meters off but it might depend on your lat/lng precision.
Maybe it will help you or someone.
Use the following pseudometric, which I'll call route distance. Intuitively, it works like highway location markers. Assume that the route polyline does not touch or cross itself (is simple). For each point q on some segment pr of the polyline where p comes first, the location of that point in our 1D coordinate system is the Euclidean (spherical?) distance from p to q, plus the lengths of all segments that come before pr. The route distance between two such points is the absolute value of the difference of their locations in our 1D coordinate system. Extend route distance to points off of the route by treating such points as the closest point on the route (the answers to this question about computing point-to-segment distance should be helpful for computing the closest route point).
Present the closest POI to the user by route distance (check it off when this distance is sufficiently small).

Resources