Como criar e localizar âncoras usando âncoras espaciais Azure em Swift

As Âncoras Espaciais Azure permitem-lhe partilhar âncoras no mundo entre diferentes dispositivos. Apoia vários ambientes de desenvolvimento diferentes. Neste artigo, vamos mergulhar em como usar o Azure Spatial Anchors SDK, em Swift, para:

  • Configurar e gerir corretamente uma sessão de Âncoras Espaciais Azure.
  • Crie e desemote propriedades nas âncoras locais.
  • Carreguem-nos para a nuvem.
  • Localize e elimine as âncoras espaciais em nuvem.

Pré-requisitos

Para completar este guia, certifique-se de que tem:

Plataforma Cross

Inicializar a sessão

O principal ponto de entrada para o SDK é a classe que representa a sua sessão. Normalmente você vai declarar um campo na classe que gere a sua visão e sessão de AR nativa.

Saiba mais sobre a classe ASACloudSpatialAnchorSession .

    var _cloudSession : ASACloudSpatialAnchorSession? = nil
    // In your view handler
    _cloudSession = ASACloudSpatialAnchorSession()

Configurar autenticação

Para aceder ao serviço, precisa de fornecer uma chave de conta, um token de acesso ou um token Azure Ative Directory. Pode também ler mais sobre isso na página do conceito de Autenticação.

Chaves de conta

As Chaves de Conta são uma credencial que permite que a sua aplicação autente com o serviço Azure Spatial Anchors. O objetivo pretendido das Chaves de Conta é ajudá-lo a começar rapidamente. Especialmente durante a fase de desenvolvimento da integração da sua aplicação com âncoras espaciais Azure. Como tal, pode utilizar as Chaves de Conta incorporando-as nas aplicações do seu cliente durante o desenvolvimento. À medida que progride para além do desenvolvimento, é altamente recomendado passar para um mecanismo de autenticação que seja de nível de produção, suportado por Access Tokens ou autenticação do utilizador do Azure Ative Directory. Para obter uma Chave de Conta para o desenvolvimento, visite a sua conta Azure Spatial Anchors e navegue no separador "Chaves".

Saiba mais sobre a classe ASASessionConfiguration .

    _cloudSession!.configuration.accountKey = "MyAccountKey"

Tokens de Acesso

Os Tokens de acesso são um método mais robusto para autenticar com âncoras espaciais Azure. Especialmente quando prepara a sua candidatura para uma implantação de produção. O resumo desta abordagem é criar um serviço de back-end com o qual a sua aplicação do cliente possa autenticar de forma segura. O seu serviço back-end interfaces com a AAD em tempo de execução e com o Serviço De Token Seguro de Âncoras Espaciais Azure para solicitar um Token de acesso. Este token é então entregue à aplicação do cliente e usado no SDK para autenticar com âncoras espaciais Azure.

    _cloudSession!.configuration.accessToken = "MyAccessToken"

Se um token de acesso não estiver definido, você deve lidar com o TokenRequired evento, ou implementar o tokenRequired método no protocolo delegado.

Pode lidar com o evento de forma sincronizada, definindo a propriedade nos argumentos do evento.

Saiba mais sobre o método do protocolo tokenRequired .

    internal func tokenRequired(_ cloudSession:ASACloudSpatialAnchorSession!, _ args:ASATokenRequiredEventArgs!) {
        args.accessToken = "MyAccessToken"
    }

Se precisar de executar trabalhos assíncronos no seu manipulador, pode adiar a definição do token solicitando um deferral objeto e, em seguida, completando-o, como no exemplo seguinte.

    internal func tokenRequired(_ cloudSession:ASACloudSpatialAnchorSession!, _ args:ASATokenRequiredEventArgs!) {
        let deferral = args.getDeferral()
        myGetTokenAsync( withCompletionHandler: { (myToken: String?) in
            if (myToken != nil) {
                args.accessToken = myToken
            }
            deferral?.complete()
        })
    }

Autenticação do Azure Active Directory

A Azure Spatial Anchors também permite que as aplicações autensem com tokens de Azure AD (Ative Directory). Por exemplo, pode utilizar Azure AD fichas para integrar com âncoras espaciais Azure. Se uma Enterprise mantiver os utilizadores em Azure AD, pode fornecer um token Azure AD de utilizador no Azure Spatial Anchors SDK. Ao fazê-lo, permite-lhe autenticar diretamente o serviço Azure Spatial Anchors para uma conta que faz parte do mesmo Azure AD inquilino.

    _cloudSession!.configuration.authenticationToken = "MyAuthenticationToken"

