AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
SpaceVisualizer.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;
5 using System;
6 using System.Collections.Generic;
7 using UnityEngine;
8 
9 namespace HoloToolkit.Examples.SpatialUnderstandingFeatureOverview
10 {
11  public class SpaceVisualizer : LineDrawer
12  {
13  // Singleton
14  public static SpaceVisualizer Instance;
15 
16  // Consts
17  const int QueryResultMaxCount = 512;
18  const int DisplayResultMaxCount = 32;
19 
20  // Privates
21  private List<AnimatedBox> lineBoxList = new List<AnimatedBox>();
22  private SpatialUnderstandingDllTopology.TopologyResult[] resultsTopology = new SpatialUnderstandingDllTopology.TopologyResult[QueryResultMaxCount];
23  private SpatialUnderstandingDllShapes.ShapeResult[] resultsShape = new SpatialUnderstandingDllShapes.ShapeResult[QueryResultMaxCount];
24 
25  // Functions
26  private void Awake()
27  {
28  Instance = this;
29  }
30 
31  public void ClearGeometry(bool clearAll = true)
32  {
33  lineBoxList = new List<AnimatedBox>();
34  AppState.Instance.SpaceQueryDescription = "";
35 
36  if (clearAll && (LevelSolver.Instance != null))
37  {
39  }
40  }
41 
43  {
44  // First clear all our geo
45  ClearGeometry();
46 
47  // Only if we're enabled
48  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
49  {
50  return;
51  }
52 
53  // Alignment information
54  SpatialUnderstandingDll.Imports.QueryPlayspaceAlignment(SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceAlignmentPtr());
55  SpatialUnderstandingDll.Imports.PlayspaceAlignment alignment = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceAlignment();
56 
57  // Box for the space
58  float timeDelay = (float)lineBoxList.Count * AnimatedBox.DelayPerItem;
59  lineBoxList.Add(
60  new AnimatedBox(
61  timeDelay,
62  new Vector3(alignment.Center.x, (alignment.CeilingYValue + alignment.FloorYValue) * 0.5f, alignment.Center.z),
63  Quaternion.LookRotation(alignment.BasisZ, alignment.BasisY),
64  Color.magenta,
65  new Vector3(alignment.HalfDims.x, (alignment.CeilingYValue - alignment.FloorYValue) * 0.5f, alignment.HalfDims.z))
66  );
67  AppState.Instance.SpaceQueryDescription = "Playspace Alignment OBB";
68  }
69 
71  {
72  ClearGeometry();
73 
74  // Only if we're enabled
75  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
76  {
77  return;
78  }
79 
80  // Setup
81  float minHeightOfWallSpace = 0.5f;
82  float minWidthOfWallSpace = 0.75f;
83  float minHeightAboveFloor = 1.25f;
84  float minFacingClearance = 1.5f;
85 
86  // Query
87  IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
89  minHeightOfWallSpace, minWidthOfWallSpace, minHeightAboveFloor, minFacingClearance,
90  resultsTopology.Length, resultsTopologyPtr);
91 
92  // Output
93  HandleResults_Topology("Find Position On Wall", locationCount, new Vector3(minWidthOfWallSpace, minHeightOfWallSpace, 0.025f), Color.blue);
94  }
95 
97  {
98  // Setup
99  float minHeightOfWallSpace = 1.0f;
100  float minWidthOfWallSpace = 1.5f;
101  float minHeightAboveFloor = 1.5f;
102  float minFacingClearance = 0.5f;
103 
104  // Only if we're enabled
105  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
106  {
107  return;
108  }
109 
110  // Query
111  IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
113  minHeightOfWallSpace, minWidthOfWallSpace, minHeightAboveFloor, minFacingClearance,
114  resultsTopology.Length, resultsTopologyPtr);
115 
116  // Output
117  HandleResults_Topology("Find Large Positions On Walls", locationCount, new Vector3(minWidthOfWallSpace, minHeightOfWallSpace, 0.025f), Color.yellow);
118  }
119 
121  {
122  ClearGeometry();
123 
124  // Only if we're enabled
125  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
126  {
127  return;
128  }
129 
130  // Query
131  IntPtr wallPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
133  wallPtr);
134  if (wallCount == 0)
135  {
136  AppState.Instance.SpaceQueryDescription = "Find Largest Wall (0)";
137  return;
138  }
139 
140  // Add the line boxes
141  float timeDelay = (float)lineBoxList.Count * AnimatedBox.DelayPerItem;
142  lineBoxList.Add(
143  new AnimatedBox(
144  timeDelay,
145  resultsTopology[0].position,
146  Quaternion.LookRotation(resultsTopology[0].normal, Vector3.up),
147  Color.magenta,
148  new Vector3(resultsTopology[0].width, resultsTopology[0].length, 0.05f) * 0.5f)
149  );
150  AppState.Instance.SpaceQueryDescription = "Find Largest Wall (1)";
151  }
152 
154  {
155  // Setup
156  float minWidthOfWallSpace = 1.0f;
157  float minHeightAboveFloor = 1.0f;
158 
159  // Only if we're enabled
160  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
161  {
162  return;
163  }
164 
165  // Query
166  IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
168  minWidthOfWallSpace, minHeightAboveFloor,
169  resultsTopology.Length, resultsTopologyPtr);
170 
171  // Output
172  HandleResults_Topology("Find Positions On Floor", locationCount, new Vector3(minWidthOfWallSpace, 0.025f, minHeightAboveFloor), Color.red);
173  }
174 
176  {
177  // Query
178  IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
180  resultsTopology.Length, resultsTopologyPtr);
181 
182  // Output
183  HandleResults_Topology("Find Largest Positions On Floor", locationCount, new Vector3(1.0f, 1.0f, 0.025f), Color.yellow);
184  }
185 
187  {
188  // Setup
189  float minHeight = 0.125f;
190  float maxHeight = 1.0f;
191  float minFacingClearance = 1.0f;
192 
193  // Only if we're enabled
194  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
195  {
196  return;
197  }
198 
199  // Query
200  IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
202  minHeight, maxHeight, minFacingClearance,
203  resultsTopology.Length, resultsTopologyPtr);
204 
205  // Output
206  HandleResults_Topology("Find Placeable Positions", locationCount, new Vector3(0.25f, 0.025f, 0.25f), Color.cyan);
207  }
208 
210  {
211  // Setup
212  float minHeight = 0.125f;
213  float maxHeight = 2.0f;
214  float minFacingClearance = 1.0f;
215  float minWidth = .5f;
216 
217  // Only if we're enabled
218  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
219  {
220  return;
221  }
222 
223  // Query
224  IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
226  minHeight, maxHeight, minFacingClearance, minWidth,
227  resultsTopology.Length, resultsTopologyPtr);
228 
229  // Output
230  HandleResults_Topology("Find Large Sittable Positions", locationCount, new Vector3(minWidth, 0.025f, minWidth), Color.cyan);
231  }
232 
233  public void Query_Shape_FindPositionsOnShape(string shapeName)
234  {
235  // Setup
236  float minRadius = 0.1f;
237 
238  // Only if we're enabled
239  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
240  {
241  return;
242  }
243 
244  // Query
245  IntPtr resultsShapePtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsShape);
247  shapeName, minRadius,
248  resultsShape.Length, resultsShapePtr);
249 
250  // Output
251  HandleResults_Shape("Find Positions on Shape '" + shapeName + "'", shapeCount, Color.cyan, new Vector3(0.1f, 0.025f, 0.1f));
252  }
253 
254  public void Query_Shape_FindShapeHalfDims(string shapeName)
255  {
256  // Only if we're enabled
257  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
258  {
259  return;
260  }
261 
262  // Query
263  IntPtr resultsShapePtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsShape);
265  shapeName,
266  resultsShape.Length, resultsShapePtr);
267 
268  // Output
269  HandleResults_Shape("Find Shape Min/Max '" + shapeName + "'", shapeCount, Color.blue, new Vector3(0.25f, 0.025f, 0.25f));
270  }
271 
272  private void HandleResults_Topology(string visDesc, int locationCount, Vector3 boxFullDims, Color color)
273  {
274  // First clear all our geo
275  ClearGeometry();
276 
277  // Only if we're enabled
278  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
279  {
280  return;
281  }
282 
283  // Add the line boxes (we may have more results than boxes - pick evenly across the results in that case)
284  int lineInc = Mathf.CeilToInt((float)locationCount / (float)DisplayResultMaxCount);
285  int boxesDisplayed = 0;
286  for (int i = 0; i < locationCount; i += lineInc)
287  {
288  float timeDelay = (float)lineBoxList.Count * AnimatedBox.DelayPerItem;
289  lineBoxList.Add(
290  new AnimatedBox(
291  timeDelay,
292  resultsTopology[i].position,
293  Quaternion.LookRotation(resultsTopology[i].normal, Vector3.up),
294  Color.blue,
295  boxFullDims * 0.5f)
296  );
297  ++boxesDisplayed;
298  }
299 
300  // Vis description
301  if (locationCount == boxesDisplayed)
302  {
303  AppState.Instance.SpaceQueryDescription = string.Format("{0} ({1})", visDesc, locationCount);
304  }
305  else
306  {
307  AppState.Instance.SpaceQueryDescription = string.Format("{0} (found={1}, displayed={2})", visDesc, locationCount, boxesDisplayed);
308  }
309  }
310 
311  private void HandleResults_Shape(string visDesc, int shapeCount, Color color, Vector3 defaultHalfDims)
312  {
313  // First clear all our geo
314  ClearGeometry();
315 
316  // Only if we're enabled
317  if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
318  {
319  return;
320  }
321 
322  // Alignment information
323  SpatialUnderstandingDll.Imports.QueryPlayspaceAlignment(SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceAlignmentPtr());
324  SpatialUnderstandingDll.Imports.PlayspaceAlignment alignment = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceAlignment();
325 
326  // Add the line boxes (we may have more results than boxes - pick evenly across the results in that case)
327  int lineInc = Mathf.CeilToInt((float)shapeCount / (float)DisplayResultMaxCount);
328  int boxesDisplayed = 0;
329  for (int i = 0; i < shapeCount; i += lineInc)
330  {
331  float timeDelay = (float)lineBoxList.Count * AnimatedBox.DelayPerItem;
332  lineBoxList.Add(
333  new AnimatedBox(
334  timeDelay,
335  resultsShape[i].position,
336  Quaternion.LookRotation(alignment.BasisZ, alignment.BasisY),
337  Color.blue,
338  (resultsShape[i].halfDims.sqrMagnitude < 0.01f) ? defaultHalfDims : resultsShape[i].halfDims)
339  );
340  ++boxesDisplayed;
341  }
342 
343  // Vis description
344  if (shapeCount == boxesDisplayed)
345  {
346  AppState.Instance.SpaceQueryDescription = string.Format("{0} ({1})", visDesc, shapeCount);
347  }
348  else
349  {
350  AppState.Instance.SpaceQueryDescription = string.Format("{0} (found={1}, displayed={2})", visDesc, shapeCount, boxesDisplayed);
351  }
352  }
353 
354  private bool Draw_LineBoxList()
355  {
356  bool needsUpdate = false;
357  for (int i = 0; i < lineBoxList.Count; ++i)
358  {
359  needsUpdate |= Draw_AnimatedBox(lineBoxList[i]);
360  }
361  return needsUpdate;
362  }
363 
364  private void Update_Queries()
365  {
366  // Queries - basics
367  if (Input.GetKeyDown(KeyCode.Escape))
368  {
369  ClearGeometry();
370  }
371  if (Input.GetKeyDown(KeyCode.F))
372  {
373  Query_PlayspaceAlignment();
374  }
375 
376  // Queries - topology
377  if (Input.GetKeyDown(KeyCode.G))
378  {
379  Query_Topology_FindPositionOnWall();
380  }
381  if (Input.GetKeyDown(KeyCode.H))
382  {
383  Query_Topology_FindLargePositionsOnWalls();
384  }
385  if (Input.GetKeyDown(KeyCode.J))
386  {
387  Query_Topology_FindLargeWall();
388  }
389  if (Input.GetKeyDown(KeyCode.K))
390  {
391  Query_Topology_FindPositionsOnFloor();
392  }
393  if (Input.GetKeyDown(KeyCode.L))
394  {
395  Query_Topology_FindLargestPositionsOnFloor();
396  }
397  if (Input.GetKeyDown(KeyCode.Semicolon))
398  {
399  Query_Topology_FindPositionsPlaceable();
400  }
401 
402  // Queries - shapes
403  if (Input.GetKeyDown(KeyCode.Quote))
404  {
405  Query_Shape_FindShapeHalfDims("All Surfaces");
406  }
407  if (Input.GetKeyDown(KeyCode.Z))
408  {
409  Query_Shape_FindPositionsOnShape("Sittable");
410  }
411  if (Input.GetKeyDown(KeyCode.X))
412  {
413  Query_Shape_FindShapeHalfDims("Chair");
414  }
415  if (Input.GetKeyDown(KeyCode.C))
416  {
417  Query_Shape_FindShapeHalfDims("Large Surface");
418  }
419  if (Input.GetKeyDown(KeyCode.V))
420  {
421  Query_Shape_FindShapeHalfDims("Large Empty Surface");
422  }
423  if (Input.GetKeyDown(KeyCode.B))
424  {
425  Query_Shape_FindShapeHalfDims("Couch");
426  }
427  }
428 
429  private void Update()
430  {
431  // Queries
433  {
434  Update_Queries();
435  }
436 
437  // Lines: Begin
438  LineDraw_Begin();
439 
440  // Drawers
441  bool needsUpdate = false;
442  needsUpdate |= Draw_LineBoxList();
443 
444  // Lines: Finish up
445  LineDraw_End(needsUpdate);
446  }
447  }
448 }
static int QueryTopology_FindPositionsOnWalls([In] float minHeightOfWallSpace, [In] float minWidthOfWallSpace, [In] float minHeightAboveFloor, [In] float minFacingClearance, [In] int locationCount, [In, Out] IntPtr locationData)
Finds spaces on walls meeting the criteria specified by the parameters.
static int QueryTopology_FindLargestPositionsOnFloor([In] int locationCount, [In, Out] IntPtr locationData)
Finds the largest spaces on the floor
Encapsulates the primary DLL functions, including marshalling helper functions. The DLL functions are...
static int QueryTopology_FindLargePositionsOnWalls([In] float minHeightOfWallSpace, [In] float minWidthOfWallSpace, [In] float minHeightAboveFloor, [In] float minFacingClearance, [In] int locationCount, [In, Out] IntPtr locationData)
Finds only large spaces on walls meeting the criteria specified by the parameters.
static int QueryTopology_FindLargePositionsSittable([In] float minHeight, [In] float maxHeight, [In] float minFacingClearance, [In] float minWidth, [In] int locationCount, [In, Out] IntPtr locationData)
Finds only large spaces on platforms meeting the criteria specified by the parameters.
static int QueryShape_FindShapeHalfDims([In, MarshalAs(UnmanagedType.LPStr)] string shapeName, [In] int shapeCount, [In, Out] IntPtr shapeData)
Finds the set of found shapes of the type specified by shapeName. Returns the bounding rectangle&#39;s ha...
Playspace alignment results. Reports internal alignment of room in Unity space and basic alignment of...
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
Encapsulates the topology queries of the understanding DLL. These queries will not be valid until aft...
static int QueryTopology_FindPositionsOnFloor([In] float minLengthOfFloorSpace, [In] float minWidthOfFloorSpace, [In] int locationCount, [In, Out] IntPtr locationData)
Finds spaces on the floor meeting the criteria specified by the parameters.
static int QueryShape_FindPositionsOnShape([In, MarshalAs(UnmanagedType.LPStr)] string shapeName, [In] float minRadius, [In] int shapeCount, [In, Out] IntPtr shapeData)
Finds the set of available positions on the set of found shapes of the type specified by shapeName...
Encapsulates the shape detection queries of the understanding DLL. Shapes are defined by the user wit...
static int QueryTopology_FindPositionsSittable([In] float minHeight, [In] float maxHeight, [In] float minFacingClearance, [In] int locationCount, [In, Out] IntPtr locationData)
Finds good spaces for sitting or placing objects on surfaces.
Result of a topology query. Typically results return an array of these structures.
The SpatialUnderstanding class controls the state and flow of the scanning process used in the unders...
static int QueryPlayspaceAlignment([In] IntPtr playspaceAlignment)
Query the playspace alignment data. This will not be valid until after scanning is finalized...
static int QueryTopology_FindLargestWall([In, Out] IntPtr wall)
Finds the largest wall