/// <summary> /// Delete a TrackedObjectProject from the table. /// </summary> /// <param name="instance">Object to delete.</param> /// <returns>Success result of deletion.</returns> public async Task <bool> DeleteSpatialAnchor(SpatialAnchor instance) { var deleteOperation = TableOperation.Delete(instance); var result = await spatialAnchorTable.ExecuteAsync(deleteOperation); return(result.HttpStatusCode == (int)HttpStatusCode.OK); }
public string CreateAnchor(Vec3 at, string id = null) { string anchorID = id == null ? Guid.NewGuid().ToString() : id; SpatialLocator locator = SpatialLocator.GetDefault(); SpatialStationaryFrameOfReference stationary = locator.CreateStationaryFrameOfReferenceAtCurrentLocation(); SpatialAnchor anchor = SpatialAnchor.TryCreateRelativeTo(stationary.CoordinateSystem); Pose pose = World.FromPerceptionAnchor(anchor); Pose newAnchor = pose.ToMatrix().Inverse.Transform(new Pose(at, Quat.Identity)); anchor = SpatialAnchor.TryCreateRelativeTo(stationary.CoordinateSystem, newAnchor.position, newAnchor.orientation); pose = World.FromPerceptionAnchor(anchor); if (anchor != null) { anchorPoses.Add(anchorID, pose); } return(anchorStore.TrySave(anchorID, anchor) ? anchorID : null); }
public void Init(SpatialAnchor source) { toolTipPanel.SetActive(true); spatialAnchorObject = source; //Workaround because TextMeshPro label is not ready until next frame StartCoroutine(DelayedInitCoroutine()); }
public AnchorPosition UpdateNewAnchorPositionInformation() { // get the information from the createAnchorPanel // update information of the currentSpatialAnchor var newSpatialAnchor = new SpatialAnchor(anchorNameInputField.text); newSpatialAnchor.Type = anchorTypeRadialSet.ToggleList[anchorTypeRadialSet.CurrentIndex].name; newSpatialAnchor.AnchorPosition = currentAnchorPosition.transform.position.ToString(); newSpatialAnchor.WorldToLocalMatrix = currentAnchorPosition.transform.worldToLocalMatrix.ToString(); // if there is previousSpatial anchor if (previousAnchorPosition != null) { // update information of the edge currentEdge.ConnectedName = anchorNameInputField.text; currentEdge.Distance = Vector3.Distance(currentAnchorPosition.transform.position, previousAnchorPosition.transform.position); } // initialize anchorPosition currentAnchorPosition.Init(newSpatialAnchor); // disable tap to place of the currentAnchorPosition currentAnchorPosition.GetComponent <TapToPlace>().enabled = false; // reset anchorNameInputFile TEXT anchorNameInputField.text = ""; return(currentAnchorPosition); }
/// <summary> /// Generates and creates an anchor and its GameObjects /// </summary> /// <param name="relativePose"></param> /// <param name="parentAnchor"></param> /// <returns></returns> public SpatialAnchorController CreateAnchor(RobotUtilities.Pose relativePose, SpatialAnchor parentAnchor) { SpatialAnchor newAnchor = new WaypointControl.Anchor.SpatialAnchor(null, relativePose, parentAnchor != null ? parentAnchor.Id : "root"); mission.AddAnchor(newAnchor); var controller = CreateAnchorGameObject(newAnchor, parentAnchor); return(controller); }
private void OnLocated(SpatialLocator loc, object args) { if (frame != null || loc.Locatability != SpatialLocatability.PositionalTrackingActive) { return; } frame = loc.CreateStationaryFrameOfReferenceAtCurrentLocation(); anchor = SpatialAnchor.TryCreateRelativeTo(frame.CoordinateSystem); root = World.FromPerceptionAnchor(anchor).ToMatrix(); UpdateBounds(center, radius); }
/// <summary> /// Converts a <see cref="CoordinateSystem"/> in \psi basis to a <see cref="SpatialCoordinateSystem"/> in HoloLens basis. /// </summary> /// <param name="coordinateSystem">The <see cref="CoordinateSystem"/> in \psi basis.</param> /// <returns>The <see cref="SpatialCoordinateSystem"/>.</returns> public static SpatialCoordinateSystem TryConvertPsiCoordinateSystemToSpatialCoordinateSystem(this CoordinateSystem coordinateSystem) { var holoLensMatrix = coordinateSystem.RebaseToHoloLensSystemMatrix(); var translation = holoLensMatrix.Translation; holoLensMatrix.Translation = Vector3.Zero; var rotation = Quaternion.CreateFromRotationMatrix(holoLensMatrix); var spatialAnchor = SpatialAnchor.TryCreateRelativeTo(MixedReality.WorldSpatialCoordinateSystem, translation, rotation); return(spatialAnchor?.CoordinateSystem); }
public void AddSpatialAnchor(SpatialAnchor anchor) { if (CreatedSpatialAnchors == null) { CreatedSpatialAnchors = new Dictionary <string, SpatialAnchor>(); } if (!CreatedSpatialAnchors.ContainsKey(anchor.Name)) { CreatedSpatialAnchors.Add(anchor.Name, anchor); } }
/// <summary> /// Insert a new or update an TrackedObjectProject instance on the table storage. /// </summary> /// <param name="spatialAnchor">Instance to write or update.</param> /// <returns>Success result.</returns> public async Task <bool> UploadOrUpdate(SpatialAnchor spatialAnchor) { if (string.IsNullOrWhiteSpace(spatialAnchor.PartitionKey)) { spatialAnchor.PartitionKey = partitionKey; } var insertOrMergeOperation = TableOperation.InsertOrMerge(spatialAnchor); var result = await spatialAnchorTable.ExecuteAsync(insertOrMergeOperation); return(result.Result != null); }
public void InitAsync(SpatialAnchor anchor) { Anchor = anchor; if (anchor.Id == null) { //create anchor and set id startAnchorCreationOnNextUpdate = true; } else { //find anchor from id shouldStartLookingForAnchor = true; } }
/// <summary> /// Initializes static members of the <see cref="MixedReality"/> class. /// Attempts to initialize the world coordinate system from a given spatial anchor. /// If no spatial anchor is given, it attempts to load a default spatial anchor. /// If the default spatial anchor is not found (e.g., if the app is being run for the first time), /// a stationary frame of reference for the world is created at the current location. /// </summary> /// <param name="worldSpatialAnchor">A spatial anchor to use for the world (optional).</param> /// <param name="regenerateDefaultWorldSpatialAnchorIfNeeded">Optional flag indicating whether to regenerate and persist default world spatial anchor if currently persisted anchor fails to localize in the current environment (default: false).</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <remarks> /// This method should be called after SK.Initialize. /// </remarks> public static async Task InitializeAsync(SpatialAnchor worldSpatialAnchor = null, bool regenerateDefaultWorldSpatialAnchorIfNeeded = false) { if (!SK.IsInitialized) { throw new InvalidOperationException("StereoKit is not initialized. Call SK.Initialize before calling MixedReality.InitializeAsync."); } // Create the spatial anchor helper SpatialAnchorHelper = new SpatialAnchorHelper(await SpatialAnchorManager.RequestStoreAsync()); InitializeWorldCoordinateSystem(worldSpatialAnchor, regenerateDefaultWorldSpatialAnchorIfNeeded); // By default, don't render the hands or register with StereoKit physics system. Input.HandVisible(Handed.Max, false); Input.HandSolid(Handed.Max, false); }
Node AddNode(SpatialAnchor anchor, PerceptionTimestamp perceptionTimestamp) { var position = Vector3.Zero; var forward = Vector3.Zero; var anchorPose = SpatialPointerPose.TryGetAtTimestamp(anchor.CoordinateSystem, perceptionTimestamp); if (anchorPose != null) { position = anchorPose.Head.Position; forward = anchorPose.Head.ForwardDirection; } var node = new Node(anchor, position, forward); nodes.Add(node); return(node); }
public void CreateEdge(SpatialAnchor anchor1, SpatialAnchor anchor2, double distance) { if (CreatedEdges == null) { CreatedEdges = new Dictionary <string, Edge>(); } if ((!CreatedEdges.ContainsKey(anchor1.SpatialAnchorId + ',' + anchor2.SpatialAnchorId)) && (!CreatedEdges.ContainsKey(anchor2.SpatialAnchorId + ',' + anchor1.SpatialAnchorId))) { Edge edge = new Edge(); edge.Name = anchor1.Name; edge.SpatialAnchorId = anchor1.SpatialAnchorId; edge.ConnectedName = anchor2.Name; edge.ConnectedSpatialAnchorId = anchor2.SpatialAnchorId; edge.Id = anchor1.Name + ',' + anchor2.Name; edge.RowKey = edge.Id; edge.Distance = distance; CreatedEdges.Add(edge.Id, edge); } }
/// <summary> /// Initializes the mission with an EntryElement. If none exists already, it creates one /// </summary> private void InitMission() { //Entry Element Configuration var EntryElement = this.GetComponentInChildren <WaypointController>(); if (EntryElement == null) { //Create and add the root anchor mission.SpatialAnchors.Clear(); SpatialAnchor RootAnchor = CreateAnchor(new RobotUtilities.Pose(), null).GetAnchor(); EntryElement = CreateWpController(new RobotUtilities.Pose(), RootAnchor); } mission.SetEntryPoint(EntryElement.waypoint); //Add some debugging stuff var newWp1 = AddChild(EntryElement); var newWp2 = AddChild(newWp1); }
public AnchorPosition UpdateNewAnchorPositionInformation() { // get the information from the createAnchorPanel // update information of the currentSpatialAnchor var newSpatialAnchor = new SpatialAnchor(anchorNameInputField.text); newSpatialAnchor.Type = anchorTypeRadialSet.ToggleList[anchorTypeRadialSet.CurrentIndex].name; newSpatialAnchor.AnchorPosition = currentAnchorPosition.transform.position.ToString(); newSpatialAnchor.WorldToLocalMatrix = currentAnchorPosition.transform.worldToLocalMatrix.ToString(); string connectAnchorName = connectAnchorDropdown.options[connectAnchorDropdown.value].text; if (connectAnchorName != null) { var connectAnchor = GetAnchorPosition(connectAnchorName); Debug.Log($"Connect to {connectAnchor.SpatialAnchorObject.Name}"); currentEdge.Name = connectAnchorName; currentEdge.SpatialAnchorId = connectAnchor.SpatialAnchorObject.SpatialAnchorId; previousAnchorPosition = connectAnchor; } if (previousAnchorPosition != null) { // update information of the edge currentEdge.ConnectedName = anchorNameInputField.text; currentEdge.Distance = Vector3.Distance(currentAnchorPosition.transform.position, previousAnchorPosition.transform.position); } // initialize anchorPosition currentAnchorPosition.Init(newSpatialAnchor); // disable tap to place of the currentAnchorPosition currentAnchorPosition.GetComponent <TapToPlace>().enabled = false; // reset anchorNameInputFile TEXT anchorNameInputField.text = ""; return(currentAnchorPosition); }
/// <summary> /// Create an Anchors GameObjects /// </summary> /// <param name="newAnchor"></param> /// <param name="parentAnchor"></param> /// <returns></returns> private SpatialAnchorController CreateAnchorGameObject(SpatialAnchor newAnchor, SpatialAnchor parentAnchor = null) { GameObject anchorObject = Instantiate(SpatialAnchorPrefab, SpatialAnchorsContainer.transform); SpatialAnchorController controller = anchorObject.GetComponent <SpatialAnchorController>(); mission.AddAnchor(newAnchor); controller.InitAsync(newAnchor); SpatialAnchorToControllerMap[newAnchor] = controller; if (parentAnchor == null) { parentAnchor = mission.SpatialAnchors.FirstOrDefault(x => x.Id == newAnchor.ParentAnchorId); } if (parentAnchor != null) { controller.SetPose(SpatialAnchorToControllerMap[parentAnchor]); } return(controller); }
/// <summary> /// Initializes the world coordinate system for the application using a pre-defined spatial anchor, /// or creates it at a stationary frame of reference if it does not exist. Once initialized, the /// world coordinate system will be consistent across application sessions, unless the associated /// spatial anchor is modified or deleted. /// <param name="worldSpatialAnchor">A spatial anchor to use for the world (may be null).</param> /// <param name="regenerateDefaultWorldSpatialAnchorIfNeeded">Flag indicating whether to regenerate and persist default world spatial anchor if currently persisted anchor fails to localize in the current environment (default: false).</param> /// </summary> private static void InitializeWorldCoordinateSystem(SpatialAnchor worldSpatialAnchor, bool regenerateDefaultWorldSpatialAnchorIfNeeded) { SpatialAnchor TryCreateDefaultWorldSpatialAnchor(SpatialStationaryFrameOfReference world) { // Save the world spatial coordinate system WorldSpatialCoordinateSystem = world.CoordinateSystem; // Create a spatial anchor to represent the world origin and persist it to the spatial // anchor store to ensure that the origin remains coherent between sessions. return(SpatialAnchorHelper.TryCreateSpatialAnchor(DefaultWorldSpatialAnchorId, WorldSpatialCoordinateSystem)); } // If no world anchor was given, try to load the default world spatial anchor if it was previously persisted worldSpatialAnchor ??= SpatialAnchorHelper.TryGetSpatialAnchor(DefaultWorldSpatialAnchorId); if (worldSpatialAnchor != null) { // Set the world spatial coordinate system using the spatial anchor WorldSpatialCoordinateSystem = worldSpatialAnchor.CoordinateSystem; if (regenerateDefaultWorldSpatialAnchorIfNeeded) { var locator = SpatialLocator.GetDefault(); if (locator == null) { throw new Exception($"Could not get spatial locator."); } // determine whether we can localize in the current environment var world = locator.CreateStationaryFrameOfReferenceAtCurrentLocation(); var success = world.CoordinateSystem.TryGetTransformTo(WorldSpatialCoordinateSystem) != null; if (!success) { SpatialAnchorHelper.RemoveSpatialAnchor(DefaultWorldSpatialAnchorId); worldSpatialAnchor = TryCreateDefaultWorldSpatialAnchor(world); if (worldSpatialAnchor == null) { throw new Exception("Could not create the persistent world spatial anchor."); } } } } else { // Generate and persist the default world spatial anchor var locator = SpatialLocator.GetDefault(); if (locator != null) { // This creates a stationary frame of reference which we will use as our world origin var world = locator.CreateStationaryFrameOfReferenceAtCurrentLocation(); worldSpatialAnchor = TryCreateDefaultWorldSpatialAnchor(world); if (worldSpatialAnchor == null) { System.Diagnostics.Trace.WriteLine($"WARNING: Could not create the persistent world spatial anchor."); } } else { System.Diagnostics.Trace.WriteLine($"WARNING: Could not get spatial locator (expected in StereoKit on desktop)."); } } if (worldSpatialAnchor != null) { // At startup, we need to capture the pose of StereoKit with respect to the world anchor, and vice versa. // These transforms will allow us to convert world coordinates to/from StereoKit coordinates where needed: // on input from StereoKit -> \psi, and on output (rendering) \psi -> StereoKit // Query the pose of the world anchor. We use this pose for rendering correctly in the world, // and for transforming from world coordinates to StereoKit coordinates. StereoKitTransforms.WorldHierarchy = World.FromPerceptionAnchor(worldSpatialAnchor).ToMatrix(); StereoKitTransforms.WorldToStereoKit = StereoKitTransforms.WorldHierarchy.ToCoordinateSystem(); // Inverting gives us a coordinate system that can be used for transforming from StereoKit to world coordinates. StereoKitTransforms.StereoKitToWorld = StereoKitTransforms.WorldToStereoKit.Invert(); System.Diagnostics.Trace.WriteLine($"StereoKit origin: {StereoKitTransforms.StereoKitToWorld.Origin.X},{StereoKitTransforms.StereoKitToWorld.Origin.Y},{StereoKitTransforms.StereoKitToWorld.Origin.Z}"); // TODO: It would be nice if we could actually just shift the origin coordinate system in StereoKit // to the pose currently defined in StereoKitTransforms.WorldPose. // There's currently an open issue for this: https://github.com/maluoi/StereoKit/issues/189 // Simply setting the renderer camera root does not work, as its transform appears to be applied in the wrong order. // E.g., if the starting StereoKit pose is at a yaw rotation of 180 degrees, we would want to apply that transform // first, then apply the transform of the headset pose (perhaps pitching up). Instead, it appears that the headset // pose is applied first (e.g., pitching up), and *then* the Renderer.CameraRoot transform is applied (yaw of 180 degrees) // which in this example manifests as the pitch going down, opposite of what we desired. ////Renderer.CameraRoot = stereoKitTransform.Inverse; } }
private void OnCoordinateSystemAdjusted(SpatialAnchor sender, SpatialAnchorRawCoordinateSystemAdjustedEventArgs args) { }