ios mkmapview mkcoordinateregion mkmaprect

ios - Convierte MKCoordinateRegion a MKMapRect



mkmapview (9)

Tengo un MKMapView cuadrado en mi aplicación, y deseo establecer un punto central y el alto / ancho exacto de la vista en metros.

Creando una MKCoordinateRegion y estableciendo el mapa en ella (como en este código ...

MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center_coord, 1000.0, 1000.0); [self.mapView setRegion:region animated:YES];

..) no funciona correctamente porque el uso de regiones aquí solo significa que se muestra al menos esa región, generalmente más que la región.


Estoy planeando utilizar el método setVisibleMapRect:animated: lugar, ya que creo que se MKMapRect al MKMapRect pasado.

Entonces, ¿hay una manera simple de convertir entre una MKcoordinateRegion y una MKMapRect? ¿Quizás obteniendo las coordenadas superior izquierda e inferior derecha de la región y usándolas para hacer MKMapRect?

No pude ver nada útil en la Referencia de funciones del kit de mapas .

(Usando iOS 5, Xcode 4.2)


@ La respuesta de David, en Swift 3

func mapRect(region: MKCoordinateRegion) -> MKMapRect { let topLeft = CLLocationCoordinate2D( latitude: region.center.latitude + (region.span.latitudeDelta/2.0), longitude: region.center.longitude - (region.span.longitudeDelta/2.0) ) let bottomRight = CLLocationCoordinate2D( latitude: region.center.latitude - (region.span.latitudeDelta/2.0), longitude: region.center.longitude + (region.span.longitudeDelta/2.0) ) let topLeftMapPoint = MKMapPointForCoordinate(topLeft) let bottomRightMapPoint = MKMapPointForCoordinate(bottomRight) let origin = MKMapPoint(x: topLeftMapPoint.x, y: topLeftMapPoint.y) let size = MKMapSize(width: fabs(bottomRightMapPoint.x - topLeftMapPoint.x), height: fabs(bottomRightMapPoint.y - topLeftMapPoint.y)) return MKMapRect(origin: origin, size: size) }


@Bogdan

Creo que debería ser:

CLLocationCoordinate2D topLeftCoordinate = CLLocationCoordinate2DMake(coordinateRegion.center.latitude + (coordinateRegion.span.latitudeDelta/2.0), coordinateRegion.center.longitude - (coordinateRegion.span.longitudeDelta/2.0)); MKMapPoint topLeftMapPoint = MKMapPointForCoordinate(topLeftCoordinate); CLLocationCoordinate2D bottomRightCoordinate = CLLocationCoordinate2DMake(coordinateRegion.center.latitude - (coordinateRegion.span.latitudeDelta/2.0), coordinateRegion.center.longitude + (coordinateRegion.span.longitudeDelta/2.0)); MKMapPoint bottomRightMapPoint = MKMapPointForCoordinate(bottomRightCoordinate); MKMapRect mapRect = MKMapRectMake(topLeftMapPoint.x, topLeftMapPoint.y, fabs(bottomRightMapPoint.x-topLeftMapPoint.x), fabs(bottomRightMapPoint.y-topLeftMapPoint.y));

De acuerdo con la referencia api de apple , MKCoordinateRegion.center representa el punto central de la región; y MKCoordinateSpan.latitudeDelta representa la cantidad de distancia de norte a sur (medida en grados) para mostrar en el mapa; MKCoordinateSpan.longitudeDelta representa la cantidad de distancia de este a oeste (medida en grados) para mostrar para la región del mapa.


Esta es una solución de Swift verion a Leo & Barnhart

func MKMapRectForCoordinateRegion(region:MKCoordinateRegion) -> MKMapRect { let topLeft = CLLocationCoordinate2D(latitude: region.center.latitude + (region.span.latitudeDelta/2), longitude: region.center.longitude - (region.span.longitudeDelta/2)) let bottomRight = CLLocationCoordinate2D(latitude: region.center.latitude - (region.span.latitudeDelta/2), longitude: region.center.longitude + (region.span.longitudeDelta/2)) let a = MKMapPointForCoordinate(topLeft) let b = MKMapPointForCoordinate(bottomRight) return MKMapRect(origin: MKMapPoint(x:min(a.x,b.x), y:min(a.y,b.y)), size: MKMapSize(width: abs(a.x-b.x), height: abs(a.y-b.y))) }


