In order to setup a query to an external server I want to get the bounds of the current Map View in an iPhone app I\'m building. UIView should respond to bounds but it seems
This extension solves this problem and maintain the centerCoordinate
syntax in Swift 5
extension MKMapView {
var northWestCoordinate: CLLocationCoordinate2D {
return MKMapPoint(x: visibleMapRect.minX, y: visibleMapRect.minY).coordinate
}
var northEastCoordinate: CLLocationCoordinate2D {
return MKMapPoint(x: visibleMapRect.maxX, y: visibleMapRect.minY).coordinate
}
var southEastCoordinate: CLLocationCoordinate2D {
return MKMapPoint(x: visibleMapRect.maxX, y: visibleMapRect.maxY).coordinate
}
var southWestCoordinate: CLLocationCoordinate2D {
return MKMapPoint(x: visibleMapRect.minX, y: visibleMapRect.maxY).coordinate
}
}
This http://wiki.openstreetmap.org/wiki/Bounding_Box is a document for bounding box
bbox = left,bottom,right,top
bbox = min Longitude , min Latitude , max Longitude , max Latitude
You can have a BoundingBox
struct that represents this
struct BoundingBox {
let min: CLLocationCoordinate2D
let max: CLLocationCoordinate2D
init(rect: MKMapRect) {
let bottomLeft = MKMapPointMake(rect.origin.x, MKMapRectGetMaxY(rect))
let topRight = MKMapPointMake(MKMapRectGetMaxX(rect), rect.origin.y)
min = MKCoordinateForMapPoint(bottomLeft)
max = MKCoordinateForMapPoint(topRight)
}
var points: [CLLocationDegrees] {
return [
min.latitude,
min.longitude,
max.latitude
max.longitude,
]
}
}
The visibleMapRect
is the same as region.span
let mapView = MKMapView(frame: CGRect(x: 0, y: 0, width: 320, height: 640))
XCTAssertEqual(mapView.userLocation.coordinate.latitude, 0)
XCTAssertEqual(mapView.userLocation.coordinate.longitude, 0)
let boundingBox = BoundingBox(rect: mapView.visibleMapRect)
XCTAssertEqual(boundingBox.max.longitude-boundingBox.min.longitude, mapView.region.span.longitudeDelta)
XCTAssertEqual(boundingBox.max.latitude-boundingBox.min.latitude, mapView.region.span.latitudeDelta)
I was having some trouble with some of the other answers for maps that had been 2 finger rotated. This code worked for me:
MKMapRect rect = self.mapView.visibleMapRect;
CLLocationCoordinate2D northeast = MKCoordinateForMapPoint(MKMapPointMake(MKMapRectGetMaxX(rect),rect.origin.y));
CLLocationCoordinate2D southwest = MKCoordinateForMapPoint(MKMapPointMake(rect.origin.x ,MKMapRectGetMaxY(rect)));
My answer is derived from 陈保状's answer and the associated website enter link description here. Its simplified down too 3 lines for south west and north east corners.
Updated @onmyway133's excellent answer for my purposes, I needed the coordinates of all four corners:
struct BoundingBox {
let topRight: CLLocationCoordinate2D
let topLeft: CLLocationCoordinate2D
let bottomRight: CLLocationCoordinate2D
let bottomLeft: CLLocationCoordinate2D
init(rect: MKMapRect) {
topRight = MKMapPoint(x: rect.maxX, y: rect.origin.y).coordinate
topLeft = MKMapPoint(x: rect.origin.x, y: rect.origin.y).coordinate
bottomRight = MKMapPoint(x: rect.maxX, y: rect.maxY).coordinate
bottomLeft = MKMapPoint(x: rect.origin.x, y: rect.maxY).coordinate
}
var items: [String: CLLocationCoordinate2D] {
return [
"topRight": topRight,
"topLeft": topLeft,
"bottomRight": bottomRight,
"bottomLeft": bottomLeft,
]
}
var points: [CLLocationDegrees] {
return [
topRight.latitude,
topRight.longitude,
topLeft.latitude,
topLeft.longitude,
bottomRight.latitude,
bottomRight.longitude,
bottomLeft.latitude,
bottomLeft.longitude,
]
}
}
And an example of how I used this data:
let boundingBox = BoundingBox(rect: mapView.visibleMapRect)
var annotations = Array<MKPointAnnotation>()
for point in boundingBox.items {
let newPoint = MKPointAnnotation()
newPoint.coordinate = point.value
annotations.append(newPoint)
}
mapView.addAnnotations(annotations)
Swift away... (Based on @deadroxy's answer...)
typealias Edges = (ne: CLLocationCoordinate2D, sw: CLLocationCoordinate2D)
extension MKMapView {
func edgePoints() -> Edges {
let nePoint = CGPoint(x: self.bounds.maxX, y: self.bounds.origin.y)
let swPoint = CGPoint(x: self.bounds.minX, y: self.bounds.maxY)
let neCoord = self.convert(nePoint, toCoordinateFrom: self)
let swCoord = self.convert(swPoint, toCoordinateFrom: self)
return (ne: neCoord, sw: swCoord)
}
}
This code works with map rotating like 90/180 degrees. set mapView.pitchEnabled = NO; for less bugs.
CLLocationDirection heading = mapView.camera.heading;
float mapWidth = mapView.frame.size.width;
float mapHeight = mapView.frame.size.height;
float neX = mapWidth;
float neY = 0.0;
float swX = 0.0;
float swY = mapHeight;
if (heading >= 0 && heading <= 90) {
//println("Q1")
float ratio = heading / 90;
neX = (1-ratio) * mapWidth;
swX = (mapWidth*ratio);
} else if (heading >= 90 && heading <= 180) {
//println("Q2")
float ratio = (heading - 90) / 90;
neX = 0;
neY = (mapHeight*ratio);
swY = (1-ratio) * mapHeight;
swX = mapWidth;
} else if (heading >= 180 && heading <= 270) {
//println("Q3")
float ratio = (heading - 180) / 90;
neX = mapWidth*ratio;
neY = mapHeight;
swX = (1-ratio) * mapWidth;
swY = 0;
} else if (heading >= 270 && heading <= 360) {
//println("Q4");
float ratio = (heading - 270) / 90;
neX = mapWidth;
neY = (1-ratio) * mapHeight;
swY = ratio * mapHeight;
}
CGPoint swPoint = CGPointMake(swX, swY);
CGPoint nePoint = CGPointMake(neX, neY);
CLLocationCoordinate2D swCoord = [mapView convertPoint:swPoint toCoordinateFromView:mapView];
CLLocationCoordinate2D neCoord = [mapView convertPoint:nePoint toCoordinateFromView:mapView];