Tal como acontece com os tokens de acesso, se um Azure AD token não estiver definido, você deve lidar com o evento TokenRequired, ou implementar o método tokenRequired no protocolo delegado.

Pode lidar com o evento de forma sincronizada, definindo a propriedade nos argumentos do evento.

    internal func tokenRequired(_ cloudSession:ASACloudSpatialAnchorSession!, _ args:ASATokenRequiredEventArgs!) {
        args.authenticationToken = "MyAuthenticationToken"
    }

Se precisar de executar trabalhos assíncronos no seu manipulador, pode adiar a definição do token solicitando um deferral objeto e, em seguida, completando-o, como no exemplo seguinte.

    internal func tokenRequired(_ cloudSession:ASACloudSpatialAnchorSession!, _ args:ASATokenRequiredEventArgs!) {
        let deferral = args.getDeferral()
        myGetTokenAsync( withCompletionHandler: { (myToken: String?) in
            if (myToken != nil) {
                args.authenticationToken = myToken
            }
            deferral?.complete()
        })
    }

Criação da biblioteca

Start() Invocar para permitir a sua sessão processar dados ambientais.

Para lidar com os eventos levantados pela sua sessão, desajei a delegate propriedade da sua sessão num objeto, como a sua vista. Este objeto deve implementar o SSCCloudSpatialAnchorSessionDelegate protocolo.

Saiba mais sobre o método de início .

    _cloudSession!.session = self.sceneView.session;
    _cloudSession!.delegate = self;
    _cloudSession!.start()

Fornecer quadros para a sessão

A sessão de âncora espacial funciona mapeando o espaço em torno do utilizador. Ao fazê-lo, ajuda a determinar onde estão as âncoras. As plataformas móveis (iOS & Android) exigem uma chamada nativa para o feed da câmara para obter quadros da biblioteca AR da sua plataforma. Em contraste, o HoloLens está constantemente a digitalizar o ambiente, por isso não há necessidade de uma chamada específica como nas plataformas móveis.

Saiba mais sobre o método processFrame .

    _cloudSession?.processFrame(self.sceneView.session.currentFrame)

Fornecer feedback ao utilizador

Pode escrever código para lidar com o evento atualizado da sessão. Este evento dispara sempre que a sessão melhora a sua compreensão do que o rodeia. Ao fazê-lo, permite-lhe:

  • Utilize a UserFeedback classe para fornecer feedback ao utilizador à medida que o dispositivo se move e a sessão atualiza a sua compreensão ambiental. Para tal,
  • Determina em que ponto há dados espaciais suficientes para criar âncoras espaciais. Determina-se isto com um ou ReadyForCreateProgress outro RecommendedForCreateProgress. Uma vez acima de ReadyForCreateProgress 1, temos dados suficientes para salvar uma âncora espacial em nuvem, embora recomendemos que espere até RecommendedForCreateProgress que seja acima de 1 para fazê-lo.

Saiba mais sobre o método do protocolo da sessão .

    internal func sessionUpdated(_ cloudSession:ASACloudSpatialAnchorSession!, _ args:ASASessionUpdatedEventArgs!) {
        let status = args.status!
        if (status.userFeedback.isEmpty) {
            return
        }
        _feedback = "Feedback: \(FeedbackToString(userFeedback:status.userFeedback)) - Recommend Create=\(status.recommendedForCreateProgress * 100)"
    }

Criar uma âncora espacial em nuvem

Para criar uma âncora espacial em nuvem, primeiro cria-se uma âncora no sistema AR da sua plataforma e, em seguida, cria-se uma contraparte em nuvem. Usas o CreateAnchorAsync() método.

Saiba mais sobre a classe ASACloudSpatialAnchor .

    // Create a local anchor, perhaps by hit-testing and creating an ARAnchor
    var localAnchor : ARAnchor? = nil
    let hits = self.sceneView.session.currentFrame?.hitTest(CGPoint(x:0.5, y:0.5), types: ARHitTestResult.ResultType.estimatedHorizontalPlane)
    if (hits!.count == 0) return
    // The hitTest method sorts the resulting list by increasing distance from the camera
    // The first hit result will usually be the most relevant when responding to user input
    localAnchor = ARAnchor(transform:hits![0].worldTransform)
    self.sceneView.session.add(anchor: _localAnchor!)

    // If the user is placing some application content in their environment,
    // you might show content at this anchor for a while, then save when
    // the user confirms placement.
    var cloudAnchor : ASACloudSpatialAnchor? = nil
    cloudAnchor = ASACloudSpatialAnchor()
    cloudAnchor!.localAnchor = localAnchor
    _cloudSession?.createAnchor(cloudAnchor!, withCompletionHandler: { (error: Error?) in
        if (error != nil) {
            _feedback = "Save Failed:\(error!.localizedDescription)"
            return
        }
        _feedback = "Created a cloud anchor with ID=\(cloudAnchor!.identifier!)"
    })

