MKMapView setRegion“捕捉”到预定义的缩放级别?

时间:2010-08-31 18:24:11

标签: iphone mapkit mkmapview

任何人都可以确认setRegion“捕捉”到预定义的缩放级别,以及此行为是否与设计(虽然未记录)或已知错误一样?具体来说,似乎setRegion捕捉到与用户双击地图时使用的缩放级别相对应的相同缩放级别。

我正在尝试恢复以前保存的区域,但如果通过缩放缩放设置保存的区域而不是双击缩放,则此行为无法实现。

如果我在地图的当前区域调用regionThatFits,那么在mapkit方面就会出现问题,这是一个很大的线索。它应该返回相同的区域(因为它显然适合地图的框架),但它返回的区域对应于下一个更高的预定义缩放级别。

setVisibleMapRect的行为类似。

任何进一步的见解或信息将不胜感激。

我发现了这些相关的帖子,但都没有包含解决方案或确切的确认,这实际上是一个mapkit错误:

MKMapView setRegion: odd behavior?

MKMapView show incorrectly saved region

编辑:

这是一个演示此问题的示例。所有值对我的地图视图的宽高比都有效:

MKCoordinateRegion initialRegion;
initialRegion.center.latitude = 47.700200f;
initialRegion.center.longitude = -122.367109f;
initialRegion.span.latitudeDelta = 0.065189f;
initialRegion.span.longitudeDelta = 0.067318f;
[map setRegion:initialRegion animated:NO];
NSLog(@"DEBUG initialRegion:  %f  %f  %f  %f", initialRegion.center.latitude, initialRegion.center.longitude, initialRegion.span.latitudeDelta, initialRegion.span.longitudeDelta);
NSLog(@"DEBUG map.region:  %f  %f  %f  %f", map.region.center.latitude, map.region.center.longitude, map.region.span.latitudeDelta, map.region.span.longitudeDelta);

输出:

DEBUG initialRegion:  47.700199  -122.367111  0.065189  0.067318
DEBUG map.region:  47.700289  -122.367096  0.106287  0.109863

请注意纬度/经度增量值的差异。地图的值几乎是我要求的两倍。较大的值对应于用户双击地图时使用的缩放级别之一。

7 个答案:

答案 0 :(得分:7)

是的,它会捕捉到不连续的关卡。我做了很多实验,似乎像每个像素经度的2.68220906e-6度的倍数。

因此,如果您的地图填满整个屏幕宽度,第一个等级跨越.0008583度,那么您可以获得的下一个等级是.001717的两倍,然后下一个等级的两倍,.003433,等等。我不确定他们为什么选择经度标准化,这意味着修正缩放级别取决于您所看到的世界的哪个部分。

我也花了很多时间试图理解这个数字的重要性.68220906e-6度。它出现在赤道约30厘米,这是有道理的,因为谷歌地图使用的高分辨率照片有30厘米的分辨率,但我希望他们使用纬度而不是经度来建立缩放级别。这样,在最大变焦时,你总是能够获得卫星图像的原始分辨率,但是谁知道,他们可能有一些聪明人的理由让它像那样工作。

在我的应用程序中,我需要显示一定范围的纬度。我将使用一些代码来尝试尽可能地缩放地图。如果有人有兴趣,请与我联系。

答案 1 :(得分:1)

我找到了解决方案。

如果收到的快照缩放级别为,则假设比所需的大1.2倍: 使用此算法进行纠正:
假设:您希望将地图视图设置为从左到右精确显示“longitudinalMeters” 1)计算校正比例:
计算你收到的纵向跨度与你得到的纵向跨度之间的关系。

    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center, 0, longitudinalMeters);

    MKCoordinateRegion regionFits = [mapView regionThatFits: region];
    double correctionFactor = regionFits.span.longitudeDelta / region.span.longitudeDelta;

2)创建转换并将其应用于地图

   CGAffineTransform mapTransform = CGAffineTransformMakeScale(correctionScale, correctionScale);       
   CGAffineTransform pinTransform = CGAffineTransformInvert(mapTransform);
   [mapView setTransform:mapTransform];

3)将逆转换应用于Map引脚,使其保持原始大小

 [mapView setTransform:mapTransform];
 for (id<MKAnnotation> annotation in self.mapView.annotations)
 {
     [[self.mapView viewForAnnotation:annotation] setTransform:pinTransform];
 }

答案 2 :(得分:0)

奇怪的行为似乎是因为当一个人请求特定区域或视图大小时,谷歌的实际API调用会被调用中心点和缩放级别。 E.G:

map.setCenter(new google.maps.LatLng(234.3453, 454.2345), 42);

