/// <summary>
    /// Gets the highest point on the dynamic mesh through at a given position.
    /// 
    /// Raycast against a subset of TangoSingleDynamicMesh colliders and find the highest point. The subset
    /// is defined by all the meshes intersected by a downward-pointing ray that passes through a position.
    /// </summary>
    /// <returns>The highest raycast hit point.</returns>
    /// <param name="position">The position to cast a ray through.</param>
    /// <param name="maxDistance">The max distance of the ray.</param>
    public Vector3 GetHighestRaycastHitPoint(Vector3 position, float maxDistance)
    {
        if (GetComponent<Collider>() == null)
        {
            return position;
        }

        Vector3 topHitPoint = position;
        Ray ray = new Ray(position + (Vector3.up * (maxDistance / 2)), Vector3.down);

        // Find the starting grid index X and Y components.
        float gridIndexSize = m_tangoApplication.m_3drResolutionMeters * 16;
        int gridIndexX = Mathf.FloorToInt(position.x / gridIndexSize);
        int gridIndexY = Mathf.FloorToInt(position.z / gridIndexSize);

        // Find the top and bottom grid indices that are overlapped by a raycast downward through the position.
        int topZ = Mathf.FloorToInt(ray.origin.y / gridIndexSize);
        int btmZ = Mathf.FloorToInt((ray.origin.y - maxDistance) / gridIndexSize);

        // Perform a raycast on each TangoSingleDynamicMesh collider the ray passes through.
        for (int i = btmZ; i <= topZ; i++)
        {
            Tango3DReconstruction.GridIndex newGridIndex = new Tango3DReconstruction.GridIndex();
            newGridIndex.x = gridIndexX;
            newGridIndex.y = gridIndexY;
            newGridIndex.z = i;

            // Find the mesh associated with the grid index if available. Raycast to the attached collider.
            TangoSingleDynamicMesh singleDynamicMesh;
            if (m_meshes.TryGetValue(newGridIndex, out singleDynamicMesh))
            {
                Collider c = singleDynamicMesh.GetComponent<Collider>();
                RaycastHit hit;
                if (c.Raycast(ray, out hit, maxDistance))
                {
                    // Update the highest position if the new raycast hit is above. Reject the hit if the normal is orthogonal to the up 
                    // direction (to prevent the object from unintentionally climbing up walls).
                    if ((hit.point.y > topHitPoint.y) && (Vector3.Dot(hit.normal, Vector3.up) > 0.1f))
                    {
                        topHitPoint = hit.point;
                    }
                }
            }
        }

        return topHitPoint;
    }
    /// <summary>
    /// When the grid index has been updated, also determine whether it should be considered completed
    /// based on its neighboring grid indices, number of observations, and mesh completeness.
    /// 
    /// When checking a grid index for completeness, the observation count of neighboring grid indices is checked.
    /// If all grid indices contained in one of the configurations have a sufficient number of observations,
    /// the grid index is considered complete.
    /// </summary>
    /// <param name="gridIndex">Grid index to observe.</param>
    /// <param name="singleMesh">TangoSingleDynamicMesh to update and observe.</param>
    private void _ObserveGridIndex(Tango3DReconstruction.GridIndex gridIndex, TangoSingleDynamicMesh singleMesh)
    {
        // Increment the observations made for this grid index.
        singleMesh.m_observations++;

        // Add observation based on the direction of the observation.
        _ViewGridIndex(gridIndex);

        // Exit if the grid index has not been observed from all 8 directions.
        if (singleMesh.m_directions != DIRECTIONS_COMPLETE)
        {
            return;
        }

        // Run through each grid index configuration and check if the grid index is complete.
        for (int i = 0; i < m_gridIndexConfigs.Length; i++)
        {
            Vector3[] config = m_gridIndexConfigs[i];
            bool neighborsObserved = true;
            foreach (Vector3 nPosition in config)
            {
                Tango3DReconstruction.GridIndex neighbor = new Tango3DReconstruction.GridIndex();
                neighbor.x = (Int32)(nPosition.x + gridIndex.x);
                neighbor.y = (Int32)(nPosition.y + gridIndex.y);
                neighbor.z = (Int32)(nPosition.z + gridIndex.z);
                TangoSingleDynamicMesh nSingleMesh;
                if (m_meshes.TryGetValue(neighbor, out nSingleMesh))
                {
                    if (nSingleMesh.m_observations < NUM_OBSERVATIONS_TO_COMPLETE)
                    {
                        neighborsObserved = false;
                        break;
                    }
                }
            }

            // Complete using this configurations of the neighbors with sufficient observations.
            if (neighborsObserved)
            {
                // Add the grid index to the completed list, so it will be skipped during next mesh update.
                singleMesh.m_completed = true;
                return;
            }
        }
    }
    /// <summary>
    /// Gets each single dynamic mesh and fills out arrays with properties. Each mesh corresponds to the same index in each array.
    /// </summary>
    /// <param name="gridIndices">Filled out with grid index of each mesh.</param>
    /// <param name="completed">Filled out with completion state of each mesh.</param>
    /// <param name="completionScale">Filled out with amount that each mesh has been completed.</param>
    /// <param name="directions">Filled out with a byte representation of the observed directions of each mesh.</param>
    public void GetSingleMeshProperties(out Tango3DReconstruction.GridIndex[] gridIndices, out bool[] completed, out float[] completionScale, out byte[] directions)
    {
        int numIndices = m_meshes.Count;
        gridIndices = new Tango3DReconstruction.GridIndex[numIndices];
        completed = new bool[numIndices];
        completionScale = new float[numIndices];
        directions = new byte[numIndices];

        // Assign mesh properties to each index of the arrays.
        m_meshes.Keys.CopyTo(gridIndices, 0);
        for (int i = 0; i < numIndices; i++)
        {
            TangoSingleDynamicMesh mesh = m_meshes[gridIndices[i]];
            completed[i] = mesh.m_completed;
            completionScale[i] = 1.0f * mesh.m_observations / NUM_OBSERVATIONS_TO_COMPLETE;
            directions[i] = mesh.m_directions;
        }
    }