Como descrito anteriormente, você precisa de dados ambientais suficientes capturados antes de tentar criar uma nova âncora espacial em nuvem. Isso significa que ReadyForCreateProgress tem de ser acima de 1, embora recomendemos que espere até RecommendedForCreateProgress que seja superior a 1 para o fazer.

Saiba mais sobre o método getStatusWithCompletionHandler .

    _cloudSession?.getStatusWithCompletionHandler( { (value:ASASessionStatus, error:Error?) in
        if (error != nil) {
            _feedback = "Session status error:\(error!.localizedDescription)"
            return
        }
        if (value!.recommendedForCreateProgress <> 1.0) {
            return
        }
        // Issue the creation request ...
    })

Definir as propriedades

Pode optar por adicionar algumas propriedades ao guardar as suas âncoras espaciais em nuvem. Como o tipo de objeto que está a ser guardado, ou propriedades básicas como se deve ser ativado para interação. Fazê-lo pode ser útil após a descoberta: pode imediatamente tornar o objeto para o utilizador, por exemplo, uma moldura com conteúdo em branco. Em seguida, um download diferente em segundo plano obtém detalhes adicionais do estado, por exemplo, a imagem para exibir no quadro.

Saiba mais sobre a propriedade appProperties .

    var cloudAnchor : ASACloudSpatialAnchor? = nil
    cloudAnchor = ASACloudSpatialAnchor()
    cloudAnchor!.localAnchor = localAnchor
    cloudAnchor!.appProperties = [ "model-type" : "frame", "label" : "my latest picture" ]
    _cloudSession?.createAnchor(cloudAnchor!, withCompletionHandler: { (error: Error?) in
        // ...
    })

Atualizar propriedades

Para atualizar as propriedades de uma âncora, utilize o UpdateAnchorProperties() método. Se dois ou mais dispositivos tentarem atualizar propriedades para a mesma âncora ao mesmo tempo, usamos um modelo de concordância otimista. O que significa que a primeira escrita vai ganhar. Todas as outras escritas terão um erro de "Concurrency": seria necessária uma atualização das propriedades antes de tentar novamente.

Saiba mais sobre o método de atualizaçãoAnchorProperties .

    var anchor : ASACloudSpatialAnchor? = /* locate your anchor */;
    anchor!.appProperties["last-user-access"] = "just now"
    _cloudSession?.updateAnchorProperties(anchor!, withCompletionHandler: { (error:Error?) in
        if (error != nil) {
            _feedback = "Updating Properties Failed:\(error!.localizedDescription)"
        }
    })

Não é possível atualizar a localização de uma âncora uma vez criada no serviço - tem de criar uma nova âncora e apagar a antiga para rastrear uma nova posição.

Se não precisar de localizar uma âncora para atualizar as suas propriedades, pode utilizar o GetAnchorPropertiesAsync() método, que devolve um CloudSpatialAnchor objeto com propriedades.

Saiba mais sobre o método getAnchorProperties .

    _cloudSession?.getAnchorProperties("anchorId", withCompletionHandler: { (anchor:SCCCloudSpatialAnchor?, error:Error?) in
        if (error != nil) {
            _feedback = "Getting Properties Failed:\(error!.localizedDescription)"
        }
        if (anchor != nil) {
            anchor!.appProperties["last-user-access"] = "just now"
            _cloudSession?.updateAnchorProperties(anchor!, withCompletionHandler: { (error:Error?) in
                // ...
            })
        }
    })

Definir expiração

Também é possível configurar a sua âncora para expirar automaticamente numa determinada data no futuro. Quando uma âncora expirar, deixará de ser localizada ou atualizada. A expiração só pode ser definida quando a âncora é criada, antes de guardá-la para a nuvem. Atualizar a expiração depois não é possível. Se não for definida qualquer expiração durante a criação da âncora, a âncora só expirará quando eliminada manualmente.

Saiba mais sobre a propriedade de validade .

    let secondsInAWeek = 60.0 * 60.0 * 24.0 * 7.0
    let oneWeekFromNow = Date(timeIntervalSinceNow: secondsInAWeek)
    cloudAnchor!.expiration = oneWeekFromNow

