You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MKOverlayRenderer加载NOAA雷达图像显示异常(拉伸)求助

问题描述

我尝试通过自定义MKOverlay与MKOverlayRenderer子类,在MapView中展示NOAA雷达图像。尝试多种方法后,要么因mapRect不正确导致无图像显示,要么图像南北方向拉伸至加拿大和南美区域,东西方向显示正常。怀疑是渲染器中mapRect的问题,已参考多个相关链接仍未解决,附上相关调用方法及代码:

调用显示的方法

func loadRadarImage() {
    let center = CLLocationCoordinate2D(latitude: 47.6062, longitude: -122.3320)
    let overlay = RadarOverlay(coord: center, rect: self.mapView.visibleMapRect)
    self.mapView.addOverlay(overlay, level: .aboveRoads)
}

MKOverlay类

class RadarOverlay: NSObject, MKOverlay {
    var coordinate: CLLocationCoordinate2D
    var boundingMapRect: MKMapRect
    init(coord: CLLocationCoordinate2D, rect: MKMapRect) {
        self.coordinate = coord
        self.boundingMapRect = rect
    }
}

MKOverlayRenderer类

@objcMembers class NOAAMapOverlayRenderer : MKOverlayRenderer {
    var radarImage : UIImage?
    init(overlay: MKOverlay, overlayImage: UIImage) {
        self.radarImage = overlayImage
        super.init(overlay: overlay)
    }
    override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
        if let mapImage = self.radarImage?.cgImage {
            let mapRect = rect(for: overlay.boundingMapRect) // CGRect
            context.scaleBy(x: 1.0, y: -1.0)
            context.translateBy(x: 0.0, y: CGFloat(-mapRect.size.height))
            context.draw(mapImage, in: mapRect)
        }
    }
}

当前效果:图像南北方向过度拉伸,东西方向显示正常。


解决方案

咱们来一步步排查修复这个问题,核心问题出在地理范围的定义和渲染时的坐标系/比例匹配上,下面是具体的调整方案:

1. 给Overlay设置正确的雷达地理范围

你现在直接用地图的可视区域visibleMapRect作为Overlay的边界,但NOAA雷达图本身有固定的经纬度覆盖范围,不能跟着当前地图视图走。你需要先确定雷达图对应的实际地理边界,再转换成正确的MKMapRect。

比如假设你的雷达图覆盖北纬45°到49°、西经120°到124°,可以这样计算:

// 定义雷达图的四个边角坐标
let topLeftCoord = CLLocationCoordinate2D(latitude: 49.0, longitude: -124.0)
let bottomRightCoord = CLLocationCoordinate2D(latitude: 45.0, longitude: -120.0)

// 转换为MapKit的地图点
let topLeftPoint = MKMapPoint(topLeftCoord)
let bottomRightPoint = MKMapPoint(bottomRightCoord)

// 计算准确的boundingMapRect
let radarMapRect = MKMapRect(
    x: topLeftPoint.x,
    y: topLeftPoint.y,
    width: bottomRightPoint.x - topLeftPoint.x,
    height: bottomRightPoint.y - topLeftPoint.y
)

然后用这个radarMapRect初始化RadarOverlay,替换原来的mapView.visibleMapRect。

2. 修复Renderer的绘制逻辑

你当前的draw方法有两个问题:一是没考虑zoomScale的影响,二是坐标系翻转的顺序不对。修改后的代码如下:

override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
    guard let radarCGImage = radarImage?.cgImage else { return }
    
    // 获取Overlay地理范围对应的屏幕矩形(自动适配当前缩放级别)
    let overlayScreenRect = rect(for: overlay.boundingMapRect)
    
    // 保存上下文状态,避免干扰其他绘制操作
    context.saveGState()
    
    // 正确翻转y轴:Core Graphics原点在左下角,MapKit在左上角
    context.translateBy(x: 0, y: overlayScreenRect.height)
    context.scaleBy(x: 1, y: -1)
    
    // 把雷达图绘制到正确的屏幕区域
    context.draw(radarCGImage, in: overlayScreenRect)
    
    // 恢复上下文状态
    context.restoreGState()
}

3. 确保图像比例和地理范围比例一致

雷达图是固定宽高比的,如果你的MKMapRect宽高比和图像不一致,必然会拉伸。可以加个验证步骤:

let imageRatio = radarImage.size.width / radarImage.size.height
let mapRectRatio = radarMapRect.width / radarMapRect.height
// 允许微小误差,避免浮点精度问题
assert(abs(imageRatio - mapRectRatio) < 0.01, "雷达图比例和地理范围比例不匹配,会导致拉伸!")

如果比例不匹配,需要调整地理范围的计算,或者对图像进行裁剪/缩放预处理。

4. 调整Overlay的添加时机

不要在地图还没加载完成时就调用loadRadarImage,否则visibleMapRect可能不准确。建议在mapView(_:regionDidChangeAnimated:)代理方法中更新Overlay,或者等地图初始化完成后再加载。


内容的提问来源于stack exchange,提问作者Tim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 07:28:11