现在Apple可以请求适当的缩放级别,然后调整视图的大小以适应实际的区域请求,但似乎他们没有这样做。我正在地图上绘制公交车路线,我的一条路线几乎没有触发更大的缩放级别,因此缩放太小(缩放下)并且看起来很丑陋和破碎。

@pseudopeach,请更新我尝试解决此问题的进度。如果可以检测到缩放级别的边界,则可以故意缩小区域请求以避免缩小。既然你是这样的话,我就会有兴趣在我自己尝试之前看到你的代码。

Backspace Prolog博客的作者编写了一个有趣的类别,可以通过模拟他们的setCenter(centerPoint,ZoomLevel)调用签名来直接操作Google Maps API。你可以找到它here。我还没有花时间,但数学可能是逆向工程,以产生计算给定Region或MapRect的缩放级别的方法。取决于它在缩放级别范围内的距离 - 即它超过触发较低缩放级别的阈值的距离 - 它可以通过请求不足来决定是转到较低级别还是保持较高级别。

这显然是一个需要修复的行为错误,以便可以更精确地使用MKMapView。

答案 3 :(得分:0)

MKCoordinateRegion region;

region.center.latitude = latitude;
region.center.longitude = longitude;
region.span.latitudeDelta = 5.0;
region.span.longitudeDelta = 5.0;
[mapView setRegion:region animated:YES];

答案 4 :(得分:0)

这是一个老问题,但我最近详细调查了Google地图,并且可以分享一些见解。我不知道这对当前的Apple地图是否也有效。

分辨率捕捉到预定义缩放级别的原因是因为从Google服务器获取的原始地图是使用这些缩放级别绘制的。这些地图上的要素大小是以一定的分辨率绘制的。例如,这些地图上道路的宽度(以像素为单位)始终相同。在较高分辨率的地图上,绘制了更多的传统道路,但它们的宽度始终相同。分辨率会捕捉到预定义的级别,以确保始终以相同的大小描绘这些功能。也就是说,它不是一个bug而是一个功能。

由于地图的Mercator projection,这些预定义的分辨率因纬度而异。墨卡托投影很容易使用,因为纬度线是直线和水平线,经度线是直线和垂直线。但是使用墨卡托投影时,地图顶部的分辨率略高于底部(北半球)。这对于在北部和南部边缘拟合地图具有影响。

也就是说,当你从赤道开始并向北行驶时,那么你驾驶的墨卡托地图的分辨率会逐渐增加。经度线保持垂直,因此经度跨度保持不变。但分辨率增加,因此纬度跨度减小。尽管如此,在所有这些地图上,道路的像素宽度相同,文字也以相同的字体大小等描述。

Google使用墨卡托投影,其中赤道周长为缩放级别0的256像素。每个下一个缩放级别都会增加一倍。也就是说,在zoomlevel 1,赤道长512像素,在zoomlevel 2,赤道长1024像素等。他们使用的地球模型是一个FAI地球仪,半径正好为6371 km,或周长为40030公里。 因此,赤道处zoomLevel 0的分辨率为156.37 km /像素,在zoomlevel 1处的分辨率为78.19 km /像素等。然后,这些分辨率随着地球上任何其他地方的纬度的余弦而变化。

答案 5 :(得分:-1)

我没有问题地恢复该区域,并且没有您所描述的差异。如果没有一些代码可以看出你的情况下真的不能说出什么是特别错误的,但是这对我有用:

将中心值和跨度值保存在某处。当你恢复它们时,专门设置中心和跨度。

恢复应如下所示:

MKCoordinateRegion initialRegion;
initialRegion.center.latitude = Value you've stored
initialRegion.center.longitude = Value you've stored 
initialRegion.span.latitudeDelta = Value you've stored
initialRegion.span.longitudeDelta = Value you've stored
[self.mapView setRegion:initialRegion animated:NO];

还记得这个方法在4.0中可用:`mapRectThatFits:edgePadding:MapRectThatFits有助于添加合理的边框,以确保边缘上的地图注释不被遮挡,并且您尝试显示的矩形是完全的可见。如果你想控制边框,可以使用允许你设置edgePadding的调用。

答案 6 :(得分:-1)

如果在InterfaceBuilder中设置MapView,请确保不要这样做:

_mapView = [[MKMapView alloc] init];

我删除此初始化行后,我的地图视图突然开始正确响应我发送的所有更新。我怀疑发生的情况是,如果你执行alloc init,它实际上是在创建另一个没有在任何地方显示的视图。您在屏幕上看到的是您的笔尖初始化的那个。但是如果你为init分配一个新的,那么那就是其他的东西而且它不会做任何事情。