Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Augment reality to show tabletop scene #303

Merged
merged 24 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bc965f4
Add augment reality to show tabletop scene and metadata updater
TADraeseke Jan 10, 2025
b407e6d
remove metadata move from this PR
TADraeseke Jan 11, 2025
4ca61d2
screenshot
TADraeseke Jan 11, 2025
35df4f2
rename ar core module
TADraeseke Jan 11, 2025
50d743a
Merge branch 'v.next' into trev8939/augmentRealityToShowTabletopScene
TADraeseke Jan 11, 2025
485f2ab
Update README.metadata.json
TADraeseke Jan 11, 2025
6d68418
Update README.metadata.json
TADraeseke Jan 11, 2025
4ad0bca
Update samples/augment-reality-to-show-tabletop-scene/src/main/java/c…
TADraeseke Jan 13, 2025
a4f4150
Update gradle/libs.versions.toml
TADraeseke Jan 13, 2025
53b0634
Update samples/augment-reality-to-show-tabletop-scene/build.gradle.kts
TADraeseke Jan 13, 2025
de700de
Update samples/augment-reality-to-show-tabletop-scene/src/main/java/c…
TADraeseke Jan 13, 2025
7b5507e
Update samples/augment-reality-to-show-tabletop-scene/src/main/java/c…
TADraeseke Jan 13, 2025
849744f
Update samples/augment-reality-to-show-tabletop-scene/README.md
TADraeseke Jan 13, 2025
2a6655c
PR fixes
TADraeseke Jan 13, 2025
f220702
Update README.md
TADraeseke Jan 13, 2025
74325d8
Update samples/augment-reality-to-show-tabletop-scene/README.md
TADraeseke Jan 14, 2025
1d95674
Update samples/augment-reality-to-show-tabletop-scene/README.md
TADraeseke Jan 14, 2025
58c4649
PR fixes
TADraeseke Jan 14, 2025
de14396
Merge branch 'v.next' into trev8939/augmentRealityToShowTabletopScene
TADraeseke Jan 14, 2025
44e7cd0
show instructions to user to setup AR
TADraeseke Jan 14, 2025
4760876
pull from origin
TADraeseke Jan 14, 2025
410633f
typo fix
TADraeseke Jan 15, 2025
685bc59
Update README.metadata.json
TADraeseke Jan 15, 2025
8e756a3
Update samples/augment-reality-to-show-tabletop-scene/src/main/java/c…
TADraeseke Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[versions]

# ArcGIS Maps SDK for Kotlin version
arcgisMapsKotlinVersion = "200.7.0-4452"
arcgisMapsKotlinVersion = "200.7.0-4476"

### Android versions
androidGradlePlugin = "8.7.3"
Expand Down Expand Up @@ -41,6 +41,7 @@ minSdk = "26"
targetSdk = "35"

### Third party libraries
arcore = "1.47.0"

[libraries]

