The SurfacePlane class is used by SurfaceMeshesToPlanes to create different types of planes (walls, floors, tables, etc.) based on the Spatial Mapping data returned by the SpatialMappingManager's source. This script should be a component on the SufacePlane prefab, which is used by SurfaceMeshesToPlanes.
Inheritance: UnityEngine.MonoBehaviour
    public void GenerateLevel()
    {
        List <GameObject> tables = GetTablesInDescendingAreaOrder();

        Debug.Log("GenerateLevel(): number of tables=" + tables.Capacity.ToString());
        //TODO: check if empty and take corrective action
        if (tables.Capacity == 0)
        {
            // For now, place a big ugly gray cube if no tables found

            /*
             * GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
             * cube.transform.parent = gameObject.transform; // level manager will be parent
             * cube.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
             * cube.transform.position = new Vector3(0, 0, 2);
             * cube.GetComponent<Renderer>().material = m_flat_material;
             * cube.GetComponent<Renderer>().material.color = Color.grey;
             * cube.SetActive(true);
             */
            return;
        }
        // Until we develop some real assets, just place cubes :)
        HoloToolkit.Unity.SurfacePlane city_plane = tables[0].GetComponent <HoloToolkit.Unity.SurfacePlane>();
        Debug.Log("up=" + city_plane.transform.up.ToString("F2"));
        Debug.Log("forward=" + city_plane.transform.forward.ToString("F2"));
        Debug.Log("right=" + city_plane.transform.right.ToString("F2"));
        Debug.Log("normal=" + city_plane.Plane.Plane.normal.ToString("F2"));
        PlaceCube(0.25f, 0.75f, 0.25f, m_flat_material, Color.red, city_plane, -0.25f + 0.0f, 0.1f);
        PlaceCube(0.25f, 0.30f, 0.25f, m_flat_material, Color.green, city_plane, -0.50f - 0.1f, 0.1f);
        PlaceCube(0.25f, 0.40f, 0.25f, m_flat_material, Color.blue, city_plane, 0.0f + 0.1f, 0.25f + 0.1f);
    }
        /// <summary>
        /// Gets all active planes of the specified type(s).
        /// </summary>
        /// <param name="planeTypes">A flag which includes all plane type(s) that should be returned.</param>
        /// <returns>A collection of planes that match the expected type(s).</returns>
        public List <GameObject> GetActivePlanes(PlaneTypes planeTypes)
        {
            List <GameObject> typePlanes = new List <GameObject>();

            foreach (GameObject plane in ActivePlanes)
            {
                SurfacePlane surfacePlane = plane.GetComponent <SurfacePlane>();

                if (surfacePlane != null)
                {
                    if ((planeTypes & surfacePlane.PlaneType) == surfacePlane.PlaneType)
                    {
                        typePlanes.Add(plane);
                    }
                }
            }

            return(typePlanes);
        }
 /// <summary>
 /// Sets visibility of planes based on their type.
 /// </summary>
 /// <param name="surfacePlane"></param>
 private void SetPlaneVisibility(SurfacePlane surfacePlane)
 {
     surfacePlane.IsVisible = ((drawPlanesMask & surfacePlane.PlaneType) == surfacePlane.PlaneType);
 }
        /// <summary>
        /// Iterator block, analyzes surface meshes to find planes and create new 3D cubes to represent each plane.
        /// </summary>
        /// <returns>Yield result.</returns>
        private IEnumerator MakePlanesRoutine()
        {
            // Remove any previously existing planes, as they may no longer be valid.
            for (int index = 0; index < ActivePlanes.Count; index++)
            {
                Destroy(ActivePlanes[index]);
            }

            // Pause our work, and continue on the next frame.
            yield return(null);

            float start = Time.realtimeSinceStartup;

            ActivePlanes.Clear();

            // Get the latest Mesh data from the Spatial Mapping Manager.
            List <PlaneFinding.MeshData> meshData = new List <PlaneFinding.MeshData>();
            List <MeshFilter>            filters  = SpatialMappingManager.Instance.GetMeshFilters();

            for (int index = 0; index < filters.Count; index++)
            {
                MeshFilter filter = filters[index];
                if (filter != null && filter.sharedMesh != null)
                {
                    // fix surface mesh normals so we can get correct plane orientation.
                    filter.mesh.RecalculateNormals();
                    meshData.Add(new PlaneFinding.MeshData(filter));
                }

                if ((Time.realtimeSinceStartup - start) > FrameTime)
                {
                    // Pause our work, and continue to make more PlaneFinding objects on the next frame.
                    yield return(null);

                    start = Time.realtimeSinceStartup;
                }
            }

            // Pause our work, and continue on the next frame.
            yield return(null);

#if !UNITY_EDITOR && UNITY_METRO
            // When not in the unity editor we can use a cool background task to help manage FindPlanes().
            Task <BoundedPlane[]> planeTask = Task.Run(() => PlaneFinding.FindPlanes(meshData, snapToGravityThreshold, MinArea));

            while (planeTask.IsCompleted == false)
            {
                yield return(null);
            }

            BoundedPlane[] planes = planeTask.Result;
#else
            // In the unity editor, the task class isn't available, but perf is usually good, so we'll just wait for FindPlanes to complete.
            BoundedPlane[] planes = PlaneFinding.FindPlanes(meshData, snapToGravityThreshold, MinArea);
#endif

            // Pause our work here, and continue on the next frame.
            yield return(null);

            start = Time.realtimeSinceStartup;

            float maxFloorArea   = 0.0f;
            float maxCeilingArea = 0.0f;
            FloorYPosition   = 0.0f;
            CeilingYPosition = 0.0f;
            float upNormalThreshold = 0.9f;

            if (SurfacePlanePrefab != null && SurfacePlanePrefab.GetComponent <SurfacePlane>() != null)
            {
                upNormalThreshold = SurfacePlanePrefab.GetComponent <SurfacePlane>().UpNormalThreshold;
            }

            // Find the floor and ceiling.
            // We classify the floor as the maximum horizontal surface below the user's head.
            // We classify the ceiling as the maximum horizontal surface above the user's head.
            for (int i = 0; i < planes.Length; i++)
            {
                BoundedPlane boundedPlane = planes[i];
                if (boundedPlane.Bounds.Center.y < 0 && boundedPlane.Plane.normal.y >= upNormalThreshold)
                {
                    maxFloorArea = Mathf.Max(maxFloorArea, boundedPlane.Area);
                    if (maxFloorArea == boundedPlane.Area)
                    {
                        FloorYPosition = boundedPlane.Bounds.Center.y;
                    }
                }
                else if (boundedPlane.Bounds.Center.y > 0 && boundedPlane.Plane.normal.y <= -(upNormalThreshold))
                {
                    maxCeilingArea = Mathf.Max(maxCeilingArea, boundedPlane.Area);
                    if (maxCeilingArea == boundedPlane.Area)
                    {
                        CeilingYPosition = boundedPlane.Bounds.Center.y;
                    }
                }
            }

            // Create SurfacePlane objects to represent each plane found in the Spatial Mapping mesh.
            for (int index = 0; index < planes.Length; index++)
            {
                GameObject   destPlane;
                BoundedPlane boundedPlane = planes[index];

                // Instantiate a SurfacePlane object, which will have the same bounds as our BoundedPlane object.
                if (SurfacePlanePrefab != null && SurfacePlanePrefab.GetComponent <SurfacePlane>() != null)
                {
                    destPlane = Instantiate(SurfacePlanePrefab);
                }
                else
                {
                    destPlane = GameObject.CreatePrimitive(PrimitiveType.Cube);
                    destPlane.AddComponent <SurfacePlane>();
                    destPlane.GetComponent <Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
                }

                destPlane.transform.parent = planesParent.transform;
                SurfacePlane surfacePlane = destPlane.GetComponent <SurfacePlane>();

                // Set the Plane property to adjust transform position/scale/rotation and determine plane type.
                surfacePlane.Plane = boundedPlane;

                SetPlaneVisibility(surfacePlane);

                if ((destroyPlanesMask & surfacePlane.PlaneType) == surfacePlane.PlaneType)
                {
                    DestroyImmediate(destPlane);
                }
                else
                {
                    // Set the plane to use the same layer as the SpatialMapping mesh.
                    destPlane.layer = SpatialMappingManager.Instance.PhysicsLayer;
                    ActivePlanes.Add(destPlane);
                }

                // If too much time has passed, we need to return control to the main game loop.
                if ((Time.realtimeSinceStartup - start) > FrameTime)
                {
                    // Pause our work here, and continue making additional planes on the next frame.
                    yield return(null);

                    start = Time.realtimeSinceStartup;
                }
            }

            Debug.Log("Finished making planes.");

            // We are done creating planes, trigger an event.
            EventHandler handler = MakePlanesComplete;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }

            makingPlanes = false;
        }
    private void PlaceCube(float width, float height, float depth, Material material, Color color, HoloToolkit.Unity.SurfacePlane plane, float local_x, float local_z)
    {
        //
        // Plane coordinate system is different from Unity world convention:
        //  x,y (right,up) -> plane surface
        //  z (forward)    -> perpendicular to plane surface
        // To further add to confusion, the forward direction is not necessarily
        // the same as the normal, and can be its inverse. We must test for this
        // situation and rotate 180 degrees about (local) x, y.
        //

        // World xz -> plane xy
        float x      = local_x;
        float y      = local_z;
        float size_x = width;
        float size_y = depth;
        float size_z = height;

        // Construct rotation from plane to world space
        Vector3    origin   = plane.transform.position;
        Quaternion rotation = plane.transform.rotation;

        if (plane.transform.forward.y < 0) // plane is oriented upside down
        {
            rotation = Quaternion.LookRotation(-plane.transform.forward, plane.transform.up);
        }

        // Place object in plane-local coordinate system; rotate to world system
        GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

        cube.transform.parent                         = gameObject.transform; // level manager will be parent
        cube.transform.localScale                     = new Vector3(size_x, size_y, size_z);
        cube.transform.position                       = origin + rotation * new Vector3(x, y, 0.5f * size_z);
        cube.transform.transform.rotation             = rotation;
        cube.GetComponent <Renderer>().material       = material;
        cube.GetComponent <Renderer>().material.color = color; // equivalent to SetColor("_Color", color)
        cube.SetActive(true);
    }