|
| 1 | +--- |
| 2 | +title: Create and locate anchors using Azure Spatial Anchors in C++/NDK | Microsoft Docs |
| 3 | +description: In-depth explanation of how to create and locate anchors using Azure Spatial Anchors in C++/NDK. |
| 4 | +author: ramonarguelles |
| 5 | +manager: vicenterivera |
| 6 | +services: azure-spatial-anchors |
| 7 | + |
| 8 | +ms.author: ramonarguelles |
| 9 | +ms.date: 02/24/2019 |
| 10 | +ms.topic: conceptual |
| 11 | +ms.service: azure-spatial-anchors |
| 12 | +# ms.reviewer: MSFT-alias-of-reviewer |
| 13 | +#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. |
| 14 | +--- |
| 15 | +# Create and locate anchors using Azure Spatial Anchors in C++/NDK |
| 16 | + |
| 17 | +> [!div class="op_single_selector"] |
| 18 | +> * [Unity](create-locate-anchors-unity.md) |
| 19 | +> * [Objective-C](create-locate-anchors-objc.md) |
| 20 | +> * [Swift](create-locate-anchors-swift.md) |
| 21 | +> * [Android Java](create-locate-anchors-java.md) |
| 22 | +> * [C++/NDK](create-locate-anchors-cpp-ndk.md) |
| 23 | +> * [C++/WinRT](create-locate-anchors-cpp-winrt.md) |
| 24 | +
|
| 25 | +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. |
| 26 | + |
| 27 | +[!INCLUDE [Start](../../../includes/spatial-anchors-create-locate-anchors-start.md)] |
| 28 | + |
| 29 | +```cpp |
| 30 | + std::shared_ptr<CloudSpatialAnchorSession> cloudSession_; |
| 31 | + // In your view handler |
| 32 | + cloudSession_ = std::make_shared<CloudSpatialAnchorSession>(); |
| 33 | +``` |
| 34 | + |
| 35 | +[!INCLUDE [Account Keys](../../../includes/spatial-anchors-create-locate-anchors-account-keys.md)] |
| 36 | + |
| 37 | +```cpp |
| 38 | + auto configuration = cloudSession_->Configuration(); |
| 39 | + configuration->AccountKey(R"(MyAccountKey)"); |
| 40 | +``` |
| 41 | +
|
| 42 | +[!INCLUDE [Access Tokens](../../../includes/spatial-anchors-create-locate-anchors-access-tokens.md)] |
| 43 | +
|
| 44 | +```cpp |
| 45 | + auto configuration = cloudSession_->Configuration(); |
| 46 | + configuration->AccessToken(R"(MyAccessToken)"); |
| 47 | +``` |
| 48 | + |
| 49 | +[!INCLUDE [Access Tokens Event](../../../includes/spatial-anchors-create-locate-anchors-access-tokens-event.md)] |
| 50 | + |
| 51 | +```cpp |
| 52 | + auto accessTokenRequiredToken = cloudSession_->AccessTokenRequired([](auto&&, auto&& args) { |
| 53 | + args->AccessToken(R"(MyAccessToken)"); |
| 54 | + }); |
| 55 | +``` |
| 56 | +
|
| 57 | +[!INCLUDE [Asynchronous Tokens](../../../includes/spatial-anchors-create-locate-anchors-asynchronous-tokens.md)] |
| 58 | +
|
| 59 | +```cpp |
| 60 | + auto accessTokenRequiredToken = cloudSession_->TokenRequired([this](auto&&, auto&& args) { |
| 61 | + std::shared_ptr<CloudSpatialAnchorSessionDeferral> deferral = args->GetDeferral(); |
| 62 | + MyGetTokenAsync([&deferral, &args](std::string const& myToken) { |
| 63 | + if (myToken != nullptr) args->AccessToken(myToken); |
| 64 | + deferral->Complete(); |
| 65 | + }); |
| 66 | + }); |
| 67 | +``` |
| 68 | + |
| 69 | +[!INCLUDE [AAD Tokens](../../../includes/spatial-anchors-create-locate-anchors-aad-tokens.md)] |
| 70 | + |
| 71 | +```cpp |
| 72 | + auto configuration = cloudSession_->Configuration(); |
| 73 | + configuration->AuthenticationToken(R"(MyAuthenticationToken)"); |
| 74 | +``` |
| 75 | +
|
| 76 | +[!INCLUDE [AAD Tokens Event](../../../includes/spatial-anchors-create-locate-anchors-aad-tokens-event.md)] |
| 77 | +
|
| 78 | +```cpp |
| 79 | + auto accessTokenRequiredToken = cloudSession_->AccessTokenRequired([](auto&&, auto&& args) { |
| 80 | + args->AuthenticationToken(R"(MyAuthenticationToken)"); |
| 81 | + }); |
| 82 | +``` |
| 83 | + |
| 84 | +[!INCLUDE [Asynchronous Tokens](../../../includes/spatial-anchors-create-locate-anchors-asynchronous-tokens.md)] |
| 85 | + |
| 86 | +```cpp |
| 87 | + auto accessTokenRequiredToken = cloudSession_->TokenRequired([this](auto&&, auto&& args) { |
| 88 | + std::shared_ptr<CloudSpatialAnchorSessionDeferral> deferral = args->GetDeferral(); |
| 89 | + MyGetTokenAsync([&deferral, &args](std::string const& myToken) { |
| 90 | + if (myToken != nullptr) args->AuthenticationToken(myToken); |
| 91 | + deferral->Complete(); |
| 92 | + }); |
| 93 | + }); |
| 94 | +``` |
| 95 | +
|
| 96 | +[!INCLUDE [Setup](../../../includes/spatial-anchors-create-locate-anchors-setup-non-ios.md)] |
| 97 | +
|
| 98 | +```cpp |
| 99 | + cloudSession_->Session(ar_session_); |
| 100 | + cloudSession_->Start(); |
| 101 | +``` |
| 102 | + |
| 103 | +[!INCLUDE [Frames](../../../includes/spatial-anchors-create-locate-anchors-frames.md)] |
| 104 | + |
| 105 | +```cpp |
| 106 | + cloudSession_->ProcessFrame(ar_frame_); |
| 107 | +``` |
| 108 | +
|
| 109 | +[!INCLUDE [Feedback](../../../includes/spatial-anchors-create-locate-anchors-feedback.md)] |
| 110 | +
|
| 111 | +```cpp |
| 112 | + auto sessionUpdatedToken = cloudSession_->SessionUpdated([this](auto&&, auto&& args) { |
| 113 | + auto status = args->Status(); |
| 114 | + if (status->UserFeedback() == SessionUserFeedback::None) return; |
| 115 | + std::ostringstream str; |
| 116 | + str << std::fixed << std::setw(2) << std::setprecision(0) |
| 117 | + << R"(Feedback: )" << FeedbackToString(status.UserFeedback()) << R"( -)" |
| 118 | + << R"( Recommend Create=)" << (status->RecommendedForCreateProgress() * 100) << R"(%)"; |
| 119 | + feedback_ = str.str(); |
| 120 | + }); |
| 121 | +``` |
| 122 | + |
| 123 | +[!INCLUDE [Creating](../../../includes/spatial-anchors-create-locate-anchors-creating.md)] |
| 124 | + |
| 125 | +```cpp |
| 126 | + // Create a local anchor, perhaps by hit-testing and creating an ARAnchor |
| 127 | + ArAnchor* localAnchor; |
| 128 | + ArHitResultList* hit_result_list = nullptr; |
| 129 | + ArHitResultList_create(ar_session_, &hit_result_list); |
| 130 | + CHECK(hit_result_list); |
| 131 | + ArFrame_hitTest(ar_session_, ar_frame_, 0.5, 0.5, hit_result_list); |
| 132 | + int32_t hit_result_list_size = 0; |
| 133 | + ArHitResultList_getSize(ar_session_, hit_result_list, &hit_result_list_size); |
| 134 | + if (hit_result_list_size == 0) { |
| 135 | + ArHitResultList_destroy(hit_result_list); |
| 136 | + return; |
| 137 | + } |
| 138 | + ArHitResult* ar_hit = nullptr; |
| 139 | + ArHitResult_create(ar_session_, &ar_hit); |
| 140 | + // The hitTest method sorts the resulting list by distance from the camera, increasing |
| 141 | + // The first hit result will usually be the most relevant when responding to user input |
| 142 | + ArHitResultList_getItem(ar_session_, hit_result_list, 0, ar_hit); |
| 143 | + if (ArHitResult_acquireNewAnchor(ar_session_, ar_hit, &localAnchor) != AR_SUCCESS) return; |
| 144 | + ArTrackingState tracking_state = AR_TRACKING_STATE_STOPPED; |
| 145 | + ArAnchor_getTrackingState(ar_session_, localAnchor, &tracking_state); |
| 146 | + if (tracking_state != AR_TRACKING_STATE_TRACKING) { |
| 147 | + ArAnchor_release(localAnchor); |
| 148 | + ArHitResult_destroy(ar_hit); |
| 149 | + return; |
| 150 | + } |
| 151 | + ArHitResult_destroy(ar_hit); |
| 152 | + ar_hit = nullptr; |
| 153 | + ArHitResultList_destroy(hit_result_list); |
| 154 | + hit_result_list = nullptr; |
| 155 | + |
| 156 | + // If the user is placing some application content in their environment, |
| 157 | + // you might show content at this anchor for a while, then save when |
| 158 | + // the user confirms placement. |
| 159 | + std::shared_ptr<CloudSpatialAnchor> cloudAnchor = std::make_shared<CloudSpatialAnchor>(); |
| 160 | + cloudAnchor->LocalAnchor(localAnchor); |
| 161 | + cloudSession_->CreateAnchorAsync(cloudAnchor, [this, cloudAnchor](Status status) { |
| 162 | + std::ostringstream str; |
| 163 | + if (status != Status::OK) { |
| 164 | + str << "Save Failed: " << std::to_string(static_cast<uint32_t>(status)); |
| 165 | + feedback_ = str.str(); |
| 166 | + return; |
| 167 | + } |
| 168 | + str << R"(Created a cloud anchor with ID=)" << cloudAnchor->Identifier(); |
| 169 | + feedback_ = str.str(); |
| 170 | + }); |
| 171 | +``` |
| 172 | +
|
| 173 | +[!INCLUDE [Session Status](../../../includes/spatial-anchors-create-locate-anchors-session-status.md)] |
| 174 | +
|
| 175 | +```cpp |
| 176 | + cloudSession_->GetSessionStatusAsync([this](Status status, const std::shared_ptr<SessionStatus>& value) { |
| 177 | + if (status != Status::OK) { |
| 178 | + std::ostringstream str; |
| 179 | + str << "Session status error: " << std::to_string(static_cast<uint32_t>(status)); |
| 180 | + feedback_ = str.str(); |
| 181 | + return; |
| 182 | + } |
| 183 | + if (value->RecommendedForCreateProgress() < 1.0f) return; |
| 184 | + // Issue the creation request ... |
| 185 | + }); |
| 186 | +``` |
| 187 | + |
| 188 | +[!INCLUDE [Setting Properties](../../../includes/spatial-anchors-create-locate-anchors-setting-properties.md)] |
| 189 | + |
| 190 | +```cpp |
| 191 | + std::shared_ptr<CloudSpatialAnchor> cloudAnchor = std::make_shared<CloudSpatialAnchor>(); |
| 192 | + cloudAnchor->LocalAnchor(localAnchor); |
| 193 | + auto properties = cloudAnchor->AppProperties(); |
| 194 | + properties->Insert(R"(model-type)", R"(frame)"); |
| 195 | + properties->Insert(R"(label)", R"(my latest picture)"); |
| 196 | + cloudSession_->CreateAnchorAsync(cloudAnchor, [this, cloudAnchor](Status status) { |
| 197 | + // ... |
| 198 | + }); |
| 199 | +``` |
| 200 | +
|
| 201 | +[!INCLUDE [Update Anchor Properties](../../../includes/spatial-anchors-create-locate-anchors-updating-properties.md)] |
| 202 | +
|
| 203 | +```cpp |
| 204 | + std::shared_ptr<CloudSpatialAnchor> anchor = /* locate your anchor */; |
| 205 | + auto properties = anchor->AppProperties(); |
| 206 | + properties->Insert(R"(last-user-access)", R"(just now)"); |
| 207 | + cloudSession_->UpdateAnchorPropertiesAsync(anchor, [this](Status status) { |
| 208 | + if (status != Status::OK) { |
| 209 | + std::ostringstream str; |
| 210 | + str << "Updating Properties Failed: " << std::to_string(static_cast<uint32_t>(status)); |
| 211 | + feedback_ = str.str(); |
| 212 | + } |
| 213 | + }); |
| 214 | +``` |
| 215 | + |
| 216 | +[!INCLUDE [Getting Properties](../../../includes/spatial-anchors-create-locate-anchors-getting-properties.md)] |
| 217 | + |
| 218 | +```cpp |
| 219 | + cloudSession_->GetAnchorPropertiesAsync(R"(anchorId)", [this](Status status, const std::shared_ptr<CloudSpatialAnchor>& anchor) { |
| 220 | + if (status != Status::OK) { |
| 221 | + std::ostringstream str; |
| 222 | + str << "Getting Properties Failed: " << std::to_string(static_cast<uint32_t>(status)); |
| 223 | + feedback_ = str.str(); |
| 224 | + return; |
| 225 | + } |
| 226 | + if (anchor != nullptr) { |
| 227 | + auto properties = anchor->AppProperties(); |
| 228 | + properties->Lookup(R"(last-user-access)") = R"(just now)"; |
| 229 | + cloudSession_->UpdateAnchorPropertiesAsync(anchor, [this](Status status) { |
| 230 | + // ... |
| 231 | + }); |
| 232 | + } |
| 233 | + }); |
| 234 | +``` |
| 235 | +
|
| 236 | +[!INCLUDE [Expiration](../../../includes/spatial-anchors-create-locate-anchors-expiration.md)] |
| 237 | +
|
| 238 | +```cpp |
| 239 | + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); |
| 240 | + std::chrono::system_clock::time_point oneWeekFromNow = now + std::chrono::hours(7 * 24); |
| 241 | + const int64_t oneWeekFromNowUnixEpochTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(oneWeekFromNow.time_since_epoch()).count(); |
| 242 | + cloudAnchor->Expiration(oneWeekFromNowUnixEpochTimeMs); |
| 243 | +``` |
| 244 | + |
| 245 | +[!INCLUDE [Locate](../../../includes/spatial-anchors-create-locate-anchors-locating.md)] |
| 246 | + |
| 247 | +```cpp |
| 248 | + auto criteria = std::make_shared<AnchorLocateCriteria>(); |
| 249 | + criteria->Identifiers({ R"(id1)", R"(id2)", R"(id3)" }); |
| 250 | + auto cloudSpatialAnchorWatcher = cloudSession_->CreateWatcher(criteria); |
| 251 | +``` |
| 252 | +
|
| 253 | +[!INCLUDE [Locate Events](../../../includes/spatial-anchors-create-locate-anchors-locating-events.md)] |
| 254 | +
|
| 255 | +```cpp |
| 256 | + auto anchorLocatedToken = cloudSession_->AnchorLocated([this](auto&&, auto&& args) { |
| 257 | + switch (args->Status()) { |
| 258 | + case LocateAnchorStatus::Located: { |
| 259 | + std::shared_ptr<CloudSpatialAnchor> foundAnchor = args->Anchor(); |
| 260 | + // Go add your anchor to the scene... |
| 261 | + } |
| 262 | + break; |
| 263 | + case LocateAnchorStatus::AlreadyTracked: |
| 264 | + // This anchor has already been reported and is being tracked |
| 265 | + break; |
| 266 | + case LocateAnchorStatus::NotLocatedAnchorDoesNotExist: |
| 267 | + // The anchor was deleted or never exited in the first place |
| 268 | + // Drop it, or show UI to ask user to anchor the content anew |
| 269 | + break; |
| 270 | + case LocateAnchorStatus::NotLocated: |
| 271 | + // The anchor hasn't been found given the location data |
| 272 | + // The user might in the wrong location, or maybe more data will help |
| 273 | + // Show UI to tell user to keep looking around |
| 274 | + break; |
| 275 | + } |
| 276 | + }); |
| 277 | +``` |
| 278 | + |
| 279 | +[!INCLUDE [Deleting](../../../includes/spatial-anchors-create-locate-anchors-deleting.md)] |
| 280 | + |
| 281 | +```cpp |
| 282 | + cloudSession_->DeleteAnchorAsync(cloudAnchor, [this](Status status) { |
| 283 | + // Perform any processing you may want when delete finishes |
| 284 | + }); |
| 285 | +``` |
| 286 | +
|
| 287 | +[!INCLUDE [Stopping](../../../includes/spatial-anchors-create-locate-anchors-stopping.md)] |
| 288 | +
|
| 289 | +```cpp |
| 290 | + cloudSession_->Stop(); |
| 291 | +``` |
| 292 | + |
| 293 | +[!INCLUDE [Resetting](../../../includes/spatial-anchors-create-locate-anchors-resetting.md)] |
| 294 | + |
| 295 | +```cpp |
| 296 | + cloudSession_->Reset(); |
| 297 | +``` |
| 298 | + |
| 299 | +[!INCLUDE [Cleanup](../../../includes/spatial-anchors-create-locate-anchors-cleanup-others.md)] |
| 300 | + |
| 301 | +```cpp |
| 302 | + cloudSession_ = nullptr; |
| 303 | +``` |
| 304 | + |
| 305 | +[!INCLUDE [Next Steps](../../../includes/spatial-anchors-create-locate-anchors-next-steps.md)] |
0 commit comments