Conversion MKCoordinateRegion en MKMapRect

j'ai un MKMapView carré dans mon application, et je souhaite mettre un point central et la hauteur exacte/largeur de la vue en mètres.

créer un MKCoordinateRegion et mettre la carte à elle (comme dans ce code...

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

..) ne fonctionne pas correctement parce que l'utilisation de régions ici signifie simplement qu'au moins cette région est affichée, généralement plus que la région est.



Je suis à la planification sur l'utilisation de setVisibleMapRect: animated: méthode à la place, car je crois que cela va zoomer sur le réel MKMapRect passé.

alors, y a-t-il un moyen simple de convertir entre un MKcoordinateRegion et un MKMapRect? Peut-être obtenir les coordonnées haut-gauche et bas-droite de la région, et les utiliser pour faire le MKMapRect?

Je ne voyais rien de pratique sur la carte Fonctions Du Kit Référence .

(utilisant iOS 5, Xcode 4.2)

32
demandé sur Jon Cox 2012-02-14 04:50:17

9 réponses

pour ajouter une autre implémentation à la pile:

- (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: il y a plusieurs façons de convertir entre MKMapRect et MKCoordinateRegion . Celui-ci est certainement pas l'exact inverse de MKCoordinateRegionMakeWithDistance() , mais se rapproche assez bien. Donc, faites attention à la conversion de va-et-vient, parce que l'information peut être perdue.

51
répondu leo 2014-12-12 16:20:34

C'est une Swift version de Leo & Barnhart solution

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)))
}
23
répondu Mike 2016-02-10 17:11:11

utilisez MKMapPointForCoordinate pour convertir les 2 points de la région (Haut / Gauche et bas / droite), puis créer le MKMapRect en utilisant les 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);
12
répondu Bogdan 2012-06-21 18:14:55

vous pouvez utiliser la méthode pour convertir MKCoordinateRegion en CGRect

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

et utiliser - (MKMapRect)mapRectForRect:(CGRect)rect

ou utiliser la méthode MKMapPointForCoordinate pour convertir d'abord les coordonnées en MKPoint et utiliser cette méthode pour former MKMapRect pour éventuellement utiliser setVisibleMapRect:animated:

9
répondu chatur 2012-02-14 05:40:39

@Bogdan

je pense qu'il devrait être:

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

Selon pomme d'api de référence , MKCoordinateRegion.centre représente le point central de la région; et MKCoordinateSpan.latitudeDelta représente la distance Nord-Sud (mesurée en degrés) à afficher sur la carte; MKCoordinateSpan.la longitude Elta représente la distance est-ouest (mesurée en degrés) à afficher pour la région cartographique.

9
répondu David 2012-12-10 09:39:33

@David réponse, 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)
}
2
répondu onmyway133 2017-10-12 15:24:58

la réponse donnée par @David (et par conséquent la version Swift 3 de @onmyway133) comporte une erreur importante chaque fois que la région traverse l'anti-méridien de l'hémisphère oriental (longitude 0 degrés à 180 degrés) à l'hémisphère occidental (longitude -180 degrés à 0 degrés). La largeur du MKMapRect sera plus grande qu'elle ne devrait l'être (habituellement beaucoup plus grand).

voici le correctif (pour le code 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)

prendre un MKCoordinateRegion, le convertir en MKMapRect avec le code ci-dessus, puis le retourner en MKCoordinateRegion en utilisant MKCoordinateRegionForMapRect() me donne un très bon accord entre la région d'entrée et la région de sortie partout sur la carte.

1
répondu Mark A Durham 2017-08-11 00:45:50

doit encore être un peu plus prudent sur la traversée du méridien (ainsi que l'enroulement autour des pôles) sinon MKMapPointForCoordinate retourne -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)
}

Certains cas de test de code (à l'aide d'Agile):

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)
}
1
répondu GilroyKilroy 2017-09-04 19:28:07

utiliser la fonction intégrée MKCoordinateRegionForMapRect

MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect);
0
répondu Duane Fields 2012-03-26 15:25:40