// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Utilities; using System.Collections; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.SpatialAwareness { /// <summary> /// Class providing a base implementation of the <see cref="IMixedRealitySpatialAwarenessObserver"/> interface. /// </summary> public abstract class BaseSpatialObserver : BaseDataProvider<IMixedRealitySpatialAwarenessSystem>, IMixedRealitySpatialAwarenessObserver { /// <summary> /// Default dedicated layer for spatial awareness layer used by most components in MRTK /// </summary> public const int DefaultSpatialAwarenessLayer = 31; /// <summary> /// Constructor. /// </summary> /// <param name="spatialAwarenessSystem">The <see cref="SpatialAwareness.IMixedRealitySpatialAwarenessSystem"/> to which the observer is providing data.</param> /// <param name="name">The friendly name of the data provider.</param> /// <param name="priority">The registration priority of the data provider.</param> /// <param name="profile">The configuration profile for the data provider.</param> protected BaseSpatialObserver( IMixedRealitySpatialAwarenessSystem spatialAwarenessSystem, string name = null, uint priority = DefaultPriority, BaseMixedRealityProfile profile = null) : base(spatialAwarenessSystem, name, priority, profile) { SourceId = (Service != null) ? Service.GenerateNewSourceId() : 0; SourceName = name; } /// <summary> /// The spatial awareness system that is associated with this observer. /// </summary> [System.Obsolete("Call Service instead.")] protected IMixedRealitySpatialAwarenessSystem SpatialAwarenessSystem => Service; private GameObject observedObjectParent = null; protected virtual GameObject ObservedObjectParent => observedObjectParent != null ? observedObjectParent : (observedObjectParent = Service?.CreateSpatialAwarenessObservationParent(Name)); /// <summary> /// The parent GameObject for all observed meshes to be placed under. /// </summary> public GameObject ObservationParent => ObservedObjectParent; /// <summary> /// Creates the spatial observer and handles the desired startup behavior. /// </summary> protected virtual void CreateObserver() { } /// <summary> /// Ensures that the spatial observer has been stopped and destroyed. /// </summary> protected virtual void CleanupObserver() { } #region BaseService Implementation /// <inheritdoc /> protected override void Dispose(bool disposing) { if (disposed) { return; } base.Dispose(disposing); if (disposing) { CleanupObservationsAndObserver(); } disposed = true; } #endregion BaseService Implementation #region IMixedRealityDataProvider Implementation /// <summary> /// Creates the observer. /// </summary> public override void Initialize() { CreateObserver(); base.Initialize(); } /// <summary> /// Suspends the observer, clears observations, cleans up the observer, then re-initializes. /// </summary> public override void Reset() { Destroy(); Initialize(); } /// <inheritdoc /> public override void Enable() { base.Enable(); if (!IsRunning && StartupBehavior == AutoStartBehavior.AutoStart) { Resume(); } } /// <inheritdoc /> public override void Disable() { // If we are disabled while running... if (IsRunning) { // Suspend the observer Suspend(); } base.Disable(); } /// <inheritdoc /> public override void Destroy() { CleanupObservationsAndObserver(); base.Destroy(); } #endregion IMixedRealityDataProvider Implementation #region IMixedRealityEventSource Implementation /// <inheritdoc /> bool IEqualityComparer.Equals(object x, object y) { return x.Equals(y); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) { return false; } if (ReferenceEquals(this, obj)) { return true; } if (obj.GetType() != GetType()) { return false; } return Equals((IMixedRealitySpatialAwarenessObserver)obj); } private bool Equals(IMixedRealitySpatialAwarenessObserver other) { return ((other != null) && (SourceId == other.SourceId) && string.Equals(SourceName, other.SourceName)); } /// <inheritdoc /> public int GetHashCode(object obj) { return obj.GetHashCode(); } public override int GetHashCode() { return Mathf.Abs(SourceName.GetHashCode()); } /// <inheritdoc /> public uint SourceId { get; } /// <inheritdoc /> public string SourceName { get; } #endregion IMixedRealityEventSource Implementation #region IMixedRealitySpatialAwarenessObserver Implementation /// <inheritdoc /> public AutoStartBehavior StartupBehavior { get; set; } = AutoStartBehavior.AutoStart; /// <inheritdoc /> public int DefaultPhysicsLayer { get; protected set; } = DefaultSpatialAwarenessLayer; /// <inheritdoc /> public bool IsRunning { get; protected set; } = false; /// <inheritdoc /> public bool IsStationaryObserver { get; set; } = false; /// <inheritdoc /> public Quaternion ObserverRotation { get; set; } = Quaternion.identity; /// <inheritdoc /> public Vector3 ObserverOrigin { get; set; } = Vector3.zero; /// <inheritdoc /> public VolumeType ObserverVolumeType { get; set; } = VolumeType.AxisAlignedCube; /// <inheritdoc /> public Vector3 ObservationExtents { get; set; } = Vector3.one * 3f; // 3 meter sides / radius /// <inheritdoc /> public float UpdateInterval { get; set; } = 3.5f; // 3.5 seconds /// <inheritdoc /> public virtual void Resume() { } /// <inheritdoc /> public virtual void Suspend() { } /// <inheritdoc /> public virtual void ClearObservations() { } #endregion IMixedRealitySpatialAwarenessObserver Implementation #region Helpers /// <summary> /// Destroys all observed objects and the observer. /// </summary> private void CleanupObservationsAndObserver() { Disable(); // Destroys all observed objects and the observer. ClearObservations(); CleanupObserver(); } #endregion Helpers #region Obsolete /// <summary> /// Constructor. /// </summary> /// <param name="registrar">The <see cref="IMixedRealityServiceRegistrar"/> instance that loaded the observer.</param> /// <param name="spatialAwarenessSystem">The <see cref="SpatialAwareness.IMixedRealitySpatialAwarenessSystem"/> to which the observer is providing data.</param> /// <param name="name">The friendly name of the data provider.</param> /// <param name="priority">The registration priority of the data provider.</param> /// <param name="profile">The configuration profile for the data provider.</param> [System.Obsolete("This constructor is obsolete (registrar parameter is no longer required) and will be removed in a future version of the Microsoft Mixed Reality Toolkit.")] protected BaseSpatialObserver( IMixedRealityServiceRegistrar registrar, IMixedRealitySpatialAwarenessSystem spatialAwarenessSystem, string name = null, uint priority = DefaultPriority, BaseMixedRealityProfile profile = null) : this(spatialAwarenessSystem, name, priority, profile) { Registrar = registrar; } #endregion } }