Frank Lan
Frank Lan

Reputation: 123

ARGeoTrackingStatus and camera tracking state can't display

I'm trying to display geotracking status and camera tracking state on UI. I've tried func session(_ session: ARSession, didUpdate frame: ARFrame) and func session(_ session: ARSession, didChange geoTrackingStatus: ARGeoTrackingStatus) to obtain geotracking state, but it showed nothing. I also tried func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) to display camera tracking state, but it showed nothing neither. Could someone help me out? Thanks.

ContentView

import SwiftUI
import ARKit
import RealityKit

struct ContentView: View {
    @State var viewModel = ARViewContainer.ViewModel()
    
    var body: some View {
        ZStack {
            ARViewContainer(viewModel: $viewModel)
                .ignoresSafeArea(.all)
            VStack(alignment: .leading) {
                Text("Camera State: \(viewModel.cameraTrackingStatus)")
                Text("GeoTracking State: \(viewModel.geoTrackingStatus)")
                Text("Accuracy: \(viewModel.accuracy)")
            }
            .font(.system(size: 20))
            .position(x: 92, y: 36)
        }
    }
}


struct ARViewContainer: UIViewRepresentable {
    
    struct ViewModel {
        var notAvailable = false
        var geoTrackingStatus = ""
        var cameraTrackingStatus = ""
        var accuracy = ""
    }
    
    @Binding var viewModel: ViewModel
    

    let arView = ARView(frame: .zero)
    
    func makeUIView(context: Context) -> ARView {
        if ARGeoTrackingConfiguration.isSupported {
            ARGeoTrackingConfiguration.checkAvailability { available, error in
                if !available {
                    viewModel.notAvailable = true
                    print("GeoTracking is not available at your location")
                }
            }
        } else {
            print("Your Decive support ARGeoTracking")
        }
        
        let config = ARGeoTrackingConfiguration()
        arView.automaticallyConfigureSession = false
        arView.session.run(config)
        context.coordinator.addCoaching()
        return arView
    }
    
    func makeCoordinator() -> Coordiantor {
        Coordiantor(self)
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Coordinator

import ARKit
import RealityKit

class Coordiantor: NSObject, ARSessionDelegate, ARCoachingOverlayViewDelegate {
    
    var parent: ARViewContainer
    
    init(_ parent: ARViewContainer) {
        self.parent = parent
    }
    
    func addCoaching() {
        let coachingOverlay = ARCoachingOverlayView()
        coachingOverlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        coachingOverlay.goal = .geoTracking
        coachingOverlay.session = parent.arView.session
        coachingOverlay.delegate = self
        parent.arView.addSubview(coachingOverlay)
    }
    
    public func coachingOverlayViewDidRequestSessionReset(_ coachingOverlayView: ARCoachingOverlayView) {
        let config = ARGeoTrackingConfiguration()
        parent.arView.session.run(config, options: [.resetTracking, .removeExistingAnchors])
    }
    
    
    func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
        parent.viewModel.cameraTrackingStatus = camera.trackingState.description
    }
    
    func session(_ session: ARSession, didChange geoTrackingStatus: ARGeoTrackingStatus) {
        switch geoTrackingStatus.state {
            
        case .notAvailable:
            parent.viewModel.geoTrackingStatus = "Not Available"
        case .initializing:
            switch geoTrackingStatus.stateReason {
                
            case .none:
                parent.viewModel.geoTrackingStatus = "No issue reported"
            case .notAvailableAtLocation:
                parent.viewModel.geoTrackingStatus = "Geotracking not available at this location"
            case .needLocationPermissions:
                parent.viewModel.geoTrackingStatus = "Geotracking requires location permission"
            case .worldTrackingUnstable:
                parent.viewModel.geoTrackingStatus = "World tracking is not stable"
            case .waitingForLocation:
                parent.viewModel.geoTrackingStatus = "ARKit waiting for location"
            case .waitingForAvailabilityCheck:
                parent.viewModel.geoTrackingStatus = "ARKit waiting for availablity check"
            case .geoDataNotLoaded:
                parent.viewModel.geoTrackingStatus = "Geo data not loaded, please check network connection"
            case .devicePointedTooLow:
                parent.viewModel.geoTrackingStatus = "Camera pointed too low"
            case .visualLocalizationFailed:
                parent.viewModel.geoTrackingStatus = "Visual localization failed"
            @unknown default:
                break
            }
        case .localizing:
            switch geoTrackingStatus.stateReason {
                
            case .none:
                parent.viewModel.geoTrackingStatus = "No issue reported"
            case .notAvailableAtLocation:
                parent.viewModel.geoTrackingStatus = "Geotracking not available at this location"
            case .needLocationPermissions:
                parent.viewModel.geoTrackingStatus = "Geotracking requires location permission"
            case .worldTrackingUnstable:
                parent.viewModel.geoTrackingStatus = "World tracking is not stable"
            case .waitingForLocation:
                parent.viewModel.geoTrackingStatus = "ARKit waiting for location"
            case .waitingForAvailabilityCheck:
                parent.viewModel.geoTrackingStatus = "ARKit waiting for availablity check"
            case .geoDataNotLoaded:
                parent.viewModel.geoTrackingStatus = "Geo data not loaded, please check network connection"
            case .devicePointedTooLow:
                parent.viewModel.geoTrackingStatus = "Camera pointed too low"
            case .visualLocalizationFailed:
                parent.viewModel.geoTrackingStatus = "Visual localization failed"
            @unknown default:
                break
            }
        case .localized:
            switch geoTrackingStatus.accuracy {
                
            case .undetermined:
                parent.viewModel.accuracy = "Undetermined"
            case .low:
                parent.viewModel.accuracy = "Low"
            case .medium:
                parent.viewModel.accuracy = "Medium"
            case .high:
                parent.viewModel.accuracy = "High"
            @unknown default:
                break
            }
        @unknown default:
            break
        }
    }
    
}

    
extension ARCamera.TrackingState: CustomStringConvertible {
    public var description: String {
        switch self {
        case .notAvailable:
            return "Not Available"
        case .limited(.initializing):
            return "Limited-Initializing"
        case .limited(.excessiveMotion):
            return "Limited-Excessive motion"
        case .limited(.insufficientFeatures):
            return "Limited-Insufficient image input"
        case .limited(.relocalizing):
            return "Relocalizing"
        case .normal:
            return "Normal"
        case .limited:
            return "Unspecified Reason"
        }
    }
}

Upvotes: 0

Views: 206

Answers (1)

Luan
Luan

Reputation: 11

I think you forgot to assign parent.arView.session.delegate = self in your coordinator so the following function is never called

func session(_ session: ARSession, didChange geoTrackingStatus: ARGeoTrackingStatus) {
}

Upvotes: 1

Related Questions