J'ai un MKMapView carré dans mon application, et je souhaite définir un point central et la hauteur/largeur exacte de la vue en mètres.
Créer une MKCoordinateRegion et y définir la carte (comme dans ce code ...
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center_coord, 1000.0, 1000.0);
[self.mapView setRegion:region animated:YES];
..) ne fonctionne pas correctement car 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.
Je prévois d'utiliser la méthode setVisibleMapRect: animated: à la place, car je pense que cela va zoomer sur le MKMapRect réel passé.
Alors, existe-t-il un moyen simple de convertir entre un MKcoordinateRegion et un MKMapRect? Peut-être obtenir les coordonnées en haut à gauche et en bas à droite de la région et les utiliser pour créer le MKMapRect?
Je n'ai rien vu de pratique dans la référence des fonctions Map Kit .
(sous iOS 5, Xcode 4.2)
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 existe de nombreuses façons de convertir entre MKMapRect
et MKCoordinateRegion
. Celui-ci est certainement pas l'inverse exact de MKCoordinateRegionMakeWithDistance()
, mais il se rapproche assez bien. Soyez donc prudent lors des conversions avant et en arrière, car des informations peuvent être perdues.
Ceci est une version Swift vers la solution 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)))
}
Utilisez MKMapPointForCoordinate pour convertir les 2 points de la région (haut/gauche et bas/droite), puis créez 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);
@Bogdan
Je pense que ça 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 référence de l'API Apple , MKCoordinateRegion.center représente le point central de la région; et MKCoordinateSpan.latitudeDelta représente la quantité de distance nord-sud (mesurée en degrés) à afficher sur la carte; MKCoordinateSpan.longitudeDelta représente la distance d'est en ouest (mesurée en degrés) à afficher pour la région de la carte.
vous pouvez utiliser la méthode pour convertir MKCoordinateRegion
en CGRect
- (CGRect)convertRegion:(MKCoordinateRegion)region toRectToView:(UIView *)view
et utilisez - (MKMapRect)mapRectForRect:(CGRect)rect
ou utilisez la méthode MKMapPointForCoordinate
pour convertir d'abord les coordonnées en MKPoint
et utilisez-la pour former MKMapRect
pour éventuellement utiliser setVisibleMapRect:animated:
@ Réponse de David, dans 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)
}
Encore faut-il être un peu plus prudent sur la traversée du méridien (ainsi que sur les pôles) sinon MKMapPointForCoordinate renvoie -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)
}
Quelques codes de cas de test (en utilisant 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)
}
La réponse donnée par @David (et par conséquent la version Swift 3 par @ onmyway133) contient une erreur significative chaque fois que la région traverse l'antimé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 (généralement beaucoup plus grande).
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 reconvertir 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.
Utilisez la fonction intégrée MKCoordinateRegionForMapRect
MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect);