using System; using System.Runtime.InteropServices; using UnityEngine.XR.ARSubsystems; namespace UnityEngine.XR.MagicLeap { /// /// Contains information necessary to report on XRAnchors. /// internal struct ReferenceFrame { /// /// Information necessary to construct a reference frame /// public struct Cinfo { /// /// The closet coordinate frame to the requested point /// public Pose closetCoordinateFrame; /// /// The closest coordinate frame's UID. Necessary so we can /// update the anchor in the future. /// public Native.MagicLeapNativeBindings.MLCoordinateFrameUID cfuid; /// /// The tracking state of the anchor. Necessary so we can /// report an update if the tracking state changes. /// public TrackingState trackingState; /// /// The initial pose of the anchor. Necessary so we can compute /// the transform between and the /// anchor. /// public Pose initialAnchorPose; } public ReferenceFrame(Cinfo cinfo) { trackableId = GenerateTrackableId(); coordinateFrame = cinfo.closetCoordinateFrame; cfuid = cinfo.cfuid; trackingState = cinfo.trackingState; // Compute the delta transform between the closet coordinate frame and the anchor m_AnchorFromCoordinateFrame = Pose.identity; ComputeDelta(cinfo.initialAnchorPose); } /// /// A pose which describes the delta beteen the anchor and the closest MLCoordinateFrame. /// Pose m_AnchorFromCoordinateFrame; /// /// The anchor's trackable id. /// public TrackableId trackableId { get; private set; } /// /// The pose of the coordinate frame used as the origin when calculating the . /// public Pose coordinateFrame { get; set; } /// /// The UID of the closest coordinate frame /// public Native.MagicLeapNativeBindings.MLCoordinateFrameUID cfuid { get; private set; } /// /// The tracking state associated with the anchor /// /// public TrackingState trackingState { get; set; } /// /// Compute the pose of the anchor. /// public Pose anchorPose { get { return m_AnchorFromCoordinateFrame.GetTransformedBy(coordinateFrame); } } /// /// Get the reference frame as a refernce point /// public XRAnchor anchor { get { return new XRAnchor( trackableId, anchorPose, trackingState, IntPtr.Zero); } } /// /// Sets a new coordinate frame. This is different from simply setting /// the . This method causes the anchor /// to be computed relative to a different coordinate frame entirely. /// /// The UID of the new coordinate frame /// The pose of the new coordinate frame public void SetCoordinateFrame(Native.MagicLeapNativeBindings.MLCoordinateFrameUID cfuid, Pose coordinateFrame) { // Compute the current anchor pose var pose = anchorPose; // Set new coordinate frame this.cfuid = cfuid; this.coordinateFrame = coordinateFrame; // Recompute the delta transform based on the new coordinate frame ComputeDelta(pose); } /// /// Sets the tracking state and returns true if the state changed. /// /// The new tracking state /// true if the tracking state changed. public bool SetTrackingState(TrackingState trackingState) { var oldTrackingState = this.trackingState; this.trackingState = trackingState; return oldTrackingState != trackingState; } void ComputeDelta(Pose pose) { var invRotation = Quaternion.Inverse(coordinateFrame.rotation); m_AnchorFromCoordinateFrame = new Pose( invRotation * (pose.position - coordinateFrame.position), invRotation * pose.rotation); } static unsafe TrackableId GenerateTrackableId() { var guid = Guid.NewGuid(); void* guidPtr = &guid; return Marshal.PtrToStructure((IntPtr)guidPtr); } } }