Search code examples
swiftuiimageviewmapkitmkmapviewscale

How to Scale a Image 1:1 in Apple Maps


I need to scale an image/icon 1:1 in Apple Maps. Cannot find any Information about that topic on the Internet.

The Idea is to place a simple jpg as an UIImageView over the MKMapView . but if there is a other way please let me know

Just to be clear, I need to put the image in relation to the zoom level of the map. For example, show objects like a cat ;) or a tree in real size at the map. At the first step, the object should stay in the middle of the screen, so I can rotate and rearrange the map lying underneath. Later on a like to pin the object to the map.


Solution

  • I finally came up with something like this:

    class MapViewController: UIViewController {
    
        @IBOutlet weak var mapView: MKMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()        
            mapView.delegate = self
    
            draw()
        }
    
        func draw() {
    
            let region = mapView.region
            let center = region.center
    
            let pointsPerMeter = MKMapPointsPerMeterAtLatitude(center.latitude)
    
            // Real-World-Object with 24 Meters length and 4 Meters width
            let objectLength = pointsPerMeter*24
            let objectWidth = pointsPerMeter*4
            let mapSize = MKMapSize.init(width: objectLength, height: objectWidth)
            let mapPoint = MKMapPoint.init(center)
            let objectRect = MKMapRect.init(origin: mapPoint, size: mapSize)
    
            // clear the map
            mapView.removeOverlays(mapView.overlays)
    
            // create image overlay from Real-World-Object
            let objectOverlay = ImageOverlay(image: UIImage(named: "nameOfYourImageAsset")!, rect: objectRect.offsetBy(dx: -objectLength/2 , dy: -objectWidth/2))
    
            // add overlay to map
            mapView.addOverlay(objectOverlay)
    
        }
    
    }
    
    // found here https://stackoverflow.com/a/45989625/10878331
    class ImageOverlay : NSObject, MKOverlay {
        let image:UIImage
        let boundingMapRect: MKMapRect
        let coordinate:CLLocationCoordinate2D
    
        init(image: UIImage, rect: MKMapRect) {
            self.image = image
            self.boundingMapRect = rect
            self.coordinate = rect.origin.coordinate
        }
    }
    
    class ImageOverlayRenderer : MKOverlayRenderer {
        override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
    
            guard let overlay = self.overlay as? ImageOverlay else {
                return
            }
    
            let rect = self.rect(for: overlay.boundingMapRect)
    
            UIGraphicsPushContext(context)
            overlay.image.draw(in: rect)
            UIGraphicsPopContext()
        }
    }
    

    The Code isn't beauty yet, nor is it optimal, but it kind of works I guess. I assume that you already have your user location or any point so mapView.region has a valid value.

    The Code is still in progress. I will try to put a simple UIImage on top of the map which i hopefully can put into context of the map. I guess I need to set mapView.isZoomEnabled = false for ease