我正在MkMapView上绘制线条,我想以米为单位指定其宽度。
我试过这样的东西:
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>) overlay
{
if([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
double ppm = MKMapPointsPerMeterAtLatitude(myLatitude);
renderer.lineWidth = ppm * myMetersValue;
...
这会产生一条比myMetersValue宽得多的线,并且在放大和缩小时不会缩放。
ppm保持恒定在约9.49即使我放大和缩小Map。我已验证myLatitude是有效的纬度(大约45度)。我已验证myMetersValue是合理的#(约18m)。
(编辑)
我发现MKMapPointsPerMeterAtLatitude返回的MapPoint不是屏幕点,所以我不能使用该函数。
所以我的基本问题是如何在mkMapView中将米转换为屏幕点。更简洁地说,我如何在代码中获得ppm的值?我试过这个(在其他地方找到):
MKCoordinateRegion myRegion = MKCoordinateRegionMakeWithDistance(mapView.centerCoordinate, 400, 0);
CGRect myRect = [mapView convertRegion: myRegion toRectToView: nil];
double ppm = myRect.size.width / 400.0;
这一招没用。
然后我试了这个:
CLLocationCoordinate2D l1 = [mapView convertPoint:CGPointMake(0,0) toCoordinateFromView:mapView];
CLLocation *ll1 = [[CLLocation alloc] initWithLatitude:l1.latitude longitude:l1.longitude];
CLLocationCoordinate2D l2 = [mapView convertPoint:CGPointMake(0,500) toCoordinateFromView:mapView];
CLLocation *ll2 = [[CLLocation alloc] initWithLatitude:l2.latitude longitude:l2.longitude];
double ppm = 500.0 / [ll1 distanceFromLocation:ll2];
这里的想法是获得相隔500个屏幕点的两个点的纬度/经度。然后得到它们之间的距离,这样我就可以计算ppm。这种工作,但它看起来像由此产生的ppm是不太正确的,所以我不相信这是正确的。另外,当我缩放Map时,Map上现有的线不会重新渲染,因此缩放后保持相同的宽度(但这是另一个问题)。
(编辑)
现在看来我的ppm计算是正确的。问题是渲染器在用户完成缩放之前被调用,因此线条不会以最终的缩放比例渲染。当我在最终缩放比例确定后强制重新渲染时,ppm是正确的,我的代码可以工作。
3条答案
按热度按时间avwztpqn1#
结合布鲁斯和安娜提供的信息,我编写了以下折线渲染器子类。
rkttyhzu2#
我尝试了上面Verticon的答案。虽然它达到了预期的效果,不幸的是它崩溃了我的操作系统模拟几次。我的目标是在放大一定距离后,主要放大到几乎道路的宽度。
我通过以下方式管理:首先创建我的自定义
MKPolyLine
类,它设置了一个width
变量,以及其他用于自定义的变量。首先包括我在别处使用的
MKMapView
的扩展:然后在我的
mapView(regionDidChangeAnimated)
函数中包含一个子句。将折线添加到Map后,我将它们附加到数组中。这工作正常,不同的计算和初始值可能可以集成到它的其他尺度。我使用扩展得到的最大值
zoomLevel
是~12.5,所以我使用了一些值来得到它。cczfrluj3#
因此,以下是绘制特定宽度(以米为单位)的MkPolyline的一种方法。请注意,一旦在Map上绘制了线,如果用户缩放,它可能不会重新渲染。或者,如果是这样,则它可以在用户完成缩放之前被重新渲染。在这种情况下,缩放后的宽度将不再反映所需的宽度(以米为单位)。处理此问题的一种方法是覆盖regionDidChangeAnimated并移除覆盖层并将其添加回来。这个方法在我的特定情况下工作正常,但我认为您应该看看安娜建议的解决方案,因为它可能是一个更好的通用方法。