Localize uma âncora espacial em nuvem

Ser capaz de localizar uma âncora espacial de nuvem previamente salva é uma das principais razões para a utilização de Âncoras Espaciais Azure. Para isto, estamos a usar "Observadores". Só pode utilizar um Observador de cada vez; vários Observadores não são suportados. Existem várias maneiras diferentes (também conhecidas como Estratégias de Localização de Âncora) um Observador pode localizar uma âncora espacial em nuvem. Podes usar uma estratégia num observador de cada vez.

  • Localize as âncoras por identificador.
  • Localizar âncoras ligadas a uma âncora previamente localizada. Pode aprender sobre relações de âncora aqui.
  • Localize a âncora utilizando a relocalização grossa.

Nota

Cada vez que localizar uma âncora, as âncoras espaciais Azure tentarão utilizar os dados ambientais recolhidos para aumentar as informações visuais na âncora. Se tiver dificuldade em localizar uma âncora, pode ser útil criar uma âncora e, em seguida, localizá-la várias vezes de diferentes ângulos e condições de iluminação.

Se estiver a localizar âncoras espaciais em nuvem por identificador, pode armazenar o identificador de âncora espacial em nuvem no serviço back-end da sua aplicação e torná-lo acessível a todos os dispositivos que possam autenticar adequadamente o mesmo. Para um exemplo disso, consulte Tutorial: Partilhar Âncoras Espaciais em todos os dispositivos.

Instantaneamente um AnchorLocateCriteria objeto, desemote os identificadores que procura, e invoque o CreateWatcher método na sessão fornecendo o seu AnchorLocateCriteria.

Saiba mais sobre o método createWatcher .

    let criteria = ASAAnchorLocateCriteria()!
    criteria.identifiers = [ "id1", "id2", "id3" ]
    _cloudSession!.createWatcher(criteria)

Após a criação do seu observador, o AnchorLocated evento disparará para todas as âncoras solicitadas. Este evento dispara quando uma âncora está localizada, ou se a âncora não pode ser localizada. Se esta situação acontecer, a razão será indicada no estado. Depois de todas as âncoras para um observador serem processadas, encontradas ou não encontradas, então o LocateAnchorsCompleted evento disparará. Há um limite de 35 identificadores por observador.

Saiba mais sobre o método do protocolo anchorLocated .

    internal func anchorLocated(_ cloudSession: ASACloudSpatialAnchorSession!, _ args: ASAAnchorLocatedEventArgs!) {
        let status = args.status
        switch (status) {
        case ASALocateAnchorStatus.located:
            let foundAnchor = args.anchor
            // Go add your anchor to the scene...
            break
        case ASALocateAnchorStatus.alreadyTracked:
            // This anchor has already been reported and is being tracked
            break
        case ASALocateAnchorStatus.notLocatedAnchorDoesNotExist:
            // The anchor was deleted or never existed in the first place
            // Drop it, or show UI to ask user to anchor the content anew
            break
        case ASALocateAnchorStatus.notLocated:
            // The anchor hasn't been found given the location data
            // The user might in the wrong location, or maybe more data will help
            // Show UI to tell user to keep looking around
            break
        }
    }

Apagar âncoras

Eliminar âncoras quando já não é usado é uma boa prática para incluir no início do seu processo de desenvolvimento e práticas, para manter os seus recursos Azure limpos.

Saiba mais sobre o método de eliminação .

    _cloudSession?.delete(cloudAnchor!, withCompletionHandler: { (error: Error?) in
        // Perform any processing you may want when delete finishes
    })

Pausa, reset ou parar a sessão

Para interromper a sessão temporariamente, pode invocar Stop(). Ao fazê-lo, impedirá qualquer observador e processamento de ambiente, mesmo que invoque ProcessFrame(). Em seguida, pode invocar Start() para retomar o processamento. Ao retomar, os dados ambientais já capturados na sessão são mantidos.

Saiba mais sobre o método stop .

    _cloudSession!.stop()

Para redefinir os dados ambientais capturados na sua sessão, pode invocar Reset().

Saiba mais sobre o método de reset .

    _cloudSession!.reset()

Para limpar corretamente após uma sessão, liberte todas as referências.

    _cloudSession = nil

Passos seguintes

Neste guia, aprendeu sobre como criar e localizar âncoras usando o Azure Spatial Anchors SDK. Para saber mais sobre relações de âncora, continue para o próximo guia.