class Plane : Trackable


Describes the system's current best knowledge of a real-world planar surface.

Summary

Nested types

A semantic description of a Plane.

The representation of the current state of a Plane.

A simple summary of the normal vector of a Plane.

Public companion functions

StateFlow<Collection<Plane>>
subscribe(session: Session)

Emits the planes that are currently being tracked in the session.

Public functions

open AnchorCreateResult

Creates an Anchor that is attached to this trackable, using the given initial pose in the world coordinate space.

Public properties

open StateFlow<Plane.State>

The current state of the Plane.

Plane.Type

The Type of the Plane.

Extension properties

Flowable<Plane.State>

The current state of the Plane.

Public companion functions

subscribe

Added in 1.0.0-alpha09
fun subscribe(session: Session): StateFlow<Collection<Plane>>

Emits the planes that are currently being tracked in the session.

Only Planes that are TrackingState.TRACKING will be emitted in the Collection. Instances of the same Plane will remain between subsequent emits to the StateFlow as long as they remain tracking.

Throws
kotlin.IllegalStateException

if Session.config is set to Config.PlaneTrackingMode.DISABLED @sample androidx.xr.arcore.samples.getPlanes

Public functions

createAnchor

open fun createAnchor(pose: Pose): AnchorCreateResult

Creates an Anchor that is attached to this trackable, using the given initial pose in the world coordinate space.

Public properties

state

open val stateStateFlow<Plane.State>

The current state of the Plane.

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import androidx.xr.arcore.Plane
import androidx.xr.runtime.TrackingState
import androidx.xr.runtime.math.Pose
import androidx.xr.scenecore.scene

// Use a coroutine to listen to changes to the set of detected planes.
yourCoroutineScope.launch {
    val activePlanes = mutableMapOf<Plane, Job>()

    lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
        val supervisor = SupervisorJob()
        val supervisorScope = CoroutineScope(yourCoroutineScope.coroutineContext + supervisor)
        try {
            Plane.subscribe(session).collect { planes ->
                // The list of detected planes has changed.
                for (plane in planes) {

                    // If a plane doesn't exist in our set of active planes, set up a
                    // coroutine to respond to its state changes.
                    if (!activePlanes.contains(plane)) {
                        val job =
                            supervisorScope.launch {
                                plane.state.collect {
                                    // if the plane is not currently reporting as tracked, then
                                    // we don't want to render it.
                                    if (it.trackingState != TrackingState.TRACKING)
                                        return@collect

                                    // Transform the pose from its original coordinate space to
                                    // one suitable for rendering to the display.
                                    val pose =
                                        it.centerPose.let { p ->
                                            session.scene.perceptionSpace.transformPoseTo(
                                                p,
                                                session.scene.activitySpace,
                                            )
                                        }

                                    // This function is where you'll actually render the plane
                                    // to the display.
                                    renderFunction(pose, it.extents, it.vertices, it.label)
                                }
                            }
                        activePlanes[plane] = job
                    }

                    // Likewise, if a plane exists in the `activePlanes` map, but not in our
                    // `planes` list, it needs to be removed, and its corresponding job
                    // canceled.
                    for (plane in activePlanes.keys.toList()) {
                        if (planes.none { it == plane }) {
                            activePlanes.remove(plane)?.cancel()
                        }
                    }
                }
            }
        } finally {
            // cancel any coroutines still running.
            supervisor.cancel()
            activePlanes.clear()
        }
    }
}

type

Added in 1.0.0-alpha09
val typePlane.Type

The Type of the Plane.

Extension properties

val Plane.stateAsFlowableFlowable<Plane.State>

The current state of the Plane.