Newer
Older
HoloAnatomy / Assets / HoloToolkit-Examples / SpatialMapping / Scripts / PlaneFindingTest.cs
SURFACEBOOK2\jackwynne on 25 May 2018 6 KB v1
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using UnityEngine;
using System.Collections.Generic;

namespace HoloToolkit.Unity.SpatialMapping.Tests
{
    /// <summary>
    /// Attach this component to a GameObject that contains some meshes (i.e.: the FakeSpatialMappingMesh.fbx).
    /// When running in the Unity editor, the planes are then visualized via editor gizmos.  You can then
    /// play with the API parameters in real-time to see how the impact the plane finding algorithm.
    /// </summary>
    public class PlaneFindingTest : MonoBehaviour
    {
        [Range(0, 45)]
        public float SnapToGravityThreshold = 0.0f;

        [Range(0, 10)]
        public float MinArea = 1.0f;

        public bool VisualizeSubPlanes = false;

        private List<PlaneFinding.MeshData> meshData = new List<PlaneFinding.MeshData>();
        private BoundedPlane[] planes;

        private void Update()
        {
            // Grab the necessary mesh data from the current set of surfaces that we want to run
            // PlaneFinding against.  This must be done on the main UI thread.
            meshData.Clear();
            foreach (MeshFilter mesh in GetComponentsInChildren<MeshFilter>())
            {
                meshData.Add(new PlaneFinding.MeshData(mesh));
            }

            // Now call FindPlanes().  NOTE: In a real application, this MUST be executed on a
            // background thread (i.e.: via ThreadPool.QueueUserWorkItem) so that it doesn't stall the
            // rendering thread while running plane finding.  Maintaining a solid 60fps is crucial
            // to a good user experience.
            planes = (VisualizeSubPlanes) ?
                PlaneFinding.FindSubPlanes(meshData, SnapToGravityThreshold) :
                PlaneFinding.FindPlanes(meshData, SnapToGravityThreshold, MinArea);
        }

        private static Color[] colors = new Color[] { Color.blue, Color.cyan, Color.green, Color.magenta, Color.red, Color.white, Color.yellow };
        private void OnDrawGizmos()
        {
            if (planes != null)
            {
                for (int i = 0; i < planes.Length; ++i)
                {
                    Vector3 center = planes[i].Bounds.Center;
                    Quaternion rotation = planes[i].Bounds.Rotation;
                    Vector3 extents = planes[i].Bounds.Extents;
                    Vector3 normal = planes[i].Plane.normal;
                    center -= planes[i].Plane.GetDistanceToPoint(center) * normal;

                    Vector3[] corners = new Vector3[4] {
                    center + rotation * new Vector3(+extents.x, +extents.y, 0),
                    center + rotation * new Vector3(-extents.x, +extents.y, 0),
                    center + rotation * new Vector3(-extents.x, -extents.y, 0),
                    center + rotation * new Vector3(+extents.x, -extents.y, 0)
                };

                    Color color = colors[i % colors.Length];

                    Gizmos.color = color;
                    Gizmos.DrawLine(corners[0], corners[1]);
                    Gizmos.DrawLine(corners[0], corners[2]);
                    Gizmos.DrawLine(corners[0], corners[3]);
                    Gizmos.DrawLine(corners[1], corners[2]);
                    Gizmos.DrawLine(corners[1], corners[3]);
                    Gizmos.DrawLine(corners[2], corners[3]);
                    Gizmos.DrawLine(center, center + normal * 0.4f);
                }
            }
        }

#if UNITY_EDITOR
        // This relies on helper functionality from the UnityEditor.Handles class, so make it UNITY_EDITOR only
        private void OnDrawGizmosSelected()
        {
            if (planes != null)
            {
                Ray cameraForward = new Ray(Camera.current.transform.position, Camera.current.transform.forward);

                // Draw planes
                for (int i = 0; i < planes.Length; ++i)
                {
                    Vector3 center = planes[i].Bounds.Center;
                    Quaternion rotation = planes[i].Bounds.Rotation;
                    Vector3 extents = planes[i].Bounds.Extents;
                    Vector3 normal = planes[i].Plane.normal;
                    center -= planes[i].Plane.GetDistanceToPoint(center) * normal;

                    Vector3[] corners = new Vector3[4] {
                    center + rotation * new Vector3(+extents.x, +extents.y, 0),
                    center + rotation * new Vector3(-extents.x, +extents.y, 0),
                    center + rotation * new Vector3(-extents.x, -extents.y, 0),
                    center + rotation * new Vector3(+extents.x, -extents.y, 0)
                };

                    Color color = colors[i % colors.Length];

                    // Draw the same plane lines using the Handles class which ignores the depth buffer
                    UnityEditor.Handles.color = color;
                    UnityEditor.Handles.DrawLine(corners[0], corners[1]);
                    UnityEditor.Handles.DrawLine(corners[0], corners[2]);
                    UnityEditor.Handles.DrawLine(corners[0], corners[3]);
                    UnityEditor.Handles.DrawLine(corners[1], corners[2]);
                    UnityEditor.Handles.DrawLine(corners[1], corners[3]);
                    UnityEditor.Handles.DrawLine(corners[2], corners[3]);
                    UnityEditor.Handles.ArrowHandleCap(0, center, Quaternion.FromToRotation(Vector3.forward, normal), 0.4f, EventType.Ignore);

                    // If this plane is currently in the center of the camera's field of view, highlight it by drawing a
                    // solid rectangle, and display the important details about this plane.
                    float planeHitDistance;
                    if (planes[i].Plane.Raycast(cameraForward, out planeHitDistance))
                    {
                        Vector3 hitPoint = Quaternion.Inverse(rotation) * (cameraForward.GetPoint(planeHitDistance) - center);
                        if (Mathf.Abs(hitPoint.x) <= extents.x && Mathf.Abs(hitPoint.y) <= extents.y)
                        {
                            color.a = 0.1f;
                            UnityEditor.Handles.DrawSolidRectangleWithOutline(corners, color, Color.clear);

                            string text = string.Format("Area: {0} Bounds: {1}\nPlane: N{2}, D({3})",
                                planes[i].Area.ToString("F1"),
                                ((Vector2)extents).ToString("F2"),
                                normal.ToString("F3"),
                                planes[i].Plane.distance.ToString("F3"));

                            UnityEditor.Handles.Label(center, text, GUI.skin.textField);
                        }
                    }
                }
            }
        }
#endif
    }
}