Delen via


Hoe maak en vind ik ankers met behulp van Azure Spatial Anchors in Java

Met Azure Spatial Anchors kunt u ankers delen tussen verschillende apparaten. Er worden meerdere ontwikkelomgevingen ondersteund. In dit artikel gaan we dieper in op het gebruik van de Azure Spatial Anchors SDK in Java om:

  • een Azure Spatial Anchors-sessie correct in te stellen en te beheren.
  • eigenschappen op lokale ankers te maken en in te stellen.
  • gegevens naar de cloud te uploaden.
  • ruimtelijke ankers in de cloud te vinden en verwijderen.

Vereisten

Om deze zelfstudie te voltooien, moet u ervoor zorgen dat u:

Cross Platform

De sessie initialiseren

Het belangrijkste invoerpunt voor de SDK is de klasse die uw sessie weergeeft. Normaal gesproken declareert u een veld in de klasse waarmee uw weergave en de systeemeigen AR-sessie worden beheerd.

Meer informatie over de les CloudSpatialAnchorSession.

    private CloudSpatialAnchorSession mCloudSession;
    // In your view handler
    mCloudSession = new CloudSpatialAnchorSession();

Verificatie instellen

Voor toegang tot de service moet u een accountsleutel, toegangstoken of Microsoft Entra-verificatietoken opgeven. U kunt hierover meer lezen op de conceptpagina Verificatie.

Accountsleutels

Accountsleutels zijn een referentie waarmee uw toepassing kan worden geverifieerd bij de service Azure Spatial Anchors. Het beoogde doel van accountsleutels is om snel aan de slag te kunnen. Met name tijdens de ontwikkelingsfase van de integratie van uw toepassing met Azure Spatial Anchors. Zo kunt u accountsleutels gebruiken door ze tijdens het ontwikkelen in uw clienttoepassingen in te sluiten. Naarmate u verdergaat met ontwikkelen, wordt het ten zeerste aanbevolen om over te stappen naar een verificatiemechanisme dat op productieniveau wordt ondersteund door Toegangstokens of Microsoft Entra-gebruikersverificatie. Als u een accountsleutel voor ontwikkeling wilt ophalen, gaat u in uw Azure Spatial Anchors-account en naar het tabblad Sleutels.

Meer informatie over de les SessionConfiguration.

    mCloudSession.getConfiguration().setAccountKey("MyAccountKey");

Toegangstokens

Toegangstokens zijn een meer robuuste methode om verificatie uit te voeren bij Azure Spatial Anchors. Met name wanneer u de toepassing voorbereidt voor een productie-implementatie. Samengevat: stel een back-endservice in waarmee uw clienttoepassing veilig kan worden geverifieerd. Uw back-endservice communiceert tijdens runtime met AAD en met de beveiligingstokenservice van Azure Spatial Anchors om een toegangstoken aan te vragen. Dit token wordt vervolgens afgeleverd aan de clienttoepassing en wordt in de SDK gebruikt om verificatie bij Azure Spatial Anchors uit te voeren.

    mCloudSession.getConfiguration().setAccessToken("MyAccessToken");

Als er geen toegangstoken is ingesteld, moet u de TokenRequired gebeurtenis afhandelen of de methode tokenRequired implementeren op het gemachtigde protocol.

U kunt de gebeurtenis synchroon afhandelen door de eigenschap voor de gebeurtenisargumenten in te stellen.

Meer informatie over de TokenRequiredListener-interface.

    mCloudSession.addTokenRequiredListener(args -> {
        args.setAccessToken("MyAccessToken");
    });

Als u asynchroon werk in uw handler wilt uitvoeren, kunt u het instellen van het token uitstellen door een deferral-object aan te vragen en het vervolgens te voltooien, zoals in het volgende voorbeeld.

    mCloudSession.addTokenRequiredListener(args -> {
        CloudSpatialAnchorSessionDeferral deferral = args.getDeferral();
        MyGetTokenAsync(myToken -> {
            if (myToken != null) args.setAccessToken(myToken);
            deferral.complete();
        });
    });

Microsoft Entra-verificatie

Met Azure Spatial Anchors kunnen toepassingen ook worden geverifieerd met Microsoft Entra ID-tokens (Active Directory). U kunt bijvoorbeeld Microsoft Entra-tokens gebruiken om te integreren met Azure Spatial Anchors. Als een Enterprise gebruikers onderhoudt in Microsoft Entra ID, kunt u een Microsoft Entra-token van een gebruiker opgeven in de Azure Spatial Anchors SDK. Hierdoor kunt u zich rechtstreeks verifiëren bij de Azure Spatial Anchors-service voor een account dat deel uitmaakt van dezelfde Microsoft Entra-tenant.

    mCloudSession.getConfiguration().setAuthenticationToken("MyAuthenticationToken");

Net als bij toegangstokens moet u, als een Microsoft Entra-token niet is ingesteld, de tokenRequired-gebeurtenis afhandelen of de methode tokenRequired implementeren in het gemachtigde protocol.

U kunt de gebeurtenis synchroon afhandelen door de eigenschap voor de gebeurtenisargumenten in te stellen.

    mCloudSession.addTokenRequiredListener(args -> {
        args.setAuthenticationToken("MyAuthenticationToken");
    });

Als u asynchroon werk in uw handler wilt uitvoeren, kunt u het instellen van het token uitstellen door een deferral-object aan te vragen en het vervolgens te voltooien, zoals in het volgende voorbeeld.

    mCloudSession.addTokenRequiredListener(args -> {
        CloudSpatialAnchorSessionDeferral deferral = args.getDeferral();
        MyGetTokenAsync(myToken -> {
            if (myToken != null) args.setAuthenticationToken(myToken);
            deferral.complete();
        });
    });

De sessie instellen

Start() aanroepen om uw sessie in staat te stellen omgevingsgegevens te verwerken.

Als u gebeurtenissen wilt afhandelen die door uw sessie worden gegenereerd, koppelt u een gebeurtenis-handler.

    mCloudSession.setSession(mSession);
    mCloudSession.start();

De sessie voorzien van frames

De ruimtelijke-ankersessie werkt door de ruimte rond de gebruiker toe te wijzen. Zo kunt u bepalen waar de ankers zich moeten bevinden. Mobiele platformen (iOS en Android) vereisen een systeemeigen aanroep naar de camerafeed om frames van de AR-bibliotheek van uw platform te verkrijgen. Daarentegen wordt de omgeving voortdurend gescand door HoloLens, dus er is geen specifieke aanroep nodig, zoals bij mobiele platforms.

    mCloudSession.processFrame(mSession.update());

De gebruiker feedback geven

U kunt code schrijven voor het verwerken van de actuele sessiegebeurtenis. Deze gebeurtenis wordt geactiveerd wanneer het begrip van uw omgeving door de sessie worden verbeterd. Hierdoor kunt u het volgende doen:

  • Klasse UserFeedback gebruiken om feedback te geven aan de gebruiker terwijl het apparaat beweegt en het begrip van de omgeving wordt bijgewerkt. Dit wilt doen
  • Bepaal op welk moment er voldoende getraceerde ruimtelijke gegevens zijn om ruimtelijke ankers te maken. U kunt dit vaststellen met ReadyForCreateProgress of RecommendedForCreateProgress. Als ReadyForCreateProgress meer is dan 1, zijn er voldoende gegevens om een ruimtelijk anker in de cloud op te slaan. Het is echter raadzaam te wachten tot RecommendedForCreateProgress groter is dan 1.

Meer informatie over de SessionUpdatedListener-interface.

    mCloudSession.addSessionUpdatedListener(args -> {
        auto status = args->Status();
        if (status->UserFeedback() == SessionUserFeedback::None) return;
        NumberFormat percentFormat = NumberFormat.getPercentInstance();
        percentFormat.setMaximumFractionDigits(1);
        mFeedback = String.format("Feedback: %s - Recommend Create=%s",
            FeedbackToString(status.getUserFeedback()),
            percentFormat.format(status.getRecommendedForCreateProgress()));
    });

Een ruimtelijk anker in de cloud maken

Als u een ruimtelijk anker in de Cloud wilt maken, maakt u eerst een anker in het AR-systeem van uw platform en maakt u vervolgens een equivalent in de cloud. U gebruikt de CreateAnchorAsync()-methode.

Meer informatie over de les CloudSpatialAnchor.

    // Create a local anchor, perhaps by hit-testing and creating an ARAnchor
    Anchor localAnchor = null;
    List<HitResult> hitResults = mSession.update().hitTest(0.5f, 0.5f);
    for (HitResult hit : hitResults) {
        Trackable trackable = hit.getTrackable();
        if (trackable instanceof Plane) {
            if (((Plane) trackable).isPoseInPolygon(hit.getHitPose())) {
                localAnchor = hit.createAnchor();
                break;
            }
        }
    }

    // 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.
    CloudSpatialAnchor cloudAnchor = new CloudSpatialAnchor();
    cloudAnchor.setLocalAnchor(localAnchor);
    Future createAnchorFuture = mCloudSession.createAnchorAsync(cloudAnchor);
    CheckForCompletion(createAnchorFuture, cloudAnchor);

    // ...

    private void CheckForCompletion(Future createAnchorFuture, CloudSpatialAnchor cloudAnchor) {
        new android.os.Handler().postDelayed(() -> {
            if (createAnchorFuture.isDone()) {
                try {
                    createAnchorFuture.get();
                    mFeedback = String.format("Created a cloud anchor with ID=%s", cloudAnchor.getIdentifier());
                }
                catch(InterruptedException e) {
                    mFeedback = String.format("Save Failed:%s", e.getMessage());
                }
                catch(ExecutionException e) {
                    mFeedback = String.format("Save Failed:%s", e.getMessage());
                }
            }
            else {
                CheckForCompletion(createAnchorFuture, cloudAnchor);
            }
        }, 500);
    }

Zoals eerder beschreven, hebt u voldoende omgevingsgegevens nodig voor het maken van een nieuw ruimtelijk anker voor de cloud. Dit betekent dat ReadyForCreateProgress hoger dan 1 moet zijn, maar we raden u aan om te wachten tot RecommendedForCreateProgress hoger dan 1 is.

    Future<SessionStatus> sessionStatusFuture = mCloudSession.getSessionStatusAsync();
    CheckForCompletion(sessionStatusFuture);

    // ...

    private void CheckForCompletion(Future<SessionStatus> sessionStatusFuture) {
        new android.os.Handler().postDelayed(() -> {
            if (sessionStatusFuture.isDone()) {
                try {
                    SessionStatus value = sessionStatusFuture.get();
                    if (value.getRecommendedForCreateProgress() < 1.0f) return;
                    // Issue the creation request...
                }
                catch(InterruptedException e) {
                    mFeedback = String.format("Session status error:%s", e.getMessage());
                }
                catch(ExecutionException e) {
                    mFeedback = String.format("Session status error:%s", e.getMessage());
                }
            }
            else {
                CheckForCompletion(sessionStatusFuture);
            }
        }, 500);
    }

Eigenschappen instellen

U kunt ervoor kiezen bepaalde eigenschappen toe te voegen bij het opslaan van ruimtelijke ankers in de cloud. Zoals het type object dat wordt opgeslagen of basiseigenschappen, bijvoorbeeld of het voor interactie moet worden ingeschakeld. Dit kan handig zijn bij detectie: u kunt het object direct voor de gebruiker weergeven, bijvoorbeeld een afbeeldingskader met lege inhoud. Vervolgens krijgt een andere downloadactie op de achtergrond aanvullende statusdetails, bijvoorbeeld de afbeelding die in het kader moet worden weergegeven.

    CloudSpatialAnchor cloudAnchor = new CloudSpatialAnchor();
    cloudAnchor.setLocalAnchor(localAnchor);
    Map<String,String> properties = cloudAnchor.getAppProperties();
    properties.put("model-type", "frame");
    properties.put("label", "my latest picture");
    Future createAnchorFuture = mCloudSession.createAnchorAsync(cloudAnchor);
    // ...

Eigenschappen bijwerken

Als u de eigenschappen van een anker wilt bijwerken, gebruikt u methode UpdateAnchorProperties(). Als twee of meer apparaten de eigenschappen van hetzelfde anker op hetzelfde moment proberen bij te werken, wordt een model voor optimistische gelijktijdigheid gebruikt. Dit betekent dat de eerste schrijfbewerking wint. Bij alle andere schrijfbewerkingen wordt een gelijktijdigheidsfout weergeven: vernieuw de eigenschappen voordat u het opnieuw probeert.

    CloudSpatialAnchor anchor = /* locate your anchor */;
    anchor.getAppProperties().put("last-user-access", "just now");
    Future updateAnchorPropertiesFuture = mCloudSession.updateAnchorPropertiesAsync(anchor);
    CheckForCompletion(updateAnchorPropertiesFuture);

    // ...

    private void CheckForCompletion(Future updateAnchorPropertiesFuture) {
        new android.os.Handler().postDelayed(() -> {
            if (updateAnchorPropertiesFuture.isDone()) {
                try {
                    updateAnchorPropertiesFuture.get();
                }
                catch(InterruptedException e) {
                    mFeedback = String.format("Updating Properties Failed:%s", e.getMessage());
                }
                catch(ExecutionException e) {
                    mFeedback = String.format("Updating Properties Failed:%s", e.getMessage());
                }
            }
            else {
                CheckForCompletion1(updateAnchorPropertiesFuture);
            }
        }, 500);
    }

U kunt de locatie van een anker niet bijwerken wanneer het is gemaakt voor de service. U moet een nieuw anker maken en het oude verwijderen om een nieuwe positie bij te houden.

Als u geen anker hoeft te lokaliseren om de eigenschappen ervan bij te werken, kunt u methode GetAnchorPropertiesAsync() gebruiken, waarmee een CloudSpatialAnchor-object met eigenschappen wordt geretourneerd.

    Future<CloudSpatialAnchor> getAnchorPropertiesFuture = mCloudSession.getAnchorPropertiesAsync("anchorId");
    CheckForCompletion(getAnchorPropertiesFuture);

    // ...

    private void CheckForCompletion(Future<CloudSpatialAnchor> getAnchorPropertiesFuture) {
        new android.os.Handler().postDelayed(() -> {
            if (getAnchorPropertiesFuture.isDone()) {
                try {
                    CloudSpatialAnchor anchor = getAnchorPropertiesFuture.get();
                    if (anchor != null) {
                        anchor.getAppProperties().put("last-user-access", "just now");
                        Future updateAnchorPropertiesFuture = mCloudSession.updateAnchorPropertiesAsync(anchor);
                        // ...
                    }
                } catch (InterruptedException e) {
                    mFeedback = String.format("Getting Properties Failed:%s", e.getMessage());
                } catch (ExecutionException e) {
                    mFeedback = String.format("Getting Properties Failed:%s", e.getMessage());
                }
            } else {
                CheckForCompletion(getAnchorPropertiesFuture);
            }
        }, 500);
    }

Vervaldatum instellen

Het is ook mogelijk uw anker zodanig te configureren dat deze op een bepaalde datum verloopt. Wanneer een anker verloopt, kan het niet meer worden gelokaliseerd of bijgewerkt. De vervaldatum kan alleen worden ingesteld wanneer het anker wordt gemaakt, voordat het in de cloud wordt opgeslagen. Het is niet mogelijk de vervaldatum daarna nog bij te werken. Als er geen verloopdatum is ingesteld tijdens het maken van het anker, verloopt het anker alleen wanneer het handmatig wordt verwijderd.

    Date now = new Date();
    Calendar cal = Calendar.getInstance();
    cal.setTime(now);
    cal.add(Calendar.DATE, 7);
    Date oneWeekFromNow = cal.getTime();
    cloudAnchor.setExpiration(oneWeekFromNow);

Een ruimtelijk anker in de cloud lokaliseren

Een van de belangrijkste redenen om Azure Spatial Anchors te gebruiken, is dat u een eerder opgeslagen ruimtelijk anker in de cloud kunt lokaliseren. Hiervoor gebruiken we Watchers. U kunt slechts één Watcher tegelijk gebruiken; meerdere Watchers worden niet ondersteund. Een Watcher kan op verschillende manieren (ook wel 'Anchor Locate Strategies' genoemd) een ruimtelijk anker in de cloud vinden. Voor een watcher kunt u één strategie per keer gebruiken.

  • Lokaliseer ankers op id.
  • Lokaliseer ankers die zijn verbonden met een eerder gelokaliseerd anker. U vindt hier informatie over ankerrelaties.
  • Lokaliseer een anker met grove herlokalisatie.

Notitie

Telkens wanneer u een anker lokaliseert, probeert Azure Spatial Anchors de omgevingsgegevens te gebruiken die zijn verzameld om de visuele informatie op het anker te verbeteren. Als u problemen ondervindt bij het lokaliseren van een anker, kan het nuttig zijn om een anker te maken en deze vervolgens meerdere keren vanuit verschillende hoeken en lichtomstandigheden te lokaliseren.

Als u ruimtelijke ankers voor de cloud op id zoekt, kunt u de ruimtelijke anker-id van de cloud opslaan in de back-endservice van uw toepassing en toegankelijk maken voor alle apparaten die er goed bij kunnen worden geverifieerd. Zie zelfstudie: Spatial Anchors delen op verschillende apparaten voor een voorbeeld hiervan.

Instantieer een AnchorLocateCriteria-object, stel de id's in die u zoekt en roep de CreateWatcher-methode voor de sessie aan door uw AnchorLocateCriteria op te geven.

    AnchorLocateCriteria criteria = new AnchorLocateCriteria();
    criteria.setIdentifiers(new String[] { "id1", "id2", "id3" });
    mCloudSession.createWatcher(criteria);

Nadat de watcher is gemaakt, wordt de AnchorLocated-gebeurtenis voor elk aangevraagd anker geactiveerd. Deze gebeurtenis wordt geactiveerd wanneer er een anker wordt gelokaliseerd of als het anker niet kan worden gelokaliseerd. Als deze situatie zich voordoet, wordt de reden aangegeven in de status. Nadat alle ankers voor een watcher zijn verwerkt, gevonden of niet gevonden, wordt de LocateAnchorsCompleted-gebeurtenis geactiveerd. Er geldt een limiet van 35 id's per watcher.

Meer informatie over de AnchorLocatedListener-interface.

    mCloudSession.addAnchorLocatedListener(args -> {
        switch (args.getStatus()) {
            case Located:
                CloudSpatialAnchor foundAnchor = args.getAnchor();
                // Go add your anchor to the scene...
                break;
            case AlreadyTracked:
                // This anchor has already been reported and is being tracked
                break;
            case 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 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;
        }
    });

Ankers verwijderen

Het verwijderen van ankers wanneer deze niet meer wordt gebruikt, is een goede gewoonte om in uw ontwikkelingsproces en -procedures vroegtijdig op te nemen om uw Azure-resources te laten opschonen.

    Future deleteAnchorFuture = mCloudSession.deleteAnchorAsync(cloudAnchor);
    // Perform any processing you may want when delete finishes (deleteAnchorFuture is done)

De sessie onderbreken, opnieuw instellen of stoppen

Als u de sessie tijdelijk wilt stoppen, kunt u Stop() aanroepen. Als u dit doet, worden alle watchers en de omgevingsverwerking gestopt, zelfs als u ProcessFrame() aanroept. Vervolgens kunt u Start() aanroepen om de verwerking te hervatten. Bij het hervatten blijven de omgevingsgegevens die al in de sessie zijn vastgelegd, behouden.

    mCloudSession.stop();

Als u de omgevingsgegevens die in uw sessie zijn vastgelegd opnieuw wilt instellen, kunt u Reset()aanroepen.

    mCloudSession.reset();

Roep close() aan om op de juiste manier op te schonen na een sessie.

    mCloudSession.close();

Volgende stappen

In deze handleiding hebt u geleerd hoe u ankers kunt maken en vinden met behulp van Azure Spatial Anchors SDK. Ga verder met de volgende handleiding voor meer informatie over ankerrelaties.