【问题标题】:How can I rotate and translate/scale an overlay so it matches the map rect?如何旋转和平移/缩放叠加层,使其与地图矩形匹配?
【发布时间】:2021-08-28 17:09:09
【问题描述】:

我有一个应用程序,用户可以在其中向地图添加图像。这很简单。当我想添加旋转(取自当前地图标题)时,它变得更加困难。我用来创建图像的代码非常简单:

let imageAspectRatio = Double(image.size.height / image.size.width)
let mapAspectRatio = Double(visibleMapRect.size.height / visibleMapRect.size.width)

var mapRect = visibleMapRect

if mapAspectRatio > imageAspectRatio {
    // Aspect ratio of map is bigger than aspect ratio of image (map is higher than the image), take away height from the rectangle
    let heightChange = mapRect.size.height - mapRect.size.width * imageAspectRatio
    mapRect.size.height = mapRect.size.width * imageAspectRatio
    mapRect.origin.y += heightChange / 2
} else {
    // Aspect ratio of map is smaller than aspect ratio of image (map is higher than the image), take away width from the rectangle
    let widthChange = mapRect.size.width - mapRect.size.height / imageAspectRatio
    mapRect.size.width = mapRect.size.height / imageAspectRatio
    mapRect.origin.x += widthChange / 2
}

photos.append(ImageOverlay(image: image, boundingMapRect: mapRect, rotation: cameraHeading))

ImageOverlay 类继承自 MKOverlay,我可以轻松地在地图上绘制。这是该类的代码:

class ImageOverlay: NSObject, MKOverlay {
    let image: UIImage
    let boundingMapRect: MKMapRect
    let coordinate: CLLocationCoordinate2D
    let rotation: CLLocationDirection
    
    init(image: UIImage, boundingMapRect: MKMapRect, rotation: CLLocationDirection) {
        self.image = UIImage.fixedOrientation(for: image) ?? image
        self.boundingMapRect = boundingMapRect
        self.coordinate = CLLocationCoordinate2D(latitude: boundingMapRect.midX, longitude: boundingMapRect.midY)
        self.rotation = rotation
    }
}

我已经弄清楚我需要多少缩放和翻译上下文以适应地图上的正确位置(从中添加它)。我不知道如何旋转上下文以使图像呈现在正确的位置。

我发现地图旋转是以度为单位的,而旋转方法需要弧度(花费的时间比我敢承认的要长),但是当我应用旋转时图像会四处移动。

我使用以下代码来渲染叠加层:

override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
    guard let overlay = overlay as? ImageOverlay else {
        return
    }
    
    let rect = self.rect(for: overlay.boundingMapRect)
    
    context.scaleBy(x: 1.0, y: -1.0)
    context.translateBy(x: 0.0, y: -rect.size.height)
    context.rotate(by: CGFloat(overlay.rotation * Double.pi / 180))
    context.draw(overlay.image.cgImage!, in: rect)
}

我需要如何旋转此上下文以使图像正确对齐?

这是一个开源项目,代码为here

编辑:我尝试过(但失败了)使用某种触发函数。如果我按3 * sin(rotation) / 4 的因子进行缩放(不知道 3/4 的来源),我会得到一些旋转的正确比例,但对于其他旋转则不然。

【问题讨论】:

标签: ios mapkit cgcontext mkoverlay


【解决方案1】:

听起来您试图在其本地坐标中旋转对象,但实际上是在世界坐标中旋转。我承认我不熟悉这个库,但这个故事的寓意是转换的操作顺序很重要。但是看起来您有“TranslateBy”并且您发送的内容为零,这可能根本不会移动它?如果您尝试转换回本地,则需要通过减去 CLLocationCoordinate2D 结构中的当前坐标来转换为本地。

  1. 如果本地坐标不存在,则转换为本地坐标(可能是 X:0、y:0,您可能需要减去当前坐标值,而不是尝试将它们设置为特定数字,例如 0)
  2. 应用轮播
  3. 转换回世界坐标(之前的位置,最初定义为 CLLocationCoordinate2D)

这应该允许图像处于正确的位置,但现在可以旋转以与标题对齐。

这是一篇解释您可能遇到的问题的论文,虽然更深入且特定于矩阵/opengl,但第一张幻灯片说明了您的问题。

Transforms PDF

【讨论】:

  • 我已经尝试(但失败了)以不同的顺序放置转换,有时旋转甚至不匹配,即使平移和缩放不应该对此产生影响。我开始认为旋转和平移与 3D 地图投影(而不仅仅是 2D 地图)有关,我将不得不做一些我不明白的花哨的事情:s
  • 在您的示例代码中,您有 context.translateBy(x: 0.0, y: -rect.size.height) 这不会在 x 轴上将其转换为 0,这仍然是您的代码正在尝试?你需要减去它的当前位置。
猜你喜欢
  • 1970-01-01
  • 2017-02-09
  • 1970-01-01
  • 1970-01-01
  • 2010-10-09
  • 1970-01-01
  • 1970-01-01
  • 2012-12-15
  • 1970-01-01
相关资源
最近更新 更多