7.4 C
New York
Wednesday, December 18, 2024

ios – Why is my ObjectCaptureSession crashing once I name proceedToNextScanPass()?


I’m making an attempt to construct an app that makes use of the ObjectCapture API, however I can not get previous this bug. The app crashes 9/10 instances once I name proceedToNextScanPass(), if you happen to might please recommend some attainable options it could be appreciated.

I am following the Apple Developer Pattern Venture just about right down to a tee so I am unsure what is going on mistaken. There’s additionally no solution to throw an error when utilizing proceedToNextScanPass() so it is troublesome to debug.

Right here is my AppDataModel, like within the pattern mission.

@MainActor
@Observable
class AppDataModel: ObservableObject {
    static let occasion = AppDataModel()

    enum ModelState {
        case notSet
        case prepared
        case capturing
        case prepareToReconstruct
        case reconstructing
        case viewing
        case accomplished
        case failed
    }

    var state: ModelState = .notSet {
        didSet {
            performStateTransition(from: oldValue, to: state)
        }
    }
    var captureFolderManager: CaptureFolderManager?
    var objectCaptureSession: ObjectCaptureSession?
    var photogrammetrySession: PhotogrammetrySession?

    var orbit: Int = 0

    personal init() {
        state = .prepared
    }

    func endCapture() {
        state = .accomplished
    }

    func removeCaptureFolder() {
        guard let url = captureFolderManager?.captureFolder else { return }
        attempt? FileManager.default.removeItem(at: url)
    }

    personal func performStateTransition(from fromState: ModelState, to toState: ModelState) {
        if fromState == toState { return }

        swap toState {
        case .prepared:
            do {
                attempt startNewCapture()
            } catch {
                print("Beginning new seize failed!")
            }
        case .prepareToReconstruct:
            objectCaptureSession = nil
            do {
                attempt startReconstruction()
            } catch {
                print("Reconstruction failed!")
            }
        default:
            break
        }
    }

    personal func startReconstruction() throws {
        var configuration = PhotogrammetrySession.Configuration()

        guard let captureFolderManager else {
            preconditionFailure("CaptureFolderManager unexpectedly nil!")
        }

        configuration.checkpointDirectory = captureFolderManager.checkpointFolder
        photogrammetrySession = attempt PhotogrammetrySession(
            enter: captureFolderManager.imagesFolder,
            configuration: configuration
        )

        state = .reconstructing
    }
}

extension AppDataModel {
    personal func startNewCapture() throws {
        captureFolderManager = attempt CaptureFolderManager()
        objectCaptureSession = ObjectCaptureSession()

        guard let captureFolderManager, let session = objectCaptureSession else {
            throw NSError(area: "AppDataModel", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed to initialize session or folder manager"])
        }

        var configuration = ObjectCaptureSession.Configuration()
        configuration.isOverCaptureEnabled = true
        configuration.checkpointDirectory = captureFolderManager.checkpointFolder
        session.begin(imagesDirectory: captureFolderManager.imagesFolder, configuration: configuration)

        state = .capturing
    }

    personal func reset() {
        objectCaptureSession = nil
        captureFolderManager = nil
        state = .prepared
    }
}

In addition to the principle view the place I am making the decision to subsequent scan cross

struct CapturePrimaryView: View {
    @Atmosphere(AppDataModel.self) var appModel
    var session: ObjectCaptureSession
    @State personal var currentOrbit = 1

    var physique: some View {
        ZStack {
            if session.userCompletedScanPass {
                if currentOrbit <= 2 {
                    Button("Proceed") {
                        proceedToNextScanPass()
                    }
                    .buttonStyle(.borderedProminent)
                    .tint(.yellow)
                } else if currentOrbit == 3 {
                    Button("End") {
                        completeCapture()
                    }
                    .buttonStyle(.borderedProminent)
                }
            } else {
                ObjectCaptureView(session: session, cameraFeedOverlay: { GradientBackground() })
                    .hideObjectReticle(false)
                    .transition(.opacity)
            }
        }
        .onAppear {
            UIApplication.shared.isIdleTimerDisabled = true
        }
        .onChange(of: session.state) { _, newValue in
            print("Session State Modified: (newValue)")
        }
        .id(session.id)
    }

    personal func proceedToNextScanPass() {
        guard session.state == .capturing else {
            print("Error: Can't start a brand new scan cross as a result of the session shouldn't be in capturing state. Present state: (session.state)")
            return
        }

        session.beginNewScanPass()
        currentOrbit += 1
        print("New scan cross began efficiently. Present orbit: (currentOrbit)")
    }

    personal func completeCapture() {
        appModel.state = .accomplished
    }
}

And my foremost ContentView

struct ContentView: View {
    @Atmosphere(AppDataModel.self) var appModel
    @State personal var hasDetectionFailed = false
    @State personal var showReconstructionView = false

    var physique: some View {
        VStack {
            if appModel.state == .capturing {
                if let session = appModel.objectCaptureSession {
                    CapturePrimaryView(session: session)
                        .overlay {
                            Spacer()
                            
                            CaptureButton(session: session, hasDetectionFailed: $hasDetectionFailed)
                        }
                }
            } else {
                Textual content("Clean")
            }
        }
        .onAppear(carry out: {
            UIApplication.shared.isIdleTimerDisabled = true
        })
        .onDisappear(carry out: {
            UIApplication.shared.isIdleTimerDisabled = false
        })
        .sheet(isPresented: $showReconstructionView) {
            if let _ = appModel.captureFolderManager {
                Textual content("Reconstruct")
            }
        }
    }
}

@MainActor
personal struct CaptureButton: View {
    @Atmosphere(AppDataModel.self) var appModel
    var session: ObjectCaptureSession
    @Binding var hasDetectionFailed: Bool
    @State personal var present = true
    
    var physique: some View {
        ZStack {
            if present {
                Button("Proceed") {
                    performAction()
                }
                .daring()
                .buttonStyle(.borderedProminent)
            }
        }
    }
    
    personal func performAction() {
        if session.state == .prepared {
            hasDetectionFailed = !(session.startDetecting())
        } else if case .detecting = session.state {
            session.startCapturing()
            present = false
        }
    }
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles