From 71b3cb2cd6942db0b869127f4fa7b5671a7bc71b Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sat, 28 Sep 2024 21:00:03 -0400 Subject: [PATCH 01/11] Update to GEOSwift 11; Bump min versions --- .gitignore | 1 - .../package.xcworkspace/contents.xcworkspacedata | 7 +++++++ CHANGELOG.md | 6 ++++++ GEOSwiftMapKit.podspec | 14 ++++++-------- Package.swift | 6 +++--- README.md | 6 +++--- 6 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/.gitignore b/.gitignore index 5887e4e..b286f84 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,3 @@ Carthage/Build # Swift Package Manager .build/ -.swiftpm/ diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index ad5b1ed..2dbbd67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.0.0 + +* Updates to GEOSwift 11.0.0 +* Increases min Swift version to 5.9 +* Increases min deployment targets for Apple platforms + ## 4.0.0 * Updates to GEOSwift 10.0.0 diff --git a/GEOSwiftMapKit.podspec b/GEOSwiftMapKit.podspec index b5e28c0..05ddcf0 100644 --- a/GEOSwiftMapKit.podspec +++ b/GEOSwiftMapKit.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'GEOSwiftMapKit' - s.version = '4.0.0' - s.swift_version = '5.5' + s.version = '5.0.0' + s.swift_version = '5.9' s.cocoapods_version = '~> 1.10' s.summary = 'MapKit support for GEOSwift' s.description = <<~DESC @@ -15,16 +15,14 @@ Pod::Spec.new do |s| file: 'LICENSE' } s.authors = 'Andrew Hershberger' - s.platforms = { - ios: '9.0', - osx: '10.9', - tvos: '9.2', - } + s.ios.deployment_target = '12.0' + s.macos.deployment_target = '10.13' + s.tvos.deployment_target = '12.0' s.source = { git: 'https://github.com/GEOSwift/GEOSwiftMapKit.git', tag: s.version } s.source_files = 'Sources/**/*.swift' s.macos.exclude_files = 'GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift' - s.dependency 'GEOSwift', '~> 10.0' + s.dependency 'GEOSwift', '~> 11.0' end diff --git a/Package.swift b/Package.swift index 52eea63..64eecbf 100644 --- a/Package.swift +++ b/Package.swift @@ -1,14 +1,14 @@ -// swift-tools-version:5.5 +// swift-tools-version:5.9 import PackageDescription let package = Package( name: "GEOSwiftMapKit", - platforms: [.iOS(.v9), .macOS("10.9"), .tvOS("9.2")], + platforms: [.iOS(.v12), .macOS(.v10_13), .tvOS(.v12)], products: [ .library(name: "GEOSwiftMapKit", targets: ["GEOSwiftMapKit"]) ], dependencies: [ - .package(url: "https://github.com/GEOSwift/GEOSwift.git", from: "10.0.0") + .package(url: "https://github.com/GEOSwift/GEOSwift.git", from: "11.0.0") ], targets: [ .target( diff --git a/README.md b/README.md index 9774ec2..13d913d 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ See [GEOSwift](https://github.com/GEOSwift/GEOSwift) for full details ## Requirements -* iOS 9.0+, tvOS 9.2+, macOS 10.9+ (CocoaPods, Swift PM) -* Swift 5.5 +* iOS 12.0+, tvOS 12.0+, macOS 10.13+ (CocoaPods, Swift PM) +* Swift 5.9 > GEOS is licensed under LGPL 2.1 and its compatibility with static linking is at least controversial. Use of geos without dynamic linking is discouraged. @@ -30,7 +30,7 @@ at least controversial. Use of geos without dynamic linking is discouraged. 1. Update the top-level dependencies in your `Package.swift` to include: - .package(url: "https://github.com/GEOSwift/GEOSwiftMapKit.git", from: "4.0.0") + .package(url: "https://github.com/GEOSwift/GEOSwiftMapKit.git", from: "5.0.0") 2. Update the target dependencies in your `Package.swift` to include From 8a8c29fad5af3d96e8a3fe2e804ba11606410f8a Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sat, 28 Sep 2024 21:02:58 -0400 Subject: [PATCH 02/11] Update CI environment --- .github/workflows/main.yml | 78 +++++++++++++++----------------------- 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 26fb0c9..90f7d60 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,25 +3,29 @@ name: GEOSwiftMapKit on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: swiftlint: - runs-on: macos-12 + runs-on: macos-14 steps: - uses: actions/checkout@v3 + - name: Install SwiftLint + run: brew install swiftlint - name: Swiftlint - run: swiftlint + run: swiftlint --strict podspec: name: Lint Podspec for ${{ matrix.platform }} - runs-on: macos-12 + runs-on: macos-14 strategy: matrix: platform: [ios, osx, tvos] steps: - uses: actions/checkout@v3 + - name: Update CocoaPods Specs + run: pod repo update - name: Lint Podspec run: pod lib lint --platforms=${{ matrix.platform }} xcodebuild: @@ -30,46 +34,26 @@ jobs: strategy: matrix: include: - - name: "xcodebuild (iOS 16.2, Xcode 14.2)" - os: macos-12 - xcode-version: "14.2" - sdk: iphonesimulator16.2 - destination: "platform=iOS Simulator,OS=16.2,name=iPhone 14" - - name: "xcodebuild (tvOS 16.1, Xcode 14.2)" - os: macos-12 - xcode-version: "14.2" - sdk: appletvsimulator16.1 - destination: "platform=tvOS Simulator,OS=16.1,name=Apple TV" - - name: "xcodebuild (macOS 13.1, Xcode 14.2)" - os: macos-12 - xcode-version: "14.2" - sdk: macosx13.1 - destination: "platform=macOS" - - name: "xcodebuild (macCatalyst 13.1, Xcode 14.2)" - os: macos-12 - xcode-version: "14.2" - sdk: macosx13.1 - destination: "platform=macOS,variant=Mac Catalyst" - - name: "xcodebuild (iOS 15.2, Xcode 13.2.1)" - os: macos-11 - xcode-version: "13.2.1" - sdk: iphonesimulator15.2 - destination: "platform=iOS Simulator,OS=15.2,name=iPhone 13" - - name: "xcodebuild (tvOS 15.2, Xcode 13.2.1)" - os: macos-11 - xcode-version: "13.2.1" - sdk: appletvsimulator15.2 - destination: "platform=tvOS Simulator,OS=15.2,name=Apple TV" - - name: "xcodebuild (macOS 12.1, Xcode 13.2.1)" - os: macos-11 - xcode-version: "13.2.1" - sdk: macosx12.1 + - name: "xcodebuild (iOS 17.5, Xcode 15.4)" + os: macos-14 + xcode-version: "15.4" + sdk: iphonesimulator17.5 + destination: "platform=iOS Simulator,OS=17.5,name=iPhone 15" + - name: "xcodebuild (tvOS 17.5, Xcode 15.4)" + os: macos-14 + xcode-version: "15.4" + sdk: appletvsimulator17.5 + destination: "platform=tvOS Simulator,OS=17.5,name=Apple TV" + - name: "xcodebuild (macOS 14.5, Xcode 15.4)" + os: macos-14 + xcode-version: "15.4" + sdk: macosx14.5 destination: "platform=OS X" - - name: "xcodebuild (macCatalyst 12.1, Xcode 13.2.1)" - os: macos-11 - xcode-version: "13.2.1" - sdk: macosx12.1 - destination: "platform=OS X,variant=Mac Catalyst" + - name: "xcodebuild (watchOS 10.5, Xcode 15.4)" + os: macos-14 + xcode-version: "15.4" + sdk: watchsimulator10.5 + destination: "platform=watchOS Simulator,OS=10.5,name=Apple Watch Series 9 (45mm)" steps: - uses: actions/checkout@v3 - name: Select Xcode Version @@ -89,10 +73,8 @@ jobs: strategy: matrix: include: - - os: macos-11 - xcode-version: "13.2.1" - - os: macos-12 - xcode-version: "14.2" + - os: macos-14 + xcode-version: "15.4" steps: - uses: actions/checkout@v3 - name: Select Xcode Version From 2341102e8a9395e78869a716bc2a6cb0a7393abe Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sat, 28 Sep 2024 21:13:19 -0400 Subject: [PATCH 03/11] Fix lint --- .github/workflows/main.yml | 2 +- Package.resolved | 42 ++++++++++---------- Sources/GEOSwiftMapKit/GEOSwift+MapKit.swift | 2 +- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 90f7d60..f77f47d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: runs-on: macos-14 strategy: matrix: - platform: [ios, osx, tvos] + platform: [ios, macos, tvos] steps: - uses: actions/checkout@v3 - name: Update CocoaPods Specs diff --git a/Package.resolved b/Package.resolved index a74e5cf..794e9ab 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,25 +1,23 @@ { - "object": { - "pins": [ - { - "package": "geos", - "repositoryURL": "https://github.com/GEOSwift/geos.git", - "state": { - "branch": null, - "revision": "f510e634c822116fca615064d889300dba40d761", - "version": "8.1.0" - } - }, - { - "package": "GEOSwift", - "repositoryURL": "https://github.com/GEOSwift/GEOSwift.git", - "state": { - "branch": null, - "revision": "e55eef92fb533107b43e30fcf275223a5055797e", - "version": "10.0.0" - } + "pins" : [ + { + "identity" : "geos", + "kind" : "remoteSourceControl", + "location" : "https://github.com/GEOSwift/geos.git", + "state" : { + "revision" : "4d8af495e7507f48f1ae9104102debdd2043917b", + "version" : "9.0.0" } - ] - }, - "version": 1 + }, + { + "identity" : "geoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/GEOSwift/GEOSwift.git", + "state" : { + "revision" : "e42c062c2feb0df61373ae8cd6031a823a0dc981", + "version" : "11.0.0" + } + } + ], + "version" : 2 } diff --git a/Sources/GEOSwiftMapKit/GEOSwift+MapKit.swift b/Sources/GEOSwiftMapKit/GEOSwift+MapKit.swift index d6b8fc1..6084b2c 100644 --- a/Sources/GEOSwiftMapKit/GEOSwift+MapKit.swift +++ b/Sources/GEOSwiftMapKit/GEOSwift+MapKit.swift @@ -20,7 +20,7 @@ public extension Point { public extension GEOSwift.Polygon { static var world: GEOSwift.Polygon { // swiftlint:disable:next force_try - return try! Polygon(exterior: Polygon.LinearRing(points: [ + try! Polygon(exterior: Polygon.LinearRing(points: [ Point(x: -180, y: 90), Point(x: -180, y: -90), Point(x: 180, y: -90), From 316ec3e3234f269b4a3cf1d489d2d8194476098d Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sat, 28 Sep 2024 21:45:33 -0400 Subject: [PATCH 04/11] add test plan --- .../xcschemes/GEOSwiftMapKit.xcscheme | 84 +++++++++++++++++++ GEOSwiftMapKit.xctestplan | 24 ++++++ 2 files changed, 108 insertions(+) create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/GEOSwiftMapKit.xcscheme create mode 100644 GEOSwiftMapKit.xctestplan diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/GEOSwiftMapKit.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/GEOSwiftMapKit.xcscheme new file mode 100644 index 0000000..904de4f --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/GEOSwiftMapKit.xcscheme @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GEOSwiftMapKit.xctestplan b/GEOSwiftMapKit.xctestplan new file mode 100644 index 0000000..146528a --- /dev/null +++ b/GEOSwiftMapKit.xctestplan @@ -0,0 +1,24 @@ +{ + "configurations" : [ + { + "id" : "13C39BF1-17D7-4105-AD5C-3810194BC2B3", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + "codeCoverage" : false + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "GEOSwiftMapKitTests", + "name" : "GEOSwiftMapKitTests" + } + } + ], + "version" : 1 +} From b0144b03b11fb66cc2390670f472a671fb144434 Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sat, 28 Sep 2024 21:56:32 -0400 Subject: [PATCH 05/11] add workspace --- .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Playgrounds/GEOSwiftMapKit.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Playgrounds/GEOSwiftMapKit.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/GEOSwiftMapKit.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Playgrounds/GEOSwiftMapKit.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + From b2be1a3c6d6b0411ed69ae9626ffa6073df8e1a0 Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sat, 28 Sep 2024 22:00:52 -0400 Subject: [PATCH 06/11] remove watchos --- .github/workflows/main.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f77f47d..0c29603 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,11 +49,6 @@ jobs: xcode-version: "15.4" sdk: macosx14.5 destination: "platform=OS X" - - name: "xcodebuild (watchOS 10.5, Xcode 15.4)" - os: macos-14 - xcode-version: "15.4" - sdk: watchsimulator10.5 - destination: "platform=watchOS Simulator,OS=10.5,name=Apple Watch Series 9 (45mm)" steps: - uses: actions/checkout@v3 - name: Select Xcode Version From 66108e8e6a6d8c954ec85b65d239f148687275ac Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sat, 28 Sep 2024 21:56:58 -0400 Subject: [PATCH 07/11] fix warnings when building with swift 6 compiler --- .../GEOSwift+MapKitQuickLook.swift | 232 ++++++++++-------- .../MapKit+Equatable.swift | 12 +- 2 files changed, 139 insertions(+), 105 deletions(-) diff --git a/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift b/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift index b6cda67..5206e47 100644 --- a/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift +++ b/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift @@ -4,43 +4,92 @@ import UIKit import MapKit import GEOSwift -protocol GEOSwiftQuickLook: CustomPlaygroundDisplayConvertible, GeometryConvertible { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) +extension Point: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } } -extension GEOSwiftQuickLook { - public var playgroundDescription: Any { - let defaultReturnValue: Any = (try? geometry.wkt()) ?? self - var bufferValue: Double = 0 - if case .point = geometry { - bufferValue = 0.1 - } - guard let buffered = try? geometry.buffer(by: bufferValue)?.intersection(with: Polygon.world), - let region = try? MKCoordinateRegion(containing: buffered) else { - return defaultReturnValue - } - let mapView = MKMapView() - mapView.mapType = .standard - mapView.frame = CGRect(x: 0, y: 0, width: 400, height: 400) - mapView.region = region - guard let image = mapView.snapshot else { - return defaultReturnValue - } - UIGraphicsBeginImageContextWithOptions(image.size, true, image.scale) - guard let context = UIGraphicsGetCurrentContext() else { - return defaultReturnValue - } - defer { UIGraphicsEndImageContext() } - image.draw(at: .zero) - quickLookDraw(in: context, imageSize: image.size, mapRect: mapView.visibleMapRect) - return UIGraphicsGetImageFromCurrentImageContext() ?? defaultReturnValue +extension MultiPoint: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension LineString: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension MultiLineString: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension GEOSwift.Polygon.LinearRing: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension GEOSwift.Polygon: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension MultiPolygon: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension GeometryCollection: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension Geometry: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension Envelope: @retroactive CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +private func makePlaygroundDescription(for g: (some GEOSwiftQuickLook)) -> Any { + let defaultReturnValue: Any = (try? g.geometry.wkt()) ?? g + var bufferValue: Double = 0 + if case .point = g.geometry { + bufferValue = 0.1 + } + guard let buffered = try? g.geometry.buffer(by: bufferValue)?.intersection(with: Polygon.world), + let region = try? MKCoordinateRegion(containing: buffered) else { + return defaultReturnValue } - fileprivate func draw( + let options = MKMapSnapshotter.Options() + options.region = region + options.size = CGSize(width: 400, height: 400) + var snapshot: MKMapSnapshotter.Snapshot? + let backgroundQueue = DispatchQueue.global(qos: .userInitiated) + let snapshotter = MKMapSnapshotter(options: options) + let semaphore = DispatchSemaphore(value: 0) + snapshotter.start(with: backgroundQueue) { s, _ in + snapshot = s + semaphore.signal() + } + _ = semaphore.wait(timeout: .now() + 3) + guard let snapshot else { + return defaultReturnValue + } + let format = UIGraphicsImageRendererFormat.default() + format.opaque = true + format.scale = snapshot.image.scale + return UIGraphicsImageRenderer(size: snapshot.image.size, format: format).image { context in + snapshot.image.draw(at: .zero) + g.quickLookDraw(in: context.cgContext, snapshot: snapshot) + } +} + +private protocol GEOSwiftQuickLook: GeometryConvertible { + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) +} + +private extension GEOSwiftQuickLook { + func draw( in context: CGContext, imageSize: CGSize, mapRect: MKMapRect, - renderer: MKOverlayRenderer) { + renderer: MKOverlayRenderer + ) { context.saveGState() // scale the content to fit inside the image @@ -60,128 +109,113 @@ extension GEOSwiftQuickLook { } extension Point: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { - let pin = MKPinAnnotationView(annotation: nil, reuseIdentifier: "") - if let pinImage = pin.image { - let coord = CLLocationCoordinate2D(self) - let mapPoint = MKMapPoint(coord) - let point = CGPoint( - x: round(CGFloat((mapPoint.x - mapRect.origin.x) / mapRect.size.width) * imageSize.width), - y: round(CGFloat((mapPoint.y - mapRect.origin.y) / mapRect.size.height) * imageSize.height)) - var pinImageRect = CGRect(x: 0, y: 0, width: pinImage.size.width, height: pinImage.size.height) - pinImageRect = pinImageRect.offsetBy(dx: point.x - pinImageRect.width / 2, - dy: point.y - pinImageRect.height) - pinImage.draw(in: pinImageRect) - } + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { + let coord = CLLocationCoordinate2D(self) + let point = snapshot.point(for: coord) + let rect = CGRect(origin: point, size: .zero).insetBy(dx: -10, dy: -10) + UIColor.red.setFill() + context.fillEllipse(in: rect) } } extension MultiPoint: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { for point in points { - point.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + point.quickLookDraw(in: context, snapshot: snapshot) } } } extension LineString: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { - let polyline = MKPolyline(lineString: self) - let renderer = MKPolylineRenderer(polyline: polyline) - renderer.lineWidth = 2 - renderer.strokeColor = UIColor.blue.withAlphaComponent(0.7) - draw(in: context, imageSize: imageSize, mapRect: mapRect, renderer: renderer) + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { + UIColor.blue.withAlphaComponent(0.7).setStroke() + let path = UIBezierPath() + path.move(to: snapshot.point(for: CLLocationCoordinate2D(firstPoint))) + for point in points[1...] { + path.addLine(to: snapshot.point(for: CLLocationCoordinate2D(point))) + } + path.lineWidth = 2 + path.stroke() } } extension MultiLineString: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { for lineString in lineStrings { - lineString.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + lineString.quickLookDraw(in: context, snapshot: snapshot) } } } extension GEOSwift.Polygon.LinearRing: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { - lineString.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { + lineString.quickLookDraw(in: context, snapshot: snapshot) } } extension GEOSwift.Polygon: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { - let polygon = MKPolygon(polygon: self) - let renderer = MKPolygonRenderer(overlay: polygon) - renderer.lineWidth = 2 - renderer.strokeColor = UIColor.blue.withAlphaComponent(0.7) - renderer.fillColor = UIColor.cyan.withAlphaComponent(0.2) - draw(in: context, imageSize: imageSize, mapRect: mapRect, renderer: renderer) + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { + UIColor.blue.withAlphaComponent(0.7).setStroke() + UIColor.cyan.withAlphaComponent(0.2).setFill() + let path = UIBezierPath() + path.move(to: snapshot.point(for: CLLocationCoordinate2D(exterior.points.first!))) + for point in exterior.points[1...] { + path.addLine(to: snapshot.point(for: CLLocationCoordinate2D(point))) + } + path.close() + for hole in holes { + path.move(to: snapshot.point(for: CLLocationCoordinate2D(hole.points.first!))) + for point in hole.points[1...] { + path.addLine(to: snapshot.point(for: CLLocationCoordinate2D(point))) + } + path.close() + } + path.lineWidth = 2 + path.fill() + path.stroke() } } extension MultiPolygon: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { for polygon in polygons { - polygon.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + polygon.quickLookDraw(in: context, snapshot: snapshot) } } } extension GeometryCollection: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { for geometry in geometries { - geometry.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + geometry.quickLookDraw(in: context, snapshot: snapshot) } } } extension Geometry: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { switch self { case let .point(point): - point.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + point.quickLookDraw(in: context, snapshot: snapshot) case let .multiPoint(multiPoint): - multiPoint.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + multiPoint.quickLookDraw(in: context, snapshot: snapshot) case let .lineString(lineString): - lineString.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + lineString.quickLookDraw(in: context, snapshot: snapshot) case let .multiLineString(multiLineString): - multiLineString.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + multiLineString.quickLookDraw(in: context, snapshot: snapshot) case let .polygon(polygon): - polygon.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + polygon.quickLookDraw(in: context, snapshot: snapshot) case let .multiPolygon(multiPolygon): - multiPolygon.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + multiPolygon.quickLookDraw(in: context, snapshot: snapshot) case let .geometryCollection(geometryCollection): - geometryCollection.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) + geometryCollection.quickLookDraw(in: context, snapshot: snapshot) } } } extension Envelope: GEOSwiftQuickLook { - func quickLookDraw(in context: CGContext, imageSize: CGSize, mapRect: MKMapRect) { - geometry.quickLookDraw(in: context, imageSize: imageSize, mapRect: mapRect) - } -} - -// MARK: - MKMapView Snapshotting -private extension MKMapView { - /** - Take a snapshot of the map with MKMapSnapshot, which is designed to work in the background, - so we block the calling thread with a semaphore. - */ - var snapshot: UIImage? { - let options = MKMapSnapshotter.Options() - options.region = region - options.size = frame.size - var snapshotImage: UIImage? - let backgroundQueue = DispatchQueue.global(qos: .background) - let snapshotter = MKMapSnapshotter(options: options) - let semaphore = DispatchSemaphore(value: 0) - snapshotter.start(with: backgroundQueue) { snapshot, _ in - snapshotImage = snapshot?.image - semaphore.signal() - } - _ = semaphore.wait(timeout: .now() + 3) - return snapshotImage + func quickLookDraw(in context: CGContext, snapshot: MKMapSnapshotter.Snapshot) { + geometry.quickLookDraw(in: context, snapshot: snapshot) } } diff --git a/Tests/GEOSwiftMapKitTests/MapKit+Equatable.swift b/Tests/GEOSwiftMapKitTests/MapKit+Equatable.swift index 936f674..1751cee 100644 --- a/Tests/GEOSwiftMapKitTests/MapKit+Equatable.swift +++ b/Tests/GEOSwiftMapKitTests/MapKit+Equatable.swift @@ -1,41 +1,41 @@ import MapKit -extension CLLocationCoordinate2D: Equatable { +extension CLLocationCoordinate2D: @retroactive Equatable { public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool { lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude } } -extension MKCoordinateSpan: Equatable { +extension MKCoordinateSpan: @retroactive Equatable { public static func == (lhs: MKCoordinateSpan, rhs: MKCoordinateSpan) -> Bool { lhs.latitudeDelta == rhs.latitudeDelta && lhs.longitudeDelta == rhs.longitudeDelta } } -extension MKCoordinateRegion: Equatable { +extension MKCoordinateRegion: @retroactive Equatable { public static func == (lhs: MKCoordinateRegion, rhs: MKCoordinateRegion) -> Bool { lhs.center == rhs.center && lhs.span == rhs.span } } -extension MKMapPoint: Equatable { +extension MKMapPoint: @retroactive Equatable { public static func == (lhs: MKMapPoint, rhs: MKMapPoint) -> Bool { lhs.x == rhs.x && lhs.y == rhs.y } } -extension MKMapSize: Equatable { +extension MKMapSize: @retroactive Equatable { public static func == (lhs: MKMapSize, rhs: MKMapSize) -> Bool { lhs.width == rhs.width && lhs.height == rhs.height } } -extension MKMapRect: Equatable { +extension MKMapRect: @retroactive Equatable { public static func == (lhs: MKMapRect, rhs: MKMapRect) -> Bool { lhs.origin == rhs.origin && lhs.size == rhs.size From 1799a453cf3f6992a1777afde35c888f41a8f7ef Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sun, 6 Oct 2024 21:48:42 -0400 Subject: [PATCH 08/11] add tvos to quicklook --- Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift b/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift index 5206e47..b1e7483 100644 --- a/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift +++ b/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift @@ -1,5 +1,4 @@ -#if os(iOS) - +#if os(iOS) || os(tvOS) import UIKit import MapKit import GEOSwift @@ -70,7 +69,7 @@ private func makePlaygroundDescription(for g: (some GEOSwiftQuickLook)) -> Any { guard let snapshot else { return defaultReturnValue } - let format = UIGraphicsImageRendererFormat.default() + let format = UIGraphicsImageRendererFormat.preferred() format.opaque = true format.scale = snapshot.image.scale return UIGraphicsImageRenderer(size: snapshot.image.size, format: format).image { context in From 75babb8278648cee1bdf0e0f728a1003e9e286c8 Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sun, 6 Oct 2024 21:55:13 -0400 Subject: [PATCH 09/11] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dbbd67..b450ecd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ * Updates to GEOSwift 11.0.0 * Increases min Swift version to 5.9 * Increases min deployment targets for Apple platforms +* Expands QuickLook support to tvOS +* Fixes some warnings when building with Xcode 16 ## 4.0.0 From 2132b61417d88a079563ad9a8a06d7a5f0752beb Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sun, 6 Oct 2024 22:21:37 -0400 Subject: [PATCH 10/11] only swift 6 compiler knows about @retroactive --- .../GEOSwift+MapKitQuickLook.swift | 42 ++++++++++++++++++ .../MapKit+Equatable.swift | 44 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift b/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift index b1e7483..3fb043d 100644 --- a/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift +++ b/Sources/GEOSwiftMapKit/GEOSwift+MapKitQuickLook.swift @@ -3,6 +3,7 @@ import UIKit import MapKit import GEOSwift +#if compiler(>=6) extension Point: @retroactive CustomPlaygroundDisplayConvertible { public var playgroundDescription: Any { makePlaygroundDescription(for: self) } } @@ -42,6 +43,47 @@ extension Geometry: @retroactive CustomPlaygroundDisplayConvertible { extension Envelope: @retroactive CustomPlaygroundDisplayConvertible { public var playgroundDescription: Any { makePlaygroundDescription(for: self) } } +#else +extension Point: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension MultiPoint: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension LineString: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension MultiLineString: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension GEOSwift.Polygon.LinearRing: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension GEOSwift.Polygon: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension MultiPolygon: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension GeometryCollection: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension Geometry: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} + +extension Envelope: CustomPlaygroundDisplayConvertible { + public var playgroundDescription: Any { makePlaygroundDescription(for: self) } +} +#endif private func makePlaygroundDescription(for g: (some GEOSwiftQuickLook)) -> Any { let defaultReturnValue: Any = (try? g.geometry.wkt()) ?? g diff --git a/Tests/GEOSwiftMapKitTests/MapKit+Equatable.swift b/Tests/GEOSwiftMapKitTests/MapKit+Equatable.swift index 1751cee..e16588e 100644 --- a/Tests/GEOSwiftMapKitTests/MapKit+Equatable.swift +++ b/Tests/GEOSwiftMapKitTests/MapKit+Equatable.swift @@ -1,5 +1,6 @@ import MapKit +#if compiler(>=6) extension CLLocationCoordinate2D: @retroactive Equatable { public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool { lhs.latitude == rhs.latitude @@ -41,3 +42,46 @@ extension MKMapRect: @retroactive Equatable { && lhs.size == rhs.size } } +#else +extension CLLocationCoordinate2D: Equatable { + public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool { + lhs.latitude == rhs.latitude + && lhs.longitude == rhs.longitude + } +} + +extension MKCoordinateSpan: Equatable { + public static func == (lhs: MKCoordinateSpan, rhs: MKCoordinateSpan) -> Bool { + lhs.latitudeDelta == rhs.latitudeDelta + && lhs.longitudeDelta == rhs.longitudeDelta + } +} + +extension MKCoordinateRegion: Equatable { + public static func == (lhs: MKCoordinateRegion, rhs: MKCoordinateRegion) -> Bool { + lhs.center == rhs.center + && lhs.span == rhs.span + } +} + +extension MKMapPoint: Equatable { + public static func == (lhs: MKMapPoint, rhs: MKMapPoint) -> Bool { + lhs.x == rhs.x + && lhs.y == rhs.y + } +} + +extension MKMapSize: Equatable { + public static func == (lhs: MKMapSize, rhs: MKMapSize) -> Bool { + lhs.width == rhs.width + && lhs.height == rhs.height + } +} + +extension MKMapRect: Equatable { + public static func == (lhs: MKMapRect, rhs: MKMapRect) -> Bool { + lhs.origin == rhs.origin + && lhs.size == rhs.size + } +} +#endif From 6cd5675a054639d733c4edc13201d88676e752a9 Mon Sep 17 00:00:00 2001 From: Andrew Hershberger Date: Sun, 6 Oct 2024 22:27:06 -0400 Subject: [PATCH 11/11] Add some xcode 16 ci jobs --- .github/workflows/main.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0c29603..0a1c2a3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,6 +34,21 @@ jobs: strategy: matrix: include: + - name: "xcodebuild (iOS 18.0, Xcode 16.0)" + os: macos-14 + xcode-version: "16" + sdk: iphonesimulator18.0 + destination: "platform=iOS Simulator,OS=18.0,name=iPhone 16" + - name: "xcodebuild (tvOS 18.0, Xcode 16.0)" + os: macos-14 + xcode-version: "16" + sdk: appletvsimulator18.0 + destination: "platform=tvOS Simulator,OS=18.0,name=Apple TV" + - name: "xcodebuild (macOS 15.0, Xcode 16.0)" + os: macos-14 + xcode-version: "16" + sdk: macosx15.0 + destination: "platform=OS X" - name: "xcodebuild (iOS 17.5, Xcode 15.4)" os: macos-14 xcode-version: "15.4" @@ -44,7 +59,7 @@ jobs: xcode-version: "15.4" sdk: appletvsimulator17.5 destination: "platform=tvOS Simulator,OS=17.5,name=Apple TV" - - name: "xcodebuild (macOS 14.5, Xcode 15.4)" + - name: "xcodebuild (macOS 14.7, Xcode 15.4)" os: macos-14 xcode-version: "15.4" sdk: macosx14.5 @@ -70,6 +85,8 @@ jobs: include: - os: macos-14 xcode-version: "15.4" + - os: macos-14 + xcode-version: "16" steps: - uses: actions/checkout@v3 - name: Select Xcode Version