2012-02-14 16 views
30

Nella mia app ho un MKMapView quadrato e desidero impostare un punto centrale e l'esatta altezza/larghezza della vista in metri.Converti MKCoordinateRegion in MKMapRect

Creazione di un MKCoordinateRegion e impostando la mappa per essa (come in questo codice ...

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

..) non funziona correttamente perché utilizza regioni qui solo significa che almeno viene visualizzata quella regione, tipicamente più della regione.


Sto pensando di usare setVisibleMapRect:animated: metodo, invece, come credo che questo sarà lo zoom al reale MKMapRect passato.

Quindi, c'è un modo semplice per convertire tra un MKcoordinateRegion e un MKMapRect? Forse ottenere le coordinate in alto a sinistra e in basso a destra della regione e usarle per creare MKMapRect?

Non ho trovato nulla di utile nello Map Kit Functions Reference.

(Utilizzando IOS 5, Xcode 4,2)

risposta

48

Per aggiungere un'altra applicazione al mucchio:

- (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: Ci sono molti modi per la conversione tra MKMapRect e MKCoordinateRegion. Questo è certamente non l'esatto inverso di MKCoordinateRegionMakeWithDistance(), ma lo si approssima abbastanza bene. Quindi, fai attenzione a convertire avanti e indietro, perché le informazioni possono essere perse.

+2

Grazie! Mi ha salvato un po 'di tempo. – Vinzius

+0

Fantastico, grazie. Usare una mappa rect invece di una regione è un ottimo modo per fare un offset, perché 'setVisibleMapRect' ha un'opzione per i margini. – SimplGy

+0

Questo produce un risultato errato, il rect risultante viene capovolto lateralmente. Ho usato la risposta @Wan Liqun di seguito, ha funzionato perfettamente! –

9

è possibile utilizzare il metodo per convertire MKCoordinateRegion a CGRect

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

Utilizzando - (MKMapRect)mapRectForRect:(CGRect)rect

o utilizzare MKMapPointForCoordinate metodo per convertire primo coordinate MKPoint e usalo per formare MKMapRect per utilizzare eventualmente setVisibleMapRect:animated:

+1

Potresti aggiungere la classe a cui appartengono le funzioni menzionate? ed eventualmente un esempio completo su come effettivamente effettuare la conversione – Daniel

+1

@Daniel è stato deprecato in iOS7, è probabilmente il motivo per cui non si trova il metodo. Puoi trovarlo nella classe di overlay. – Vinzius

1

utilizzare il costruito in funzione MKCoordinateRegionForMapRect

MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect); 
+15

questo è l'inverso della conversione richiesta, ma buono a sapersi immagino che – squinlan

+1

Apple non abbia dato le funzioni dirette perché non appropriato convertire la regione in rect. Non dovresti farlo con la tua app. –

12

Usa MKMapPointForCoordinate per convertire il 2 punto della regione (alto/sinistra e in basso/a destra), quindi creare il MKMapRect utilizzando i 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); 
7

@Bogdan

penso che dovrebbe essere:

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)); 

In base a apple api reference, MKCoordinateRegion.center rappresenta il punto centrale della regione; e MKCoordinateSpan.latitudeDelta rappresenta la quantità di distanza da nord a sud (misurata in gradi) da visualizzare sulla mappa; MKCoordinateSpan.longitudeDelta rappresenta la quantità di distanza est-ovest (misurata in gradi) da visualizzare per la regione della mappa.

+0

Questo produce il risultato atteso, non la risposta accettata –

17

Questa è una verion Swift a Leo & soluzione 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))) 
} 
+0

Grazie mille per questo. – Fattie

1

@ risposta di David, a 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) 
} 
1

La risposta @ David ha dato (e di conseguenza la versione Swift 3 da @ onmyway133) ha un errore significativo ogni volta che la regione attraversa l'anti-meridiano dall'emisfero orientale (longitudine da 0 gradi a 180 gradi) all'emisfero occidentale (longitudine -180 gradi a 0 gradi). La larghezza di MKMapRect sarà maggiore di quanto dovrebbe essere (in genere molto più grande).

Ecco la correzione (per il codice 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) 

L'assunzione di un MKCoordinateRegion, trasformandola in un MKMapRect con il codice di cui sopra, e poi girando di nuovo in un MKCoordinateRegion utilizzando MKCoordinateRegionForMapRect() dà mi trovo molto d'accordo tra la regione di input e la regione di output ovunque sulla mappa.

+0

@GilroyKilroy registra correttamente la latitudine su [-90, 90]. Una regione di coordinate che si estende su un polo sembrerebbe un papillon mentre guardi in basso sulla regione polare, e questo si tradurrebbe in due aree MKMapRect disgiunte. –

0

devono ancora essere un po 'più attenti a che attraversa il meridiano (così come involucro attorno ai poli) altrimenti MKMapPointForCoordinate restituisce -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) 
} 

Alcuni codice banco di prova (con 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) 
}