// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
// Copyright (c) (2021-2022) Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2
// Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein.
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%
using System;
using MagicLeap.OpenXR.Features.Planes;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.XR.ARSubsystems;
namespace MagicLeap.OpenXR.Subsystems
{
public partial class MLXrPlaneSubsystem
{
///
/// Container for the boundary of a detected planar surface. This is specific
/// to Magic Leap because the polygon describing the boundary may be concave,
/// and may contain holes.
///
public class PlaneBoundary
{
///
/// Whether this is valid. You should check
/// for validity before invoking
/// , or
///
private bool Valid => Polygon.VertexCountOutput > 0;
private static void AssignAtomicSafetyHandle(ref NativeArray array, Allocator allocator) where T : struct
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
var safetyHandle = allocator == Allocator.Temp ? AtomicSafetyHandle.GetTempUnsafePtrSliceHandle() : AtomicSafetyHandle.Create();
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, safetyHandle);
#endif
}
///
/// Gets the polygon representing a plane's boundary, and, if successful, copies it to .
/// is resized or created using if necessary.
/// The 2D vertices are in plane-space.
///
///
/// The Allocator to use if must be recreated.
/// Must be Allocator.TempJob or Allocator.Persistent.
///
///
/// A NativeArray to fill with boundary points. If the array is not the correct size, it is
/// disposed and recreated.
///
/// Thrown if is false.
///
/// Thrown if is Allocator.Temp or
/// Allocator.None.
///
private unsafe void GetPolygon(Allocator allocator, ref NativeArray polygonOut)
{
if (!Valid)
{
throw new InvalidOperationException("This plane boundary is not valid.");
}
CreateOrResizeNativeArrayIfNecessary(PolygonVertexCount, allocator, ref polygonOut);
polygonOut = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(Polygon.Vertices, PolygonVertexCount, allocator);
AssignAtomicSafetyHandle(ref polygonOut, allocator);
}
///
/// The number of vertices in this boundary's polygon.
///
public int PolygonVertexCount => (int)Polygon.VertexCountOutput;
///
/// Gets the polygon representing this boundary. The 2D vertices are in plane-space.
///
///
/// The allocator to use for the returned NativeArray. Must be Allocator.TempJob or
/// Allocator.Persistent.
///
///
/// A new NativeArray containing a set of 2D points in plane-space representing a boundary for a plane.
/// The caller is responsible for disposing the NativeArray.
///
/// Thrown if is false.
///
/// Thrown if is Allocator.Temp or
/// Allocator.None.
///
internal NativeArray GetPolygon(Allocator allocator)
{
var polygon = new NativeArray();
GetPolygon(allocator, ref polygon);
return polygon;
}
///
/// The number of holes in this boundary.
///
private int HoleCount => Holes.Length;
///
/// Get the polygon representing a hole in this boundary. The 2D vertices are in plane-space.
///
/// The index of the hole. Must be less than .
///
/// The allocator to use for the returned NativeArray.
/// Must be Allocator.TempJob or Allocator.Persistent.
///
///
/// A new NativeArray allocated with containing a set of 2D vertices
/// in plane-space describing the hole at .
///
/// Thrown if is false.
///
/// Thrown if is Allocator.Temp or
/// Allocator.None.
///
///
/// Thrown if is less than 0 or greater than
/// or equal to .
///
internal NativeArray GetHole(int index, Allocator allocator)
{
var hole = new NativeArray();
GetHole(index, allocator, ref hole);
return hole;
}
///
/// Get the polygon representing a hole in this boundary. The 2D vertices are in plane-space.
///
/// The index of the hole. Must be less than .
///
/// The allocator to use if must be resized.
/// Must be Allocator.TempJob or Allocator.Persistent.
///
/// The resulting polygon describing the hole at .
/// Thrown if is false.
///
/// Thrown if is Allocator.Temp or
/// Allocator.None.
///
///
/// Thrown if is less than 0 or greater than
/// or equal to .
///
private unsafe void GetHole(int index, Allocator allocator, ref NativeArray polygonOut)
{
if (!Valid)
throw new InvalidOperationException("This plane boundary is not valid.");
if (index < 0)
{
throw new ArgumentOutOfRangeException(nameof(index), "Hole index must be greater than zero.");
}
if (index >= HoleCount)
{
throw new ArgumentOutOfRangeException(nameof(index), $"Hole index must be less than or equal to holeCount ({HoleCount}).");
}
var holes = Holes[index];
CreateOrResizeNativeArrayIfNecessary((int)holes.VertexCountOutput, allocator,ref polygonOut);
polygonOut = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(holes.Vertices, (int)holes.VertexCountOutput, allocator);
AssignAtomicSafetyHandle(ref polygonOut, allocator);
}
internal NativeArray Holes;
internal XrPlaneDetectorPolygonBuffer Polygon;
internal Pose PlanePose;
internal TrackableId Id;
}
}
}