Expand Down Expand Up @@ -78,12 +79,14 @@ androidx-navigation-compose = { group = "androidx.navigation", name = "navigatio
arcgis-maps-kotlin = { group = "com.esri", name = "arcgis-maps-kotlin", version.ref = "arcgisMapsKotlinVersion" }
arcgis-maps-kotlin-toolkit-bom = { group = "com.esri", name = "arcgis-maps-kotlin-toolkit-bom", version.ref = "arcgisMapsKotlinVersion" }
arcgis-maps-kotlin-toolkit-authentication = { group = "com.esri", name = "arcgis-maps-kotlin-toolkit-authentication" }
arcgis-maps-kotlin-toolkit-ar = { group = "com.esri", name = "arcgis-maps-kotlin-toolkit-ar" }
arcgis-maps-kotlin-toolkit-geoview-compose = { group = "com.esri", name = "arcgis-maps-kotlin-toolkit-geoview-compose" }
arcgis-maps-kotlin-toolkit-featureforms = { group = "com.esri", name = "arcgis-maps-kotlin-toolkit-featureforms" }

### Third party libraries
coil-compose = { group = "io.coil-kt.coil3", name = "coil-compose", version = "3.0.0-rc01" }
coil-network-http = { group = "io.coil-kt.coil3", name = "coil-network-okhttp", version = "3.0.0-rc01" }
ar-core = { group = "com.google.ar", name = "core", version.ref = "arcore" }

### Testing libs
junit = { group = "junit", name = "junit", version.ref = "junit" }
Expand All @@ -96,7 +99,6 @@ kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-pl
ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" }
android-tools-common = { group = "com.android.tools", name = "common", version.ref = "androidTools" }


[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" }
Expand Down
42 changes: 42 additions & 0 deletions samples/augment-reality-to-show-tabletop-scene/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Augment reality to show tabletop scene

Use augmented reality (AR) to pin a scene to a table or desk for easy exploration.

![Image of augment reality to show tabletop scene](augment-reality-to-show-tabletop-scene.png)

## Use case

Tabletop scenes allow you to use your device to interact with scenes as if they are 3D-printed model models sitting on your desk. You could use this to virtually explore a proposed development without needing to create a physical model.

## How to use the sample

Once the scene loads, you'll see a feed from the camera. Wait for ArCore to highlight a plane and tap on one to place the scene. With the scene placed, you can move the camera around the scene to explore.

NOTE: [Google Play Services for AR](https://play.google.com/store/apps/details?id=com.google.ar.core) must be installed to run this app and the application code will prompt the user to install it if it is not already installed.

## How it works

1. Create a `TableTopSceneView` with `arcGISSceneAnchor`, `translationFactor`, `clippingDistance`, and an `arcGISScene`.
2. For this sample, the `arcGISSceneAnchor` sets coordinates at the center of the buildings in the `ArcGSISceneLayer` to give the impression that the scene is centered on the location the user tapped.
3. Set the `translationFactor` such that the user can view the entire scene by moving the device around it. The translation factor defines how far the virtual camera moves through the scene when the physical camera moves.
-A good formula for determining translation factor to use in a tabletop map experience is translationFactor = sceneWidth / tableTopWidth. The scene width is the width/length of the scene content you wish to display in meters. The tabletop width is the length of the area on the physical surface that you want the scene content to fill. For simplicity, the sample assumes a scene width of 800 meters.
4. Set the `clippingDistance` to clip the scene to the area you want to show.

## Relevant API

* ArcGISScene
* TableTopSceneView

## About the data

This sample uses the [Philadelphia Mobile Scene Package](https://www.arcgis.com/home/item.html?id=7dd2f97bb007466ea939160d0de96a9d). It was chosen because it is a compact scene ideal for tabletop use. Note that tabletop mapping experiences work best with small, focused scenes. The small, focused area with basemap tiles defines a clear boundary for the scene.

## Additional information

This sample requires a device that is compatible with ARCore on Android.

This sample uses [AR from the Maps SDK Toolkit](https://github.com/Esri/arcgis-maps-sdk-kotlin-toolkit/tree/main/toolkit/ar).

## Tags

augmented reality, drop, mixed reality, model, pin, place, table-top, tabletop
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"category": "Augmented Reality",
"description": "Use augmented reality (AR) to pin a scene to a table or desk for easy exploration.",
"formal_name": "AugmentRealityToShowTabletopScene",
"ignore": false,
"images": [
"augment-reality-to-show-tabletop-scene.png"
],
"keywords": [
"augmented reality",
"drop",
"mixed reality",
"model",
"pin",
"place",
"table-top",
"tabletop",
"ArcGISScene",
"TableTopSceneView"
],
"language": "kotlin",
"redirect_from": "",
"relevant_apis": [
"ArcGISScene",
"TableTopSceneView"
],
"snippets": [
"src/main/java/com/esri/arcgismaps/sample/augmentrealitytoshowtabletopscene/components/AugmentRealityToShowTabletopSceneViewModel.kt",
"src/main/java/com/esri/arcgismaps/sample/augmentrealitytoshowtabletopscene/DownloadActivity.kt",
"src/main/java/com/esri/arcgismaps/sample/augmentrealitytoshowtabletopscene/MainActivity.kt",
"src/main/java/com/esri/arcgismaps/sample/augmentrealitytoshowtabletopscene/screens/AugmentRealityToShowTabletopSceneScreen.kt"
],
"title": "Augment reality to show tabletop scene"
}
TADraeseke marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions samples/augment-reality-to-show-tabletop-scene/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
plugins {
alias(libs.plugins.arcgismaps.android.library)
alias(libs.plugins.arcgismaps.android.library.compose)
alias(libs.plugins.arcgismaps.kotlin.sample)
alias(libs.plugins.gradle.secrets)
}

secrets {
// this file doesn't contain secrets, it just provides defaults which can be committed into git.
defaultPropertiesFileName = "secrets.defaults.properties"
}

android {
namespace = "com.esri.arcgismaps.sample.augmentrealitytoshowtabletopscene"
buildFeatures {
buildConfig = true
}
}

dependencies {
// Only module specific dependencies needed here
implementation(libs.ar.core)
implementation(libs.arcgis.maps.kotlin.toolkit.ar)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />

<!-- Limits app visibility in the Google Play Store to ARCore supported devices
(https://developers.google.com/ar/devices). -->
<uses-feature android:name="android.hardware.camera.ar" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />

<application>
<activity
android:name=".DownloadActivity"
android:label="@string/augment_reality_to_show_tabletop_scene_app_name" />
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/augment_reality_to_show_tabletop_scene_app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<!-- "AR Required" app, requires "Google Play Services for AR" (ARCore)
to be installed, as the app does not include any non-AR features. -->
<meta-data
android:name="com.google.ar.core"
android:value="required" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* Copyright 2025 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.esri.arcgismaps.sample.augmentrealitytoshowtabletopscene

import android.content.Intent
import android.os.Bundle
import com.esri.arcgismaps.sample.sampleslib.DownloaderActivity

class DownloadActivity : DownloaderActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
downloadAndStartSample(
Intent(this, MainActivity::class.java),
// get the app name of the sample
getString(R.string.augment_reality_to_show_tabletop_scene_app_name),
listOf(
// ArcGIS Portal item containing the Philadelphia mobile scene package.
"https://www.arcgis.com/home/item.html?id=7dd2f97bb007466ea939160d0de96a9d"
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/* Copyright 2025 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.esri.arcgismaps.sample.augmentrealitytoshowtabletopscene


import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import com.arcgismaps.ApiKey
import com.arcgismaps.ArcGISEnvironment
import com.esri.arcgismaps.sample.augmentrealitytoshowtabletopscene.components.AugmentRealityToShowTabletopSceneViewModel
import com.esri.arcgismaps.sample.augmentrealitytoshowtabletopscene.screens.DisplaySceneInTabletopARScreen
import com.esri.arcgismaps.sample.sampleslib.theme.SampleAppTheme
import com.google.ar.core.ArCoreApk

class MainActivity : ComponentActivity() {

private var userRequestedInstall = true

private var isGooglePlayServicesArInstalled = false

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// authentication with an API key or named user is
// required to access basemaps and other location services
ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.ACCESS_TOKEN)

setContent {
SampleAppTheme {
DisplaySceneInTabletopARApp()
}
}
}

override fun onResume() {
super.onResume()
checkGooglePlayServicesArInstalled()
}

/**
* Check if Google Play Services for AR is installed on the device. If it's not installed, this method should get
* called twice: once to request the installation and once to ensure it was installed when the activity resumes.
*/
private fun checkGooglePlayServicesArInstalled() {
try {
when (ArCoreApk.getInstance().requestInstall(this, userRequestedInstall)) {
ArCoreApk.InstallStatus.INSTALL_REQUESTED -> {
userRequestedInstall = false
return
}

ArCoreApk.InstallStatus.INSTALLED -> {
isGooglePlayServicesArInstalled = true
return
}
}
} catch (e: Exception) {
val sceneViewModel: AugmentRealityToShowTabletopSceneViewModel by viewModels()
sceneViewModel.messageDialogVM.showMessageDialog(
"Error checking Google Play Services for AR",
e.message.toString()
)
}
}

@Composable
private fun DisplaySceneInTabletopARApp() {
Surface(color = MaterialTheme.colorScheme.background) {
DisplaySceneInTabletopARScreen(
sampleName = getString(R.string.augment_reality_to_show_tabletop_scene_app_name)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* Copyright 2025 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.esri.arcgismaps.sample.augmentrealitytoshowtabletopscene.components

import android.app.Application
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.arcgismaps.mapping.ArcGISScene
import com.arcgismaps.mapping.MobileScenePackage
import com.arcgismaps.mapping.NavigationConstraint
import com.esri.arcgismaps.sample.augmentrealitytoshowtabletopscene.R
import com.esri.arcgismaps.sample.sampleslib.components.MessageDialogViewModel
import kotlinx.coroutines.launch
import java.io.File


class AugmentRealityToShowTabletopSceneViewModel(application: Application) : AndroidViewModel(application) {

private val provisionPath: String by lazy {
application.getExternalFilesDir(null)?.path.toString() + File.separator + application.getString(R.string.augment_reality_to_show_tabletop_scene_app_name)
}

// Get the folder path containing the mobile scene package (.mspk) file
private val filePath = "$provisionPath/philadelphia.mspk"

// Create a mobile scene package
private val scenePackage = MobileScenePackage(filePath)

// Create a mutable state variable to hold the scene. Later loaded from the scene package
var scene: ArcGISScene? by mutableStateOf(null)

// Create a message dialog view model for handling error messages
val messageDialogVM = MessageDialogViewModel()

init {
viewModelScope.launch {
// Load the mobile scene package
scenePackage.load().onSuccess {
// Get the first scene from the package
scene = scenePackage.scenes.first().apply {
// Set the navigation constraint to allow you to look at the scene from below
baseSurface.navigationConstraint = NavigationConstraint.None
}
}.onFailure {
messageDialogVM.showMessageDialog(
"Error loading mobile scene package", it.message.toString()
)
}
}
}
}
Loading
Loading