我在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甚至当我放大和缩小地图时。 我已经验证myLatitude是一个有效的lat(大约45度)。 我已经验证了myMetersValue是一个合理的#(大约18米)。
(编辑)
我发现MKMapPointsPerMeterAtLatitude返回的MapPoints不是屏幕点,所以我无法使用该功能。
所以我的基本问题是如何在mkMapView中将米转换为屏幕点。更简洁的是,我如何在代码中获得ppm的值?我试过这个(在SO的其他地方找到):
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不太正确,所以我不相信这是正确的。此外,当我缩放地图时,地图上的现有线条不会重新渲染,因此在缩放后保持相同的宽度(但这是一个不同的问题)。
(编辑)
现在看来我的ppm计算是正确的。问题是在用户完成缩放之前调用渲染器,因此不会以最终缩放比例渲染线条。当确定最终缩放比例后,我强制重新渲染,然后ppm是正确的,我的代码可以工作。
答案 0 :(得分:0)
因此,以下是绘制特定宽度的MkPolyline的一种方法,以米为单位。请注意,一旦在地图上绘制线条,如果用户缩放,则可能无法重新渲染。或者,如果是,则可以在用户完成缩放之前重新渲染。在这种情况下,缩放后的宽度将不再以米为单位反映所需的宽度。处理此问题的一种方法是覆盖regionDidChangeAnimated并删除叠加层并将其添加回来。这个方法在我的具体情况下运行正常,但我认为你应该看看Anna建议的解决方案,因为它可能是更好的通用方法。
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>) overlay
{
if([overlay isKindOfClass:[MKPolyline class]])
{
// the following are two methods of calculating PPM (screen points per meter).
// method 1: requires that you have access to a latitude that is near to the line you are drawing
CLLocationCoordinate2D l1 = CLLocationCoordinate2DMake(myLatitude, 0);
CLLocationCoordinate2D l2 = CLLocationCoordinate2DMake(myLatitude + 1.0, 0);
CGPoint p1 = [mapView convertCoordinate:l1 toPointToView:mapView];
CGPoint p2 = [mapView convertCoordinate:l2 toPointToView:mapView];
double ppm = (p1.y - p2.y) / (60.0 * METERS_PER_NAUTICALMILE);
// method 2:
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];
ppm = 500.0 / [ll1 distanceFromLocation:ll2];
MKPolyline *l = (MKPolyline *) overlay;
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.lineWidth = ppm * myMetersValue;
renderer.strokeColor = [UIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:.3];
renderer.lineCap = CGLineCap::kCGLineCapButt;
return renderer;
}
return nil;
}
答案 1 :(得分:0)
结合Bruce和Anna提供的信息,我编写了以下Polyline Renderer子类。
public extension MKMapView {
public func metersToPoints(meters: Double) -> Double {
let deltaPoints = 500.0
let point1 = CGPoint(x: 0, y: 0)
let coordinate1 = convert(point1, toCoordinateFrom: self)
let location1 = CLLocation(latitude: coordinate1.latitude, longitude: coordinate1.longitude)
let point2 = CGPoint(x: 0, y: deltaPoints)
let coordinate2 = convert(point2, toCoordinateFrom: self)
let location2 = CLLocation(latitude: coordinate2.latitude, longitude: coordinate2.longitude)
let deltaMeters = location1.distance(from: location2)
let pointsPerMeter = deltaPoints / deltaMeters
return meters * pointsPerMeter
}
}
public class ZoomingPolylineRenderer : MKPolylineRenderer {
private var mapView: MKMapView!
private var polylineWidth: Double! // Meters
convenience public init(polyline: MKPolyline, mapView: MKMapView, polylineWidth: Double) {
self.init(polyline: polyline)
self.mapView = mapView
self.polylineWidth = polylineWidth
}
override public func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
self.lineWidth = CGFloat(mapView.metersToPoints(meters: polylineWidth))
super.draw(mapRect, zoomScale: zoomScale, in: context)
}
}