Skip to content

Commit 965639d

Browse files
authored
Merge pull request #230 from TaskarCenterAtUW/feature-bbox-annotations-overlay
Bbox annotations overlay
2 parents a09585d + 4ba449d commit 965639d

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

GoInfoGame/GoInfoGame.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@
212212
FA8C74D62C5C0DBA00D28220 /* LongFormViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA8C74D52C5C0DBA00D28220 /* LongFormViewModel.swift */; };
213213
FA8C74D82C60E95100D28220 /* PosmLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA8C74D72C60E95100D28220 /* PosmLogin.swift */; };
214214
FA9AEC002D5CACB6006A3A31 /* UserNodesHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9AEBFF2D5CACB3006A3A31 /* UserNodesHelper.swift */; };
215+
FA9F381C2DB2FF4B00D7AABF /* ShadowOverlayRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9F381B2DB2FF3E00D7AABF /* ShadowOverlayRenderer.swift */; };
215216
FA9FE2D82BAC75390036F618 /* OAuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9FE2D72BAC75390036F618 /* OAuthViewController.swift */; };
216217
FABF3CF42B7419BB0080EAC9 /* LocationManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FABF3CF32B7419BB0080EAC9 /* LocationManagerDelegate.swift */; };
217218
FABF3CF82B822F120080EAC9 /* CustomSureAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = FABF3CF72B822F120080EAC9 /* CustomSureAlert.swift */; };
@@ -533,6 +534,7 @@
533534
FA8C74D52C5C0DBA00D28220 /* LongFormViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongFormViewModel.swift; sourceTree = "<group>"; };
534535
FA8C74D72C60E95100D28220 /* PosmLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PosmLogin.swift; sourceTree = "<group>"; };
535536
FA9AEBFF2D5CACB3006A3A31 /* UserNodesHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNodesHelper.swift; sourceTree = "<group>"; };
537+
FA9F381B2DB2FF3E00D7AABF /* ShadowOverlayRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowOverlayRenderer.swift; sourceTree = "<group>"; };
536538
FA9FE2D72BAC75390036F618 /* OAuthViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthViewController.swift; sourceTree = "<group>"; };
537539
FABF3CF32B7419BB0080EAC9 /* LocationManagerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManagerDelegate.swift; sourceTree = "<group>"; };
538540
FABF3CF72B822F120080EAC9 /* CustomSureAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSureAlert.swift; sourceTree = "<group>"; };
@@ -813,6 +815,7 @@
813815
970D5BD22B67638400C20BE7 /* MapViewModel.swift */,
814816
A495DF2C2B6A190400478E44 /* CustomMapView.swift */,
815817
971902102B983EFC009B3270 /* CustomMap.swift */,
818+
FA9F381B2DB2FF3E00D7AABF /* ShadowOverlayRenderer.swift */,
816819
FA50718B2D54E08800CE9798 /* AddFeatureView.swift */,
817820
FA50718F2D5B31CC00CE9798 /* CreateNoteView.swift */,
818821
FA51484D2D76ED6300C0D35B /* NotesViewModel.swift */,
@@ -1856,10 +1859,14 @@
18561859
inputFileListPaths = (
18571860
"${PODS_ROOT}/Target Support Files/Pods-GoInfoGame/Pods-GoInfoGame-frameworks-${CONFIGURATION}-input-files.xcfilelist",
18581861
);
1862+
inputPaths = (
1863+
);
18591864
name = "[CP] Embed Pods Frameworks";
18601865
outputFileListPaths = (
18611866
"${PODS_ROOT}/Target Support Files/Pods-GoInfoGame/Pods-GoInfoGame-frameworks-${CONFIGURATION}-output-files.xcfilelist",
18621867
);
1868+
outputPaths = (
1869+
);
18631870
runOnlyForDeploymentPostprocessing = 0;
18641871
shellPath = /bin/sh;
18651872
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-GoInfoGame/Pods-GoInfoGame-frameworks.sh\"\n";
@@ -1939,10 +1946,14 @@
19391946
inputFileListPaths = (
19401947
"${PODS_ROOT}/Target Support Files/Pods-GoInfoGame-GoInfoGameUITests/Pods-GoInfoGame-GoInfoGameUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
19411948
);
1949+
inputPaths = (
1950+
);
19421951
name = "[CP] Embed Pods Frameworks";
19431952
outputFileListPaths = (
19441953
"${PODS_ROOT}/Target Support Files/Pods-GoInfoGame-GoInfoGameUITests/Pods-GoInfoGame-GoInfoGameUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
19451954
);
1955+
outputPaths = (
1956+
);
19461957
runOnlyForDeploymentPostprocessing = 0;
19471958
shellPath = /bin/sh;
19481959
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-GoInfoGame-GoInfoGameUITests/Pods-GoInfoGame-GoInfoGameUITests-frameworks.sh\"\n";
@@ -2108,6 +2119,7 @@
21082119
973FC03A2B59364F00878269 /* TactilePavingStepsForm.swift in Sources */,
21092120
FAFDA2142C7351CB00ECEAE9 /* APIError.swift in Sources */,
21102121
973FC0332B592BFE00878269 /* StairNumber.swift in Sources */,
2122+
FA9F381C2DB2FF4B00D7AABF /* ShadowOverlayRenderer.swift in Sources */,
21112123
059D47332B2C83BA000987FA /* Highway.swift in Sources */,
21122124
973FC0012B46CD5D00878269 /* QuestsListUIView.swift in Sources */,
21132125
973FC01F2B50DE7E00878269 /* ImageGridItemView.swift in Sources */,