La respuesta que dio @David (y en consecuencia la versión de Swift 3 por @ onmyway133) tiene un error significativo cada vez que la región cruza el meridiano antitérmico del Hemisferio Oriental (longitud 0 grados a 180 grados) al Hemisferio Occidental (longitud -180 grados) a 0 grados). El ancho de MKMapRect será más grande de lo que debería ser (generalmente mucho más grande).

Aquí está la solución (para el código Swift 3):

let topLeftMapPoint = MKMapPointForCoordinate(topLeft) let bottomRightMapPoint = MKMapPointForCoordinate(bottomRight) var width = bottomRightMapPoint.x - topLeftMapPoint.x if width < 0.0 { // Rect crosses from the Eastern Hemisphere to the Western Hemisphere width += MKMapPointForCoordinate(CLLocationCoordinate2D(latitude: 0.0, longitude: 180.0)).x } let height = bottomRightMapPoint.y - topLeftMapPoint.y let size = MKMapSize(width: width, height: height) return MKMapRect(origin: topLeftMapPoint, size: size)

Tomar una MKCoordinateRegion, convertirla en MKMapRect con el código anterior y luego volverla a una MKCoordinateRegion utilizando MKCoordinateRegionForMapRect () me da muy buena concordancia entre la región de entrada y la región de salida en cualquier parte del mapa.


Para agregar otra implementación a la pila:

- (MKMapRect)MKMapRectForCoordinateRegion:(MKCoordinateRegion)region { MKMapPoint a = MKMapPointForCoordinate(CLLocationCoordinate2DMake( region.center.latitude + region.span.latitudeDelta / 2, region.center.longitude - region.span.longitudeDelta / 2)); MKMapPoint b = MKMapPointForCoordinate(CLLocationCoordinate2DMake( region.center.latitude - region.span.latitudeDelta / 2, region.center.longitude + region.span.longitudeDelta / 2)); return MKMapRectMake(MIN(a.x,b.x), MIN(a.y,b.y), ABS(a.x-b.x), ABS(a.y-b.y)); }

NB: Hay muchas maneras de convertir entre MKMapRect y MKCoordinateRegion . Esta ciertamente no es la inversa exacta de MKCoordinateRegionMakeWithDistance() , pero se aproxima bastante bien. Por lo tanto, tenga cuidado de convertir de ida y vuelta, porque la información se puede perder.


Todavía tiene que ser un poco más cuidadoso al cruzar el meridiano (así como envolverse alrededor de los polos) de lo contrario, MKMapPointForCoordinate devuelve -1, -1:

public func MKMapRectForCoordinateRegion(region:MKCoordinateRegion) -> MKMapRect { var topLeft = CLLocationCoordinate2D( latitude: min(region.center.latitude + (region.span.latitudeDelta/2.0), 90), longitude: region.center.longitude - (region.span.longitudeDelta/2.0) ) if topLeft.longitude < -180 { // We wrapped around the meridian topLeft.longitude += 360 } var bottomRight = CLLocationCoordinate2D( latitude: max(region.center.latitude - (region.span.latitudeDelta/2.0), -90), longitude: region.center.longitude + (region.span.longitudeDelta/2.0) ) if bottomRight.longitude > 180 { // We wrapped around the medridian bottomRight.longitude -= 360 } let topLeftMapPoint = MKMapPointForCoordinate(topLeft) let bottomRightMapPoint = MKMapPointForCoordinate(bottomRight) var width = bottomRightMapPoint.x - topLeftMapPoint.x if width < 0.0 { // Rect crosses meridian width += MKMapPointForCoordinate(CLLocationCoordinate2D(latitude: 0.0, longitude: 180.0)).x } let height = bottomRightMapPoint.y - topLeftMapPoint.y let size = MKMapSize(width: width, height: height) return MKMapRect(origin: topLeftMapPoint, size: size) }

Algunos códigos de caso de prueba (usando Nimble):

func testMKMapRectForCoordinateRegion() { let northWesternRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(45.0, -90.0), MKCoordinateSpanMake(20.0, 20.0)) let northWesternMapRect = MKMapRectForCoordinateRegion(region: northWesternRegion) let convertedNWRegion = MKCoordinateRegionForMapRect(northWesternMapRect) expect(self.equivalentRegions(northWesternRegion, convertedNWRegion)).to(beTrue()) let northEasternRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(45.0, 90.0), MKCoordinateSpanMake(20.0, 20.0)) let northEasternMapRect = MKMapRectForCoordinateRegion(region: northEasternRegion) let convertedNERegion = MKCoordinateRegionForMapRect(northEasternMapRect) expect(self.equivalentRegions(northEasternRegion, convertedNERegion)).to(beTrue()) let southWesternRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(-45.0, -90.0), MKCoordinateSpanMake(20.0, 20.0)) let southWesternMapRect = MKMapRectForCoordinateRegion(region: southWesternRegion) let convertedSWRegion = MKCoordinateRegionForMapRect(southWesternMapRect) expect(self.equivalentRegions(southWesternRegion, convertedSWRegion)).to(beTrue()) let southEasternRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(-45.0, 90.0), MKCoordinateSpanMake(20.0, 20.0)) let southEasternMapRect = MKMapRectForCoordinateRegion(region: southEasternRegion) let convertedSERegion = MKCoordinateRegionForMapRect(southEasternMapRect) expect(self.equivalentRegions(southEasternRegion, convertedSERegion)).to(beTrue()) let meridianSpanEastRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(0.0, 170.0), MKCoordinateSpanMake(20.0, 20.0)) let meridianSpanEastMapRect = MKMapRectForCoordinateRegion(region: meridianSpanEastRegion) let convertedMeridianSpanEastRegion = MKCoordinateRegionForMapRect(meridianSpanEastMapRect) expect(self.equivalentRegions(meridianSpanEastRegion, convertedMeridianSpanEastRegion)).to(beTrue()) let meridianSpanWestRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(0.0, -170.0), MKCoordinateSpanMake(20.0, 20.0)) let meridianSpanWestMapRect = MKMapRectForCoordinateRegion(region: meridianSpanWestRegion) let convertedMeridianSpanWestRegion = MKCoordinateRegionForMapRect(meridianSpanWestMapRect) expect(self.equivalentRegions(meridianSpanWestRegion, convertedMeridianSpanWestRegion)).to(beTrue()) } fileprivate func equivalentRegions(_ regionA: MKCoordinateRegion, _ regionB: MKCoordinateRegion) -> Bool { // Allow a small delta between values let deltaAllowed: Double = 1.0 return (fabs(regionA.center.latitude - regionB.center.latitude) < deltaAllowed) && (fabs(regionA.center.longitude - regionB.center.longitude) < deltaAllowed) && (fabs(regionA.span.latitudeDelta - regionB.span.latitudeDelta) < deltaAllowed) && (fabs(regionA.span.longitudeDelta - regionB.span.longitudeDelta) < deltaAllowed) }


Use la función MKCoordinateRegionForMapRect

MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect);


Utilice MKMapPointForCoordinate para convertir los 2 puntos de la región (arriba / izquierda e inferior / derecha), luego cree MKMapRect usando los 2 MKMapPoints

CLLocationCoordinate2D coordinateOrigin = CLLocationCoordinate2DMake(latitude, longitude); CLLocationCoordinate2D coordinateMax = CLLocationCoordinate2DMake(latitude + cellSize, longitude + cellSize); MKMapPoint upperLeft = MKMapPointForCoordinate(coordinateOrigin); MKMapPoint lowerRight = MKMapPointForCoordinate(coordinateMax); MKMapRect mapRect = MKMapRectMake(upperLeft.x, upperLeft.y, lowerRight.x - upperLeft.x, lowerRight.y - upperLeft.y);


puede usar el método para convertir MKCoordinateRegion a CGRect

- (CGRect)convertRegion:(MKCoordinateRegion)region toRectToView:(UIView *)view

y use - (MKMapRect)mapRectForRect:(CGRect)rect

o use el método MKMapPointForCoordinate para convertir primero las coordenadas a MKPoint y usarlas para formar MKMapRect para eventualmente usar setVisibleMapRect:animated: