forked from MicrosoftDocs/azure-docs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #67519 from MicrosoftDocs/release-pub-preview
Release pub preview
- Loading branch information
Showing
93 changed files
with
3,854 additions
and
74 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
226 changes: 171 additions & 55 deletions
226
articles/role-based-access-control/resource-provider-operations.md
Large diffs are not rendered by default.
Oops, something went wrong.
75 changes: 75 additions & 0 deletions
75
articles/spatial-anchors/concepts/anchor-relationships-way-finding.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
--- | ||
title: Anchor relationships and way-finding in Azure Spatial Anchors | Microsoft Docs | ||
description: Describe the conceptual model behind anchor relationships. Describe the process of connecting anchors within a space, and the process of using the Nearby API to fulfill a way-finding scenario. After explaining the conceptual model, point developers to our sample apps that do nearby so they can get started implementing this scenario in their own apps. | ||
author: ramonarguelles | ||
manager: vicenterivera | ||
services: azure-spatial-anchors | ||
|
||
ms.author: ramonarguelles | ||
ms.date: 02/24/2019 | ||
ms.topic: conceptual | ||
ms.service: azure-spatial-anchors | ||
--- | ||
# Anchor relationships and way-finding in Azure Spatial Anchors | ||
|
||
Anchor relationships allow you to create connected anchors in a space and then ask questions about them like: | ||
|
||
* Are there anchors nearby? | ||
* How far away are they? | ||
|
||
## Examples | ||
|
||
Some example use-cases you can enable with connected anchors include: | ||
|
||
1. A worker needs to carry out a procedure that involves visiting various locations in an industrial factory. The factory has placed spatial anchors at each site involved in the procedure. A HoloLens or mobile app helps guide the worker from one location to the next. It would first ask for the spatial anchors that are nearby, and then guide the worker to the next location. The app displays visual indicators about the general direction and distance to the next location to complete the task. | ||
|
||
2. A museum creates spatial anchors at public displays that together create a specific tour through the museum such as "A one-hour tour of essential public displays". When visitors are at one public display, they can open the museum's mixed reality app on their mobile device. Then, they would point their phone around the space and through a camera feed, and see the general direction and distance to the other public displays on the tour. As the user starts to walk towards one of the public displays, the app progressively updates the general direction and distance to help guide users there. | ||
|
||
## Way-finding | ||
|
||
Imagine the app is using "line-of-sight" direction and distance between anchors to provide guidance hints to users. We refer to this overall scenario as way-finding. It's important to note way-finding is different from turn-by-turn navigation. In turn-by-turn navigation, the users are guided around walls, through doors, and between floors. With way-finding, the user is provided hints about the general direction of the destination. But the user's inference or knowledge of the space also helps to navigate through the structure to the destination. | ||
|
||
Building a way-finding experience involves preparing a space for the experience and developing an app that end users will interact with. The conceptual steps involved include: | ||
|
||
1. Planning the space: Determine the locations within the space that participate in the way-finding experience. In the earlier examples, this activity might be completed by the factory supervisor or the museum tour coordinator. | ||
2. Connecting anchors: Someone visits the chosen locations and creates spatial anchors there. This task can be done with an admin mode of the end-user app or a different app entirely. Through this process, each anchor is connected or related to the others. These relationships are maintained in the service. | ||
3. Starting the end-user experience: The first step for end users is to locate one of the anchors using the app, which can be in any one of the chosen locations. Determining the locations where end users can enter the experience is part of designing the overall experience. | ||
4. Finding nearby anchors: Once the user has located one anchor, the app can request nearby anchors. This procedure returns a pose between the device and these anchors. | ||
5. Guiding the user: The app can take advantage of the pose to each of these anchors to render useful guidance hints about their general direction and distance. For instance, there might be an icon and arrow on a camera feed in a mobile app representing each potential destination as in the image below. | ||
6. Refining the guidance: As the user walks, the app can periodically calculate a new pose between the device and the destination anchor. The app continues to refine the guidance hints that help the user arrive at the destination. | ||
|
||
 | ||
|
||
## Connecting Anchors | ||
|
||
To build a way-finding experience, you need to place connected anchors in the chosen locations. Below we'll assume this work is done by an admin of the app. | ||
|
||
### Connecting Anchors in a single session | ||
|
||
The steps involved in connecting anchors are: | ||
|
||
1. The admin walks to the first location and creates Anchor A using a CloudSpatialAnchorSession. | ||
2. The admin walks to the second location while the underlying MR/AR platform continues to track the user. | ||
3. The admin creates Anchor B with the same CloudSpatialAnchorSession. Anchors A and B are now connected, and this relationship is maintained by the Azure Spatial Anchors service. | ||
4. Continue the procedure for all anchors that you want to connect. | ||
|
||
### Multiple sessions | ||
|
||
You can also connect spatial anchors over multiple sessions. This method allows you to create and connect some anchors at one time, and later create and connect more anchors. To connect anchors with multiple sessions: | ||
|
||
1. The app creates some anchors in one CloudSpatialAnchorSession. | ||
2. Later, for instance on a different day, the app locates one of these anchors with a new CloudSpatialAnchorSession (for example Anchor A). | ||
3. The user walks to a new location, while the underlying MR/AR platform continues to track the user. | ||
4. Using same CloudSpatialAnchorSession, the user creates anchor C. Anchors A, B, and C are now connected and this relationship is maintained by Azure Spatial Anchors. | ||
5. You can continue this procedure for more anchors and more sessions over time. | ||
|
||
### Verifying Anchor Connections | ||
|
||
The app can verify that two anchors are connected by issuing a query for nearby anchors. When the result of the query contains the desired target anchor, then the app has confirmation that the anchors are connected. If they aren't connected, the app can retry the connection procedure again. Here are some reasons why anchors might fail to connect: | ||
|
||
1. The underlying MR/AR tracker lost tracking during the process of connecting anchors. | ||
2. There was a network error communicating with the Azure Spatial Anchors service and the anchor connection couldn't be persisted. | ||
|
||
### Sample code | ||
|
||
You can see sample code that shows you how to connect anchors and do nearby queries. Refer to the Azure Spatial Anchors sample apps on GitHub. |
305 changes: 305 additions & 0 deletions
305
articles/spatial-anchors/concepts/create-locate-anchors-cpp-ndk.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,305 @@ | ||
--- | ||
title: Create and locate anchors using Azure Spatial Anchors in C++/NDK | Microsoft Docs | ||
description: In-depth explanation of how to create and locate anchors using Azure Spatial Anchors in C++/NDK. | ||
author: ramonarguelles | ||
manager: vicenterivera | ||
services: azure-spatial-anchors | ||
|
||
ms.author: ramonarguelles | ||
ms.date: 02/24/2019 | ||
ms.topic: conceptual | ||
ms.service: azure-spatial-anchors | ||
# ms.reviewer: MSFT-alias-of-reviewer | ||
#Customer intent: As a mixed reality developer, I want and in-depth explanation of how to create and locate anchors using Azure Spatial Anchors in C++/NDK. | ||
--- | ||
# Create and locate anchors using Azure Spatial Anchors in C++/NDK | ||
|
||
> [!div class="op_single_selector"] | ||
> * [Unity](create-locate-anchors-unity.md) | ||
> * [Objective-C](create-locate-anchors-objc.md) | ||
> * [Swift](create-locate-anchors-swift.md) | ||
> * [Android Java](create-locate-anchors-java.md) | ||
> * [C++/NDK](create-locate-anchors-cpp-ndk.md) | ||
> * [C++/WinRT](create-locate-anchors-cpp-winrt.md) | ||
Azure Spatial Anchors allow you to share anchors in the world between different devices. It has been tuned to work well with your choice of development environment. In this article, we'll dive into how to do it in C++/NDK. | ||
|
||
[!INCLUDE [Start](../../../includes/spatial-anchors-create-locate-anchors-start.md)] | ||
|
||
```cpp | ||
std::shared_ptr<CloudSpatialAnchorSession> cloudSession_; | ||
// In your view handler | ||
cloudSession_ = std::make_shared<CloudSpatialAnchorSession>(); | ||
``` | ||
|
||
[!INCLUDE [Account Keys](../../../includes/spatial-anchors-create-locate-anchors-account-keys.md)] | ||
|
||
```cpp | ||
auto configuration = cloudSession_->Configuration(); | ||
configuration->AccountKey(R"(MyAccountKey)"); | ||
``` | ||
[!INCLUDE [Access Tokens](../../../includes/spatial-anchors-create-locate-anchors-access-tokens.md)] | ||
```cpp | ||
auto configuration = cloudSession_->Configuration(); | ||
configuration->AccessToken(R"(MyAccessToken)"); | ||
``` | ||
|
||
[!INCLUDE [Access Tokens Event](../../../includes/spatial-anchors-create-locate-anchors-access-tokens-event.md)] | ||
|
||
```cpp | ||
auto accessTokenRequiredToken = cloudSession_->AccessTokenRequired([](auto&&, auto&& args) { | ||
args->AccessToken(R"(MyAccessToken)"); | ||
}); | ||
``` | ||
[!INCLUDE [Asynchronous Tokens](../../../includes/spatial-anchors-create-locate-anchors-asynchronous-tokens.md)] | ||
```cpp | ||
auto accessTokenRequiredToken = cloudSession_->TokenRequired([this](auto&&, auto&& args) { | ||
std::shared_ptr<CloudSpatialAnchorSessionDeferral> deferral = args->GetDeferral(); | ||
MyGetTokenAsync([&deferral, &args](std::string const& myToken) { | ||
if (myToken != nullptr) args->AccessToken(myToken); | ||
deferral->Complete(); | ||
}); | ||
}); | ||
``` | ||
|
||
[!INCLUDE [AAD Tokens](../../../includes/spatial-anchors-create-locate-anchors-aad-tokens.md)] | ||
|
||
```cpp | ||
auto configuration = cloudSession_->Configuration(); | ||
configuration->AuthenticationToken(R"(MyAuthenticationToken)"); | ||
``` | ||
[!INCLUDE [AAD Tokens Event](../../../includes/spatial-anchors-create-locate-anchors-aad-tokens-event.md)] | ||
```cpp | ||
auto accessTokenRequiredToken = cloudSession_->AccessTokenRequired([](auto&&, auto&& args) { | ||
args->AuthenticationToken(R"(MyAuthenticationToken)"); | ||
}); | ||
``` | ||
|
||
[!INCLUDE [Asynchronous Tokens](../../../includes/spatial-anchors-create-locate-anchors-asynchronous-tokens.md)] | ||
|
||
```cpp | ||
auto accessTokenRequiredToken = cloudSession_->TokenRequired([this](auto&&, auto&& args) { | ||
std::shared_ptr<CloudSpatialAnchorSessionDeferral> deferral = args->GetDeferral(); | ||
MyGetTokenAsync([&deferral, &args](std::string const& myToken) { | ||
if (myToken != nullptr) args->AuthenticationToken(myToken); | ||
deferral->Complete(); | ||
}); | ||
}); | ||
``` | ||
[!INCLUDE [Setup](../../../includes/spatial-anchors-create-locate-anchors-setup-non-ios.md)] | ||
```cpp | ||
cloudSession_->Session(ar_session_); | ||
cloudSession_->Start(); | ||
``` | ||
|
||
[!INCLUDE [Frames](../../../includes/spatial-anchors-create-locate-anchors-frames.md)] | ||
|
||
```cpp | ||
cloudSession_->ProcessFrame(ar_frame_); | ||
``` | ||
[!INCLUDE [Feedback](../../../includes/spatial-anchors-create-locate-anchors-feedback.md)] | ||
```cpp | ||
auto sessionUpdatedToken = cloudSession_->SessionUpdated([this](auto&&, auto&& args) { | ||
auto status = args->Status(); | ||
if (status->UserFeedback() == SessionUserFeedback::None) return; | ||
std::ostringstream str; | ||
str << std::fixed << std::setw(2) << std::setprecision(0) | ||
<< R"(Feedback: )" << FeedbackToString(status.UserFeedback()) << R"( -)" | ||
<< R"( Recommend Create=)" << (status->RecommendedForCreateProgress() * 100) << R"(%)"; | ||
feedback_ = str.str(); | ||
}); | ||
``` | ||
|
||
[!INCLUDE [Creating](../../../includes/spatial-anchors-create-locate-anchors-creating.md)] | ||
|
||
```cpp | ||
// Create a local anchor, perhaps by hit-testing and creating an ARAnchor | ||
ArAnchor* localAnchor; | ||
ArHitResultList* hit_result_list = nullptr; | ||
ArHitResultList_create(ar_session_, &hit_result_list); | ||
CHECK(hit_result_list); | ||
ArFrame_hitTest(ar_session_, ar_frame_, 0.5, 0.5, hit_result_list); | ||
int32_t hit_result_list_size = 0; | ||
ArHitResultList_getSize(ar_session_, hit_result_list, &hit_result_list_size); | ||
if (hit_result_list_size == 0) { | ||
ArHitResultList_destroy(hit_result_list); | ||
return; | ||
} | ||
ArHitResult* ar_hit = nullptr; | ||
ArHitResult_create(ar_session_, &ar_hit); | ||
// The hitTest method sorts the resulting list by distance from the camera, increasing | ||
// The first hit result will usually be the most relevant when responding to user input | ||
ArHitResultList_getItem(ar_session_, hit_result_list, 0, ar_hit); | ||
if (ArHitResult_acquireNewAnchor(ar_session_, ar_hit, &localAnchor) != AR_SUCCESS) return; | ||
ArTrackingState tracking_state = AR_TRACKING_STATE_STOPPED; | ||
ArAnchor_getTrackingState(ar_session_, localAnchor, &tracking_state); | ||
if (tracking_state != AR_TRACKING_STATE_TRACKING) { | ||
ArAnchor_release(localAnchor); | ||
ArHitResult_destroy(ar_hit); | ||
return; | ||
} | ||
ArHitResult_destroy(ar_hit); | ||
ar_hit = nullptr; | ||
ArHitResultList_destroy(hit_result_list); | ||
hit_result_list = nullptr; | ||
|
||
// 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. | ||
std::shared_ptr<CloudSpatialAnchor> cloudAnchor = std::make_shared<CloudSpatialAnchor>(); | ||
cloudAnchor->LocalAnchor(localAnchor); | ||
cloudSession_->CreateAnchorAsync(cloudAnchor, [this, cloudAnchor](Status status) { | ||
std::ostringstream str; | ||
if (status != Status::OK) { | ||
str << "Save Failed: " << std::to_string(static_cast<uint32_t>(status)); | ||
feedback_ = str.str(); | ||
return; | ||
} | ||
str << R"(Created a cloud anchor with ID=)" << cloudAnchor->Identifier(); | ||
feedback_ = str.str(); | ||
}); | ||
``` | ||
[!INCLUDE [Session Status](../../../includes/spatial-anchors-create-locate-anchors-session-status.md)] | ||
```cpp | ||
cloudSession_->GetSessionStatusAsync([this](Status status, const std::shared_ptr<SessionStatus>& value) { | ||
if (status != Status::OK) { | ||
std::ostringstream str; | ||
str << "Session status error: " << std::to_string(static_cast<uint32_t>(status)); | ||
feedback_ = str.str(); | ||
return; | ||
} | ||
if (value->RecommendedForCreateProgress() < 1.0f) return; | ||
// Issue the creation request ... | ||
}); | ||
``` | ||
|
||
[!INCLUDE [Setting Properties](../../../includes/spatial-anchors-create-locate-anchors-setting-properties.md)] | ||
|
||
```cpp | ||
std::shared_ptr<CloudSpatialAnchor> cloudAnchor = std::make_shared<CloudSpatialAnchor>(); | ||
cloudAnchor->LocalAnchor(localAnchor); | ||
auto properties = cloudAnchor->AppProperties(); | ||
properties->Insert(R"(model-type)", R"(frame)"); | ||
properties->Insert(R"(label)", R"(my latest picture)"); | ||
cloudSession_->CreateAnchorAsync(cloudAnchor, [this, cloudAnchor](Status status) { | ||
// ... | ||
}); | ||
``` | ||
[!INCLUDE [Update Anchor Properties](../../../includes/spatial-anchors-create-locate-anchors-updating-properties.md)] | ||
```cpp | ||
std::shared_ptr<CloudSpatialAnchor> anchor = /* locate your anchor */; | ||
auto properties = anchor->AppProperties(); | ||
properties->Insert(R"(last-user-access)", R"(just now)"); | ||
cloudSession_->UpdateAnchorPropertiesAsync(anchor, [this](Status status) { | ||
if (status != Status::OK) { | ||
std::ostringstream str; | ||
str << "Updating Properties Failed: " << std::to_string(static_cast<uint32_t>(status)); | ||
feedback_ = str.str(); | ||
} | ||
}); | ||
``` | ||
|
||
[!INCLUDE [Getting Properties](../../../includes/spatial-anchors-create-locate-anchors-getting-properties.md)] | ||
|
||
```cpp | ||
cloudSession_->GetAnchorPropertiesAsync(R"(anchorId)", [this](Status status, const std::shared_ptr<CloudSpatialAnchor>& anchor) { | ||
if (status != Status::OK) { | ||
std::ostringstream str; | ||
str << "Getting Properties Failed: " << std::to_string(static_cast<uint32_t>(status)); | ||
feedback_ = str.str(); | ||
return; | ||
} | ||
if (anchor != nullptr) { | ||
auto properties = anchor->AppProperties(); | ||
properties->Lookup(R"(last-user-access)") = R"(just now)"; | ||
cloudSession_->UpdateAnchorPropertiesAsync(anchor, [this](Status status) { | ||
// ... | ||
}); | ||
} | ||
}); | ||
``` | ||
[!INCLUDE [Expiration](../../../includes/spatial-anchors-create-locate-anchors-expiration.md)] | ||
```cpp | ||
std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); | ||
std::chrono::system_clock::time_point oneWeekFromNow = now + std::chrono::hours(7 * 24); | ||
const int64_t oneWeekFromNowUnixEpochTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(oneWeekFromNow.time_since_epoch()).count(); | ||
cloudAnchor->Expiration(oneWeekFromNowUnixEpochTimeMs); | ||
``` | ||
|
||
[!INCLUDE [Locate](../../../includes/spatial-anchors-create-locate-anchors-locating.md)] | ||
|
||
```cpp | ||
auto criteria = std::make_shared<AnchorLocateCriteria>(); | ||
criteria->Identifiers({ R"(id1)", R"(id2)", R"(id3)" }); | ||
auto cloudSpatialAnchorWatcher = cloudSession_->CreateWatcher(criteria); | ||
``` | ||
[!INCLUDE [Locate Events](../../../includes/spatial-anchors-create-locate-anchors-locating-events.md)] | ||
```cpp | ||
auto anchorLocatedToken = cloudSession_->AnchorLocated([this](auto&&, auto&& args) { | ||
switch (args->Status()) { | ||
case LocateAnchorStatus::Located: { | ||
std::shared_ptr<CloudSpatialAnchor> foundAnchor = args->Anchor(); | ||
// Go add your anchor to the scene... | ||
} | ||
break; | ||
case LocateAnchorStatus::AlreadyTracked: | ||
// This anchor has already been reported and is being tracked | ||
break; | ||
case LocateAnchorStatus::NotLocatedAnchorDoesNotExist: | ||
// The anchor was deleted or never exited in the first place | ||
// Drop it, or show UI to ask user to anchor the content anew | ||
break; | ||
case LocateAnchorStatus::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; | ||
} | ||
}); | ||
``` | ||
|
||
[!INCLUDE [Deleting](../../../includes/spatial-anchors-create-locate-anchors-deleting.md)] | ||
|
||
```cpp | ||
cloudSession_->DeleteAnchorAsync(cloudAnchor, [this](Status status) { | ||
// Perform any processing you may want when delete finishes | ||
}); | ||
``` | ||
[!INCLUDE [Stopping](../../../includes/spatial-anchors-create-locate-anchors-stopping.md)] | ||
```cpp | ||
cloudSession_->Stop(); | ||
``` | ||
|
||
[!INCLUDE [Resetting](../../../includes/spatial-anchors-create-locate-anchors-resetting.md)] | ||
|
||
```cpp | ||
cloudSession_->Reset(); | ||
``` | ||
|
||
[!INCLUDE [Cleanup](../../../includes/spatial-anchors-create-locate-anchors-cleanup-others.md)] | ||
|
||
```cpp | ||
cloudSession_ = nullptr; | ||
``` | ||
|
||
[!INCLUDE [Next Steps](../../../includes/spatial-anchors-create-locate-anchors-next-steps.md)] |
Oops, something went wrong.