GoInfoGame/GoInfoGame/UI/Map/CustomMap.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,14 @@ struct CustomMap: UIViewRepresentable {
8484

8585
// Remove existing overlays
8686
mapView.overlays.forEach { mapView.removeOverlay($0) }
87-
87+
88+
// Add shadow overlay with rectangular cutouts
89+
if mapView.overlays.first(where: { $0 is ShadowOverlay }) == nil {
90+
let overlay = ShadowOverlay(annotations: mapView.annotations)
91+
mapView.addOverlay(overlay)
92+
}
93+
94+
8895
// Re-add overlays based on selection
8996
if useBingMaps {
9097
let tileOverlay = BingTileOverlay()
@@ -183,6 +190,10 @@ struct CustomMap: UIViewRepresentable {
183190
return renderer
184191
}
185192

193+
if let shadowOverlay = overlay as? ShadowOverlay {
194+
return ShadowOverlayRenderer(overlay: shadowOverlay)
195+
}
196+
186197
if let tileOverlay = overlay as? MKTileOverlay {
187198
return MKTileOverlayRenderer(tileOverlay: tileOverlay)
188199
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//
2+
// ShadowOverlayRenderer.swift
3+
// GoInfoGame
4+
//
5+
// Created by Achyut Kumar M on 19/04/25.
6+
//
7+
8+
import MapKit
9+
import UIKit
10+
11+
12+
class ShadowOverlayRenderer: MKOverlayRenderer {
13+
override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
14+
guard let shadowOverlay = overlay as? ShadowOverlay else { return }
15+
16+
let fullRect = self.rect(for: shadowOverlay.boundingMapRect)
17+
context.setFillColor(CGColor(red: 0, green: 0, blue: 0, alpha: 0.5))
18+
context.fill(fullRect)
19+
20+
context.setBlendMode(.clear)
21+
context.setAllowsAntialiasing(false)
22+
context.setShouldAntialias(false)
23+
24+
for mapRect in shadowOverlay.annotationRects {
25+
let cutout = self.rect(for: mapRect).integral
26+
context.fill(cutout)
27+
}
28+
29+
context.setBlendMode(.normal)
30+
}
31+
}
32+
33+
class ShadowOverlay: NSObject, MKOverlay {
34+
let coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 0, longitude: 0)
35+
let boundingMapRect: MKMapRect = MKMapRect.world
36+
let annotationRects: [MKMapRect]
37+
38+
init(annotations: [MKAnnotation]) {
39+
self.annotationRects = annotations.map { annotation in
40+
let center = MKMapPoint(annotation.coordinate)
41+
let width = MKMapPointsPerMeterAtLatitude(annotation.coordinate.latitude) * 500 // 500m box
42+
return MKMapRect(
43+
origin: MKMapPoint(x: center.x - width / 2, y: center.y - width / 2),
44+
size: MKMapSize(width: width, height: width)
45+
)
46+
}
47+
}
48+
}
49+
50+
51+
52+
extension MKCoordinateRegion {
53+
func corners() -> [CLLocationCoordinate2D] {
54+
let latMin = center.latitude - span.latitudeDelta / 2
55+
let latMax = center.latitude + span.latitudeDelta / 2
56+
let lonMin = center.longitude - span.longitudeDelta / 2
57+
let lonMax = center.longitude + span.longitudeDelta / 2
58+
return [
59+
CLLocationCoordinate2D(latitude: latMin, longitude: lonMin),
60+
CLLocationCoordinate2D(latitude: latMin, longitude: lonMax),
61+
CLLocationCoordinate2D(latitude: latMax, longitude: lonMax),
62+
CLLocationCoordinate2D(latitude: latMax, longitude: lonMin)
63+
]
64+
}
65+
}
66+

0 commit comments

Comments
 (0)