I am working with an API that allows me to specify a "bounding box" of coordinate which allows me to only return results within that box:
Returns a list of geocaches inside the specified bounding box sorted
by the distance from the center of the box.
The parameters south
latitude, west longitude, north latitude, east longitude define the
edges of a bounding box.
Coordinates should be in decimal degrees Use
positive numbers for north latitude and east longitude and negative
numbers of south latitude and west longitude.
The box cannot cross
the 180° longitude line or the 90° or -90° points.
The math for this is a little beyond me, but I found somewhat helpful calculations, but I am not sure it is what I need for the API:
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.centerCoordinate, 2000.0, 2000.0);
CLLocationCoordinate2D northWestCorner, southEastCorner;
northWestCorner.latitude = center.latitude - (region.span.latitudeDelta / 2.0);
northWestCorner.longitude = center.longitude + (region.span.longitudeDelta / 2.0);
southEastCorner.latitude = center.latitude + (region.span.latitudeDelta / 2.0);
southEastCorner.longitude = center.longitude - (region.span.longitudeDelta / 2.0);
Does anyone know how I could do this? Are the calculations here not helpful in order to get the west longitude, north latitude, east longitude that define the edges of the bounding box?
EDIT:
The error I am getting:
Invalid value for parameter: bbox=south,west,north,east
Using the center value:
center=37.552821,-122.377413
Converted Box (after calculations from above):
bbox=37.561831,-122.388730,37.543811,-122.366096
Final Working code:
// Current distance
MKMapRect mRect = mapView.visibleMapRect;
MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect));
MKMapPoint westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect));
CLLocationDistance distance = MKMetersBetweenMapPoints(eastMapPoint, westMapPoint);
// Region
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(request.center, distance, distance);
CLLocationCoordinate2D northWestCorner, southEastCorner;
northWestCorner.latitude = request.center.latitude + (region.span.latitudeDelta / 2.0);
northWestCorner.longitude = request.center.longitude - (region.span.longitudeDelta / 2.0);
southEastCorner.latitude = request.center.latitude - (region.span.latitudeDelta / 2.0);
southEastCorner.longitude = request.center.longitude + (region.span.longitudeDelta / 2.0);
base = [base stringByAppendingFormat:#"bbox=%f,%f,%f,%f&", southEastCorner.latitude,northWestCorner.longitude,northWestCorner.latitude,southEastCorner.longitude];
You seem to have gotten your hemispheres reversed. North and east are positive. So if you start from the center latitude and you want to find the northern boundary you ADD half the delta, not subtract.
Related
I want to calculate a MKCoordinateRegion with a diagonal distance of 30km and the proportions of the region should be the same as the maps frame.
My approach looks like this:
let alpha = atan(mapView.frame.width / mapView.frame.height).radiansToDegrees
let beta = 90 - alpha
let spanDiagonal = 30_000.0
let spanWidth = spanDiagonal * Double(cos(beta.degreesToRadians))
let spanHeight = sqrt(spanDiagonal * spanDiagonal + spanWidth * spanWidth)
let region = MKCoordinateRegionMakeWithDistance(mapView.centerCoordinate, spanWidth, spanHeight)
let tlLat = region.center.latitude + (region.span.latitudeDelta / 2.0)
let tlLong = region.center.longitude - (region.span.longitudeDelta / 2.0)
let brLat = region.center.latitude - (region.span.latitudeDelta / 2.0)
let brLong = region.center.longitude + (region.span.longitudeDelta / 2.0)
let tl = CLLocationCoordinate2D(latitude: tlLat, longitude: tlLong)
let br = CLLocationCoordinate2D(latitude: brLat, longitude: brLong)
print(MKMetersBetweenMapPoints(MKMapPointForCoordinate(tl), MKMapPointForCoordinate(br)))
I calculated the angle of the frame and then a triangle with this angle and a base of 30000. This resulted in what I thought the right span height and width.
The problem that I have is that the diagonal of the region is about 10km larger. I think the cause for this is the conversion of meters to degrees that is somehow wrong.
Do you see a problem with my approach or do you know any better way to calculate a region with the same proportions of the frame, a diagonal of 30km and the same center as the map?
I ended up using this awesome library which implements the Euclid algorithm and allows you to expand a bounding box around a coordinate. Exactly what I was looking for!
How can I calculate South West and North East coordinates from a position. I do not have the MKMapView. I need to calculate solely on the basis of CLLocationCoordinate2D.
Found it:
#define DEGREE(RADIANS) (180/M_PI) * RADIANS
#define RADIANS(DEGREE) (M_PI/180) * DEGREE
double lat = [[_locManager location] coordinate].latitude;
double lon = [[_locManager location] coordinate].longitude;
double R = 6371; // earth radius in km
double radius = 0.5; // bounding box spacing from current location in kilo meters
double y2 = lon + DEGREE(radius/R/cos(RADIANS(lat)));
double y1 = lon - DEGREE(radius/R/cos(RADIANS(lat)));
double x2 = lat + DEGREE(radius/R);
double x1 = lat - DEGREE(radius/R);
x1, y1 is South West latitude and longitude and x2,y2 is North East latitude and longitude
In my iOS app I have a lat and long that gives me my location. I want to be able to calculate the bounding box that satisfies a certain distance d from my location. How can I do this?
TRY 1:
So I tried the solution given by #Neeku. I can see how it's supposed to return the right information but unfortunately it's off. So I don't think I can use it.
The code I wrote is this and I pass in 1000 meters:
MKCoordinateRegion startRegion = MKCoordinateRegionMakeWithDistance(center, meters, meters);
CLLocationCoordinate2D northWestCorner, southEastCorner;
northWestCorner.latitude = startRegion.center.latitude + .5 * startRegion.span.latitudeDelta;
northWestCorner.longitude = startRegion.center.longitude - .5 * startRegion.span.longitudeDelta;
southEastCorner.latitude = startRegion.center.latitude - .5 * startRegion.span.latitudeDelta;
southEastCorner.longitude = startRegion.center.longitude - .5 * startRegion.span.longitudeDelta;
NSLog(#"CENTER <%#,%#>", #(center.latitude),#(center.longitude));
NSLog(#"NW <%#,%#>, SE <%#,%#>",#(northWestCorner.latitude),#(northWestCorner.longitude),#(southEastCorner.latitude),#(southEastCorner.longitude));
So then the result is:
CENTER <38.0826682,46.3028721>
NW <38.08717278501047,46.29717303828632>, SE <38.07816361498953,46.29717303828632>
I then put that in google maps and get this: (see screenshot)
So then to my understanding the 1000 meters should go from the center to the sides of the box. The map is measuring the corner which should be OVER 1000 meters and it's actually just over 800 meters. This is the problem I am trying to solve.
I tried this method before and the distances simply aren't accurate. So, this solution has not worked for me. If you have more suggestions or maybe want to point out what is done wrong here please let me know.
Thank you
Let's say that your desired distance is 111 meters. Then you use the following code:
// 111 kilometers / 1000 = 111 meters.
// 1 degree of latitude = ~111 kilometers.
// 1 / 1000 means an offset of coordinate by 111 meters.
float offset = 1.0 / 1000.0;
float latMax = location.latitude + offset;
float latMin = location.latitude - offset;
// With longitude, things are a bit more complex.
// 1 degree of longitude = 111km only at equator (gradually shrinks to zero at the poles)
// So need to take into account latitude too, using cos(lat).
float lngOffset = offset * cos(location.latitude * M_PI / 180.0);
float lngMax = location.longitude + lngOffset;
float lngMin = location.longitude - lngOffset;
latMax, latMin, lngMax, lngMin will give you your bounding box coordinates.
(You can change this code pretty easily if you need distance other than 111 meters. Just update offset variable accordingly).
You can add/subtract half of the span from the latitude and longitude respectively and you get the values that you need:
CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(38.0826682, 46.3028721);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoord, 1000, 1000);
double latMin = region.center.latitude - .5 * startRegion.span.latitudeDelta;
double latMax = region.center.latitude + .5 * startRegion.span.latitudeDelta;
double lonMin = region.center.longitude - .5 * startRegion.span.longitudeDelta;
double lonMax = region.center.longitude + .5 * startRegion.span.longitudeDelta;
Just remember that:
latitudeDelta
The amount of north-to-south distance (measured in degrees) to display on the map. Unlike longitudinal distances, which vary based on
the latitude, one degree of latitude is always approximately 111
kilometers (69 miles).
longitudeDelta
The amount of east-to-west distance (measured in degrees) to display for the map region. The number of kilometers spanned by a
longitude range varies based on the current latitude. For example, one
degree of longitude spans a distance of approximately 111 kilometers
(69 miles) at the equator but shrinks to 0 kilometers at the poles.
I want to calculate the distance between 2 lat & long. I am able to calculate the distance as below
CLLocation *currentLoc = [[CLLocation alloc] initWithLatitude:-24.4132995 longitude:121.0790024];
CLLocation *restaurnatLoc = [[CLLocation alloc] initWithLatitude:-32.8310013 longitude:150.1390075];
CLLocationDistance meters = [restaurnatLoc distanceFromLocation:currentLoc];
NSLog(#"Distance between 2 geo cordinates: %.2f Meters",meters);
Now I want to get the direction from currentLocation to restaurnatLoc. For this I have below code
double DegreesToRadians(double degrees) {return degrees * M_PI / 180;};
double RadiansToDegrees(double radians) {return radians * 180/M_PI;};
-(double) bearingToLocationFromCoordinate:(CLLocation*)fromLoc toCoordinate:(CLLocation*)toLoc
{
double lat1 = DegreesToRadians(fromLoc.coordinate.latitude);
double lon1 = DegreesToRadians(fromLoc.coordinate.longitude);
double lat2 = DegreesToRadians(toLoc.coordinate.latitude);
double lon2 = DegreesToRadians(toLoc.coordinate.longitude);
double dLon = lon2 - lon1;
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
double radiansBearing = atan2(y, x);
return RadiansToDegrees(radiansBearing);
}
It returns bearing = 114.975752 Now how can I decide whether restaurant is in North,South,West,East,NW,NE,SW,SE from my current location ?
I get 1 solution from this link Direction based off of 2 Lat,Long points But if I consider this solution , then I have doubt on bearing 114 from my location(red circle) to restaurant (green circle) as shown below. Correct me if I am wrong.
As current location is "Western Australia" & restaurant location is "Sydney" as shown in Google Maps.
Can any body tell me whats going wrong here ? Thanks.
///////////////////////////// Update /////////////////////////////
My compass diagram is wrong. Here is the correct diagram all thanks to AlexWien
Now I am getting the correct output
your compass rose is totally wrong. have you ever looked at a compass? open the iphone compass app and look where 90Degrees is located. It is east, not west like in your graphic.
geographical direction is measured clockwise!
so 114 deg is east, which matches you expectation
I'd like to make a Geographic Bounding box Calculation in iOS.
It can be aprox.
Input Parameters:
Current Location (Example: 41.145495, −73.994901)
Radius In Meters: (Example: 2000)
Required Output:
MinLong: (Example: 41.9995495)
MinLat: (Example: −74.004901)
MaxLong: (Example: 41.0005495)
MaxLat: (Example: −73.004901)
Requirement:
No Network Call
Any Ideas?
Mapkit / CoreLocation does not seem to offer this type of thing?
Any other Geographic SDK that i could use?
Thanks
I think you can use standard MapKit functions: MKCoordinateRegionMakeWithDistance, this will return a MKCoordinateRegion, which is really just a center point (lat, lon) and the spans in the latitudal and longitudal direction in degrees. Add/subtract half of the span from the latitude and longitude respectively and you have the values you're looking for.
CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(41.145495, −73.994901);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoord, 2000, 2000);
double latMin = region.center.latitude - .5 * startRegion.span.latitudeDelta;
double latMax = region.center.latitude + .5 * startRegion.span.latitudeDelta;
double lonMin = region.center.longitude - .5 * startRegion.span.longitudeDelta;
double lonMax = region.center.longitude + .5 * startRegion.span.longitudeDelta;
By the way: this is only representative for the longitude for small spans, in the order of a couple of kilometers. To quote Apple:
latitudeDelta
The amount of north-to-south distance (measured in degrees) to use for the span. Unlike longitudinal distances, which vary based on the latitude, one degree of latitude is approximately 111 kilometers (69 miles) at all times.
longitudeDelta
The amount of east-to-west distance (measured in degrees) to use for the span. The number of kilometers spanned by a longitude range varies based on the current latitude. For example, one degree of longitude spans a distance of approximately 111 kilometers (69 miles) at the equator but shrinks to 0 kilometers at the poles.
I know I'm a bit late to the party, but I just built a class GTBoundingBox that might (or might not) help:
https://github.com/wpearse/ios-geotools