Files
ChWebsiteApp/CHDataManagement/Workouts/MapImageCreator.swift
2025-08-21 20:26:22 +02:00

84 lines
2.8 KiB
Swift

import Foundation
import AppKit
import MapKit
struct MapImageCreator {
let locations: [CLLocation]
func createMapSnapshot(
size layoutSize: CGSize,
scale: CGFloat = 2.0,
lineWidth: CGFloat = 5,
paddingFactor: Double = 1.2,
completion: @escaping ((image: NSImage, imagePoints: [CGPoint])?) -> Void
) {
guard !locations.isEmpty else {
completion(nil)
return
}
let coordinates = locations.map { $0.coordinate }
let pixelSize = CGSize(width: layoutSize.width * scale, height: layoutSize.height * scale)
let options = MKMapSnapshotter.Options()
options.size = pixelSize
options.preferredConfiguration = MKHybridMapConfiguration(elevationStyle: .flat)
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
let boundingMapRect = polyline.boundingMapRect
let region = MKCoordinateRegion(boundingMapRect)
let latDelta = region.span.latitudeDelta * paddingFactor
let lonDelta = region.span.longitudeDelta * paddingFactor
let paddedRegion = MKCoordinateRegion(
center: region.center,
span: MKCoordinateSpan(latitudeDelta: latDelta, longitudeDelta: lonDelta)
)
options.region = paddedRegion
let snapshotter = MKMapSnapshotter(options: options)
snapshotter.start { snapshotOrNil, error in
guard let snapshot = snapshotOrNil, error == nil else {
print("Snapshot error: \(error?.localizedDescription ?? "unknown error")")
completion(nil)
return
}
let image = NSImage(size: pixelSize)
image.lockFocus()
snapshot.image.draw(in: CGRect(origin: .zero, size: pixelSize))
let path = NSBezierPath()
path.lineJoinStyle = .round
let imagePoints = coordinates.map { snapshot.point(for: $0) }
if let first = imagePoints.first {
path.move(to: first)
for point in imagePoints.dropFirst() {
path.line(to: point)
}
NSColor.systemBlue.setStroke()
path.lineWidth = lineWidth * scale
path.stroke()
}
image.unlockFocus()
// Recalculate imagePoints since they were inside the drawing block
let widthFactor = 1 / pixelSize.width
let heightFactor = 1 / pixelSize.height
let finalImagePoints = coordinates.map { coordinate in
let point = snapshot.point(for: coordinate)
return CGPoint(x: point.x * widthFactor,
y: point.y * heightFactor)
}
completion((image, finalImagePoints))
}
}
}