Reputation: 1144
I am trying to move the map by rotating the phone near my face. Below I have created a wrapper for ARView
and a coordinator class.
This is more or less a working option with bounds, but if you remove bounds from the map - moving with a face doesn't work. As you can understand, I don't need bounds on the map, but if you remove them - moving doesn't work. I can't think of anything for 3 days now. Can you give me an idea what I can do?
Inside the method I assign a value for MKCoordinateRegion
:
struct ARWrapper: UIViewRepresentable {
@Binding
var faceBounds: MKCoordinateRegion
func updateUIView(_ uiView: ARView, context: Context) {}
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
let faceConfig = ARFaceTrackingConfiguration()
// Set the coordinator as the session delegate
arView.session.delegate = context.coordinator
let session = arView.session
session.run(faceConfig)
return arView
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, ARSessionDelegate {
var parent: ARWrapper
init(_ parent: ARWrapper) {
self.parent = parent
}
// Implement ARSessionDelegate methods here
func session(_ session: ARSession, didUpdate frame: ARFrame) {}
func spanFrom(centerZ: Double, distanceZ: Double) -> MKCoordinateSpan {
let initial = parent.faceBounds.span
let delta = distanceZ / centerZ
let span = MKCoordinateSpan(
latitudeDelta: initial.latitudeDelta * delta,
longitudeDelta: initial.longitudeDelta * delta
)
return span
}
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
guard let faceAnchor = anchors.first as? ARFaceAnchor else {
print("Can't find Face anchor. Exit")
return
}
let centerX: Float = 0
let centerY: Float = 0
let centerZ: Float = 0 // zoom span
// Here's main calculation
let mapLocation = CLLocationCoordinate2D(latitude: 25.19745, longitude: 55.27417)
let translation = simd_make_float3(faceAnchor.transform.columns.3)
let distanceX = translation.x * 100
let distanceY = translation.y * 100
let distanceZ = (translation.z * 100) * -1 // zoom span
// Horizontal
let deltaX = (centerX - distanceX) * 300
let calcCenterX = mapLocation.shift(byDistance: Double(deltaX), azimuth: Double.pi / 2)
// Vertical
let deltaY = (centerY - distanceY) * 500
parent.faceBounds.center = calcCenterX.shift(byDistance: Double(deltaY), azimuth: .zero)
let region = MKCoordinateRegion(
center: parent.faceBounds.center,
span: .init()
)
parent.faceBounds = region
}
}
}
Here's a .shift(byDistance:)
method:
extension CLLocationCoordinate2D {
/// Get coordinate moved from current to `distanceMeters` meters with azimuth `azimuth` [0, Double.pi)
///
/// - Parameters:
/// - distanceMeters: the distance in meters
/// - azimuth: the azimuth (bearing)
/// - Returns: new coordinate
func shift(byDistance distanceMeters: Double, azimuth: Double) -> CLLocationCoordinate2D {
let bearing = azimuth
let origin = self
let distRadians = distanceMeters / 6_372_797.6 // earth radius in meters
let lat1 = origin.latitude * Double.pi / 180
let lon1 = origin.longitude * Double.pi / 180
let lat2 = asin(sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(bearing))
let lon2 =
lon1
+ atan2(sin(bearing) * sin(distRadians) * cos(lat1), cos(distRadians) - sin(lat1) * sin(lat2))
return CLLocationCoordinate2D(
latitude: lat2 * 180 / Double.pi, longitude: lon2 * 180 / Double.pi)
}
}
Create map via MapCameraPosition
:
@State
private var defaultCameraPosition: MapCameraPosition = .region(
.init(center: .unitedEmirates, span: .init(latitudeDelta: 3000, longitudeDelta: 3000)))
@State
private
var faceTrackingBounds: MKCoordinateRegion = .init(
center: .unitedEmirates, latitudinalMeters: 20000, longitudinalMeters: 2000)
var body: some View {
ZStack {
ARWrapper(faceBounds: $mapData.faceTrackingBounds)
Map(
position: $mapData.defaultCameraPosition,
// if we remove bounds — nothing work
bounds: .init(
centerCoordinateBounds: mapData.faceTrackingBounds,
minimumDistance: 50,
maximumDistance: 100000
)
)
}
.onAppear {
mapData.defaultCameraPosition = .region(
.init(center: .unitedEmirates, span: mapData.faceTrackingBounds.span))
}
}
Upvotes: 0
Views: 40