AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
PlaneFinding.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 System;
5 using System.Collections.Generic;
6 using System.Runtime.InteropServices;
7 using UnityEngine;
8 
9 namespace HoloToolkit.Unity.SpatialMapping
10 {
11  [StructLayout(LayoutKind.Sequential)]
12  public struct OrientedBoundingBox
13  {
14  public Vector3 Center;
15  public Vector3 Extents;
16  public Quaternion Rotation;
17  };
18 
19  [StructLayout(LayoutKind.Sequential)]
20  public struct BoundedPlane
21  {
22  public Plane Plane;
24  public float Area;
25 
29  public BoundedPlane(Transform xform)
30  {
31  Plane = new Plane(xform.forward, xform.position);
32  Bounds = new OrientedBoundingBox()
33  {
34  Center = xform.position,
35  Extents = xform.localScale / 2,
36  Rotation = xform.rotation
37  };
38  Area = Bounds.Extents.x * Bounds.Extents.y;
39  }
40  };
41 
42  public class PlaneFinding
43  {
44  #region Public APIs
45 
56  public struct MeshData
57  {
58  public Matrix4x4 Transform;
59  public Vector3[] Verts;
60  public Vector3[] Normals;
61  public Int32[] Indices;
62 
63  public MeshData(MeshFilter meshFilter)
64  {
65  Transform = meshFilter.transform.localToWorldMatrix;
66  Verts = meshFilter.sharedMesh.vertices;
67  Normals = meshFilter.sharedMesh.normals;
68  Indices = meshFilter.sharedMesh.triangles;
69  }
70  }
71 
87  public static BoundedPlane[] FindSubPlanes(List<MeshData> meshes, float snapToGravityThreshold = 0.0f)
88  {
89  StartPlaneFinding();
90 
91  try
92  {
93  int planeCount;
94  IntPtr planesPtr;
95  IntPtr pinnedMeshData = PinMeshDataForMarshalling(meshes);
96  DLLImports.FindSubPlanes(meshes.Count, pinnedMeshData, snapToGravityThreshold, out planeCount, out planesPtr);
97  return MarshalBoundedPlanesFromIntPtr(planesPtr, planeCount);
98  }
99  finally
100  {
101  FinishPlaneFinding();
102  }
103  }
104 
125  public static BoundedPlane[] MergeSubPlanes(BoundedPlane[] subPlanes, float snapToGravityThreshold = 0.0f, float minArea = 0.0f)
126  {
127  StartPlaneFinding();
128 
129  try
130  {
131  int planeCount;
132  IntPtr planesPtr;
133  DLLImports.MergeSubPlanes(subPlanes.Length, PinObject(subPlanes), minArea, snapToGravityThreshold, out planeCount, out planesPtr);
134  return MarshalBoundedPlanesFromIntPtr(planesPtr, planeCount);
135  }
136  finally
137  {
138  FinishPlaneFinding();
139  }
140  }
141 
161  public static BoundedPlane[] FindPlanes(List<MeshData> meshes, float snapToGravityThreshold = 0.0f, float minArea = 0.0f)
162  {
163  StartPlaneFinding();
164 
165  try
166  {
167  int planeCount;
168  IntPtr planesPtr;
169  IntPtr pinnedMeshData = PinMeshDataForMarshalling(meshes);
170  DLLImports.FindPlanes(meshes.Count, pinnedMeshData, minArea, snapToGravityThreshold, out planeCount, out planesPtr);
171  return MarshalBoundedPlanesFromIntPtr(planesPtr, planeCount);
172  }
173  finally
174  {
175  FinishPlaneFinding();
176  }
177  }
178 
179  #endregion
180 
181  #region Internal
182 
183  private static bool findPlanesRunning = false;
184  private static System.Object findPlanesLock = new System.Object();
185  private static DLLImports.ImportedMeshData[] reusedImportedMeshesForMarshalling;
186  private static List<GCHandle> reusedPinnedMemoryHandles = new List<GCHandle>();
187 
194  private static void StartPlaneFinding()
195  {
196  lock (findPlanesLock)
197  {
198  if (findPlanesRunning)
199  {
200  throw new Exception("PlaneFinding is already running. You can not call these APIs from multiple threads.");
201  }
202  findPlanesRunning = true;
203  }
204  }
205 
210  private static void FinishPlaneFinding()
211  {
212  UnpinAllObjects();
213  findPlanesRunning = false;
214  }
215 
221  private static IntPtr PinObject(System.Object obj)
222  {
223  GCHandle h = GCHandle.Alloc(obj, GCHandleType.Pinned);
224  reusedPinnedMemoryHandles.Add(h);
225  return h.AddrOfPinnedObject();
226  }
227 
231  private static void UnpinAllObjects()
232  {
233  for (int i = 0; i < reusedPinnedMemoryHandles.Count; ++i)
234  {
235  reusedPinnedMemoryHandles[i].Free();
236  }
237  reusedPinnedMemoryHandles.Clear();
238  }
239 
246  private static IntPtr PinMeshDataForMarshalling(List<MeshData> meshes)
247  {
248  // if we have a big enough array reuse it, otherwise create new
249  if (reusedImportedMeshesForMarshalling == null || reusedImportedMeshesForMarshalling.Length < meshes.Count)
250  {
251  reusedImportedMeshesForMarshalling = new DLLImports.ImportedMeshData[meshes.Count];
252  }
253 
254  for (int i = 0; i < meshes.Count; ++i)
255  {
256  reusedImportedMeshesForMarshalling[i] = new DLLImports.ImportedMeshData
257  {
258  transform = meshes[i].Transform,
259  vertCount = meshes[i].Verts.Length,
260  indexCount = meshes[i].Indices.Length,
261  verts = PinObject(meshes[i].Verts),
262  normals = PinObject(meshes[i].Normals),
263  indices = PinObject(meshes[i].Indices),
264  };
265  }
266 
267  return PinObject(reusedImportedMeshesForMarshalling);
268  }
269 
276  private static BoundedPlane[] MarshalBoundedPlanesFromIntPtr(IntPtr outArray, int size)
277  {
278  BoundedPlane[] resArray = new BoundedPlane[size];
279 #pragma warning disable 618
280  int structsize = Marshal.SizeOf(typeof(BoundedPlane));
281 #pragma warning restore 618
282  IntPtr current = outArray;
283  for (int i = 0; i < size; i++)
284  {
285 #pragma warning disable 618
286  resArray[i] = (BoundedPlane)Marshal.PtrToStructure(current, typeof(BoundedPlane));
287 #pragma warning restore 618
288  current = (IntPtr)((long)current + structsize);
289  }
290  Marshal.FreeCoTaskMem(outArray);
291  return resArray;
292  }
293 
297  private class DLLImports
298  {
299  [StructLayout(LayoutKind.Sequential)]
300  public struct ImportedMeshData
301  {
302  public Matrix4x4 transform;
303  public Int32 vertCount;
304  public Int32 indexCount;
305  public IntPtr verts;
306  public IntPtr normals;
307  public IntPtr indices;
308  };
309 
310  [DllImport("PlaneFinding")]
311  public static extern void FindPlanes(
312  [In] int meshCount,
313  [In] IntPtr meshes,
314  [In] float minArea,
315  [In] float snapToGravityThreshold,
316  [Out] out int planeCount,
317  [Out] out IntPtr planesPtr);
318 
319  [DllImport("PlaneFinding")]
320  public static extern void FindSubPlanes(
321  [In] int meshCount,
322  [In] IntPtr meshes,
323  [In] float snapToGravityThreshold,
324  [Out] out int planeCount,
325  [Out] out IntPtr planesPtr);
326 
327  [DllImport("PlaneFinding")]
328  public static extern void MergeSubPlanes(
329  [In] int subPlaneCount,
330  [In] IntPtr subPlanes,
331  [In] float minArea,
332  [In] float snapToGravityThreshold,
333  [Out] out int planeCount,
334  [Out] out IntPtr planesPtr);
335  }
336 
337  #endregion
338  }
339 }
BoundedPlane(Transform xform)
Builds the bounded plane to match the obb defined by xform
Definition: PlaneFinding.cs:29
static BoundedPlane [] FindSubPlanes(List< MeshData > meshes, float snapToGravityThreshold=0.0f)
Finds small planar patches that are contained within individual meshes. The output of this API can th...
Definition: PlaneFinding.cs:87
static BoundedPlane [] FindPlanes(List< MeshData > meshes, float snapToGravityThreshold=0.0f, float minArea=0.0f)
Convenience wrapper that executes FindSubPlanes followed by MergeSubPlanes via a single call into nat...
PlaneFinding is an expensive task that should not be run from Unity&#39;s main thread as it will stall th...
Definition: PlaneFinding.cs:56
static BoundedPlane [] MergeSubPlanes(BoundedPlane[] subPlanes, float snapToGravityThreshold=0.0f, float minArea=0.0f)
Takes the subplanes returned by one or more previous calls to FindSubPlanes() and merges them togethe...