AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
AppState.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using HoloToolkit.Unity;
7 using System;
8 using System.Collections.Generic;
9 using System.Linq;
10 using UnityEngine;
11 
12 #if UNITY_WSA || UNITY_STANDALONE_WIN
13 using UnityEngine.Windows.Speech;
14 #endif
15 
16 namespace HoloToolkit.Examples.SpatialUnderstandingFeatureOverview
17 {
19  {
20  // Consts
21  public float kMinAreaForStats = 5.0f;
22  public float kMinAreaForComplete = 50.0f;
23  public float kMinHorizAreaForComplete = 25.0f;
24  public float kMinWallAreaForComplete = 10.0f;
25 
26  // Config
27  public TextMesh DebugDisplay;
28  public TextMesh DebugSubDisplay;
29  public Transform Parent_Scene;
32 
33  // Properties
34  public string SpaceQueryDescription
35  {
36  get
37  {
38  return spaceQueryDescription;
39  }
40  set
41  {
42  spaceQueryDescription = value;
43  objectPlacementDescription = "";
44  }
45  }
46 
47  public string ObjectPlacementDescription
48  {
49  get
50  {
51  return objectPlacementDescription;
52  }
53  set
54  {
55  objectPlacementDescription = value;
56  spaceQueryDescription = "";
57  }
58  }
59 
60  public bool DoesScanMeetMinBarForCompletion
61  {
62  get
63  {
64  // Only allow this when we are actually scanning
65  if ((SpatialUnderstanding.Instance.ScanState != SpatialUnderstanding.ScanStates.Scanning) ||
66  (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding))
67  {
68  return false;
69  }
70 
71  // Query the current playspace stats
72  IntPtr statsPtr = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStatsPtr();
74  {
75  return false;
76  }
77  SpatialUnderstandingDll.Imports.PlayspaceStats stats = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStats();
78 
79  // Check our preset requirements
80  if ((stats.TotalSurfaceArea > kMinAreaForComplete) ||
81  (stats.HorizSurfaceArea > kMinHorizAreaForComplete) ||
82  (stats.WallSurfaceArea > kMinWallAreaForComplete))
83  {
84  return true;
85  }
86  return false;
87  }
88  }
89 
90  public string PrimaryText
91  {
92  get
93  {
94  // Display the space and object query results (has priority)
95  if (!string.IsNullOrEmpty(SpaceQueryDescription))
96  {
97  return SpaceQueryDescription;
98  }
99  else if (!string.IsNullOrEmpty(ObjectPlacementDescription))
100  {
101  return ObjectPlacementDescription;
102  }
103 
104  // Scan state
105  if (SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
106  {
107  switch (SpatialUnderstanding.Instance.ScanState)
108  {
109  case SpatialUnderstanding.ScanStates.Scanning:
110  // Get the scan stats
111  IntPtr statsPtr = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStatsPtr();
113  {
114  return "playspace stats query failed";
115  }
116 
117  // The stats tell us if we could potentially finish
118  if (DoesScanMeetMinBarForCompletion)
119  {
120  return "When ready, air tap to finalize your playspace";
121  }
122  return "Walk around and scan in your playspace";
123  case SpatialUnderstanding.ScanStates.Finishing:
124  return "Finalizing scan (please wait)";
126  return "Scan complete - Use the menu to run queries";
127  default:
128  return "ScanState = " + SpatialUnderstanding.Instance.ScanState.ToString();
129  }
130  }
131  return "";
132  }
133  }
134 
135  public Color PrimaryColor
136  {
137  get
138  {
140  {
141  if (trackedHandsCount > 0)
142  {
143  return DoesScanMeetMinBarForCompletion ? Color.green : Color.red;
144  }
145  return DoesScanMeetMinBarForCompletion ? Color.yellow : Color.white;
146  }
147 
148  // If we're looking at the menu, fade it out
149  Vector3 hitPos, hitNormal;
150  UnityEngine.UI.Button hitButton;
151  float alpha = AppCursor.RayCastUI(out hitPos, out hitNormal, out hitButton) ? 0.15f : 1.0f;
152 
153  // Special case processing &
154  return (!string.IsNullOrEmpty(SpaceQueryDescription) || !string.IsNullOrEmpty(ObjectPlacementDescription)) ?
155  (PrimaryText.Contains("processing") ? new Color(1.0f, 0.0f, 0.0f, 1.0f) : new Color(1.0f, 0.7f, 0.1f, alpha)) :
156  new Color(1.0f, 1.0f, 1.0f, alpha);
157  }
158  }
159 
160  public string DetailsText
161  {
162  get
163  {
165  {
166  return "";
167  }
168 
169  // Scanning stats get second priority
170  if ((SpatialUnderstanding.Instance.ScanState == SpatialUnderstanding.ScanStates.Scanning) &&
171  (SpatialUnderstanding.Instance.AllowSpatialUnderstanding))
172  {
173  IntPtr statsPtr = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStatsPtr();
175  {
176  return "Playspace stats query failed";
177  }
178  SpatialUnderstandingDll.Imports.PlayspaceStats stats = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStats();
179 
180  // Start showing the stats when they are no longer zero
181  if (stats.TotalSurfaceArea > kMinAreaForStats)
182  {
183  string subDisplayText = string.Format("totalArea={0:0.0}, horiz={1:0.0}, wall={2:0.0}", stats.TotalSurfaceArea, stats.HorizSurfaceArea, stats.WallSurfaceArea);
184  subDisplayText += string.Format("\nnumFloorCells={0}, numCeilingCells={1}, numPlatformCells={2}", stats.NumFloor, stats.NumCeiling, stats.NumPlatform);
185  subDisplayText += string.Format("\npaintMode={0}, seenCells={1}, notSeen={2}", stats.CellCount_IsPaintMode, stats.CellCount_IsSeenQualtiy_Seen + stats.CellCount_IsSeenQualtiy_Good, stats.CellCount_IsSeenQualtiy_None);
186  return subDisplayText;
187  }
188  return "";
189  }
190  return "";
191  }
192  }
193 
194  // Privates
195  private string spaceQueryDescription;
196  private string objectPlacementDescription;
197  private uint trackedHandsCount = 0;
198 #if UNITY_WSA || UNITY_STANDALONE_WIN
199  private KeywordRecognizer keywordRecognizer;
200 
201  // Functions
202  private void Start()
203  {
204  // Default the scene & the HoloToolkit objects to the camera
205  Vector3 sceneOrigin = CameraCache.Main.transform.position;
206  Parent_Scene.transform.position = sceneOrigin;
207  MappingObserver.SetObserverOrigin(sceneOrigin);
208  InputManager.Instance.AddGlobalListener(gameObject);
209 
210 
211  var keywordsToActions = new Dictionary<string, Action>
212  {
213  { "Toggle Scanned Mesh", ToggleScannedMesh },
214  { "Toggle Processed Mesh", ToggleProcessedMesh },
215  };
216 
217  keywordRecognizer = new KeywordRecognizer(keywordsToActions.Keys.ToArray());
218  keywordRecognizer.OnPhraseRecognized += args => keywordsToActions[args.text].Invoke();
219  keywordRecognizer.Start();
220  }
221 #endif
222 
223  protected override void OnDestroy()
224  {
225  InputManager.Instance.RemoveGlobalListener(gameObject);
226  }
227 
228  private void Update_DebugDisplay(float deltaTime)
229  {
230  // Basic checks
231  if (DebugDisplay == null)
232  {
233  return;
234  }
235 
236  // Update display text
237  DebugDisplay.text = PrimaryText;
238  DebugDisplay.color = PrimaryColor;
239  DebugSubDisplay.text = DetailsText;
240  }
241 
242  private void Update_KeyboardInput(float deltaTime)
243  {
244  // Toggle SurfaceMapping & CustomUnderstandingMesh visibility
245  if (Input.GetKeyDown(KeyCode.BackQuote) &&
246  (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift)))
247  {
248  ToggleScannedMesh();
249  }
250  else if (Input.GetKeyDown(KeyCode.BackQuote) &&
251  (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)))
252  {
253  ToggleProcessedMesh();
254  }
255  }
256 
257  private static void ToggleScannedMesh()
258  {
259  SpatialMappingManager.Instance.DrawVisualMeshes = !SpatialMappingManager.Instance.DrawVisualMeshes;
260  Debug.Log("SpatialUnderstanding -> SpatialMappingManager.Instance.DrawVisualMeshes=" + SpatialMappingManager.Instance.DrawVisualMeshes);
261  }
262 
263  private static void ToggleProcessedMesh()
264  {
265  SpatialUnderstanding.Instance.UnderstandingCustomMesh.DrawProcessedMesh = !SpatialUnderstanding.Instance.UnderstandingCustomMesh.DrawProcessedMesh;
266  Debug.Log("SpatialUnderstanding -> SpatialUnderstanding.Instance.UnderstandingCustomMesh.DrawProcessedMesh=" + SpatialUnderstanding.Instance.UnderstandingCustomMesh.DrawProcessedMesh);
267  }
268 
269  private void Update()
270  {
271  Update_DebugDisplay(Time.deltaTime);
272  Update_KeyboardInput(Time.deltaTime);
273  }
274 
275  public void OnSourceDetected(SourceStateEventData eventData)
276  {
277  // If the source has positional info and there is currently no visible source
278  if (eventData.InputSource.SupportsInputInfo(eventData.SourceId, SupportedInputInfo.GripPosition))
279  {
280  trackedHandsCount++;
281  }
282  }
283 
284  public void OnSourceLost(SourceStateEventData eventData)
285  {
286  if (eventData.InputSource.SupportsInputInfo(eventData.SourceId, SupportedInputInfo.GripPosition))
287  {
288  trackedHandsCount--;
289  }
290  }
291 
292  public void OnInputClicked(InputClickedEventData eventData)
293  {
294  if ((SpatialUnderstanding.Instance.ScanState == SpatialUnderstanding.ScanStates.Scanning) &&
295  !SpatialUnderstanding.Instance.ScanStatsReportStillWorking)
296  {
297  SpatialUnderstanding.Instance.RequestFinishScan();
298  }
299  }
300  }
301 }
override void OnDestroy()
Base OnDestroy method that destroys the Singleton&#39;s unique instance. Called by Unity when destroying ...
Definition: AppState.cs:223
Input Manager is responsible for managing input sources and dispatching relevant events to the approp...
Definition: InputManager.cs:19
static int QueryPlayspaceStats([In] IntPtr playspaceStats)
Query the playspace scan statistics.
uint SourceId
The id of the source the event is from, for instance the hand id.
The SpatialMappingObserver class encapsulates the SurfaceObserver into an easy to use object that han...
Encapsulates the primary DLL functions, including marshalling helper functions. The DLL functions are...
bool RayCastUI(out Vector3 hitPos, out Vector3 hitNormal, out Button hitButton)
SupportedInputInfo
Flags used to indicate which input information is supported by an input source.
void OnInputClicked(InputClickedEventData eventData)
Definition: AppState.cs:292
IInputSource InputSource
The source the input event originates from.
bool SetObserverOrigin(Vector3 origin)
Can be called to override the default origin for the observed volume. Can only be called while observ...
bool SupportsInputInfo(uint sourceId, SupportedInputInfo inputInfo)
Returns whether the input source supports the specified input info type.
Interface to implement to react to simple click input.
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
static T Instance
Returns the Singleton instance of the classes type. If no instance is found, then we search for an in...
Definition: Singleton.cs:26
static Camera Main
Returns a cached reference to the main camera and uses Camera.main if it hasn&#39;t been cached yet...
Definition: CameraCache.cs:20
void OnSourceDetected(SourceStateEventData eventData)
Definition: AppState.cs:275
Interface to implement to react to source state changes, such as when an input source is detected or ...
The SpatialMappingManager class allows applications to use a SurfaceObserver or a stored Spatial Mapp...
Describes an input event that involves a tap.
Describes an source state event that has a source id.
Playspace statistics for querying scanning progress
The SpatialUnderstanding class controls the state and flow of the scanning process used in the unders...
Singleton behaviour class, used for components that should only have one instance.
Definition: Singleton.cs:14