Commit 454f5af0 authored by Stephane LOUIS DIT PICARD's avatar Stephane LOUIS DIT PICARD
Browse files

feat: add implementation for API method GET RelocalizationInformation

parent ece106b6
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using ETSI.ARF.OpenAPI.WorldStorage.Models;
using System;

namespace ETSI.ARF.OpenAPI.WorldStorage.Binders
{
    public class FromJsonBinderProviderT<T> : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Metadata.ModelType == typeof(T))
            {
                return new BinderTypeModelBinder(typeof(FromJsonBinderT<T>));
            }

            return null;
        }
    }
}
 No newline at end of file
+48 −0
Original line number Diff line number Diff line
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;

using ETSI.ARF.OpenAPI.WorldStorage.Models;

namespace ETSI.ARF.OpenAPI.WorldStorage.Binders
{
    public class FromJsonBinderT<T> : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            var modelName = bindingContext.ModelName;
            var jsonString = bindingContext.ActionContext.HttpContext.Request.Query[modelName];
            var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

            if (valueProviderResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }

            bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

            var value = valueProviderResult.FirstValue;

            if (string.IsNullOrEmpty(value))
            {
                return Task.CompletedTask;
            }

            Console.WriteLine($"json string: {value}");

            T result = JsonConvert.DeserializeObject<T>(value);

            Console.WriteLine($"instance: {result}");
            
            bindingContext.Result = ModelBindingResult.Success(result);
            return Task.CompletedTask;
        }
    }
}
 No newline at end of file
+370 −0
Original line number Diff line number Diff line
//
// ARF - Augmented Reality Framework (ETSI ISG ARF)
//
// Copyright 2024 ETSI
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Swashbuckle.AspNetCore.Annotations;
using Swashbuckle.AspNetCore.SwaggerGen;
using Newtonsoft.Json;
using ETSI.ARF.OpenAPI.WorldStorage.Attributes;
using ETSI.ARF.OpenAPI.WorldStorage.Models;
using ETSI.ARF.OpenAPI.WorldStorage.Services;
using MongoDB.Driver;

using System.Numerics;

namespace ETSI.ARF.OpenAPI.WorldStorage.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    [ApiController]
    public class RelocalizationInformationApiControllerImpl : RelocalizationInformationApiController
    {
        /// <summary>
        /// 
        /// </summary>
        public RelocalizationInformationApiControllerImpl()
        {

        }

        /// <summary>
        /// Operation to retrieve all the relocalization information of one or severals WorldAnchors or Trackables.
        /// </summary>
        /// 
        public override IActionResult GetRelocalizationInformation([FromQuery(Name = "uuids")][Required()] List<GetRelocalizationInformationUuidsParameterInner> uuids, [FromQuery(Name = "capabilities")][Required()] List<Capability> capabilities, [FromHeader(Name = "token")] string token)
        {
            WorldAnchorService _worldAnchorService = WorldAnchorService.Singleton as WorldAnchorService;

            var history = new List<Guid>();
            var result = new GetRelocalizationInformation200Response();
            result.RelocInfo = new List<RelocalizationInformation>();

            foreach (var request in uuids)
            {
                var anchor = _worldAnchorService.Get(request.Uuid);

                if (anchor != null)
                {
                    history.Add(anchor.UUID);

                    Matrix4x4 matrix = Matrix4x4.Identity;

                    var relocalizationInformation = new RelocalizationInformation();
                    relocalizationInformation.RequestUUID = anchor.UUID;
                    relocalizationInformation.RelocObjects = FindRelocInfo(anchor.UUID, request.Mode, matrix, capabilities, ref history);

                    result.RelocInfo.Add(relocalizationInformation);
                }
                else
                {
                    Console.WriteLine($"WorldAnchor with UUID {request.Uuid} does not exist in database");
                }
            }

            return result.RelocInfo.Count > 0 ? new ObjectResult(result) : StatusCode(404, "Not found, could not find UUID in database.");
        }

        private List<RelocalizationInformationRelocObjectsInner> FindRelocInfo(Guid targetUUID, ModeWorldStorage mode, Matrix4x4 matrix, List<Capability> capabilities, ref List<Guid> history)
        {
            var results = new List<RelocalizationInformationRelocObjectsInner>();

            results.AddRange(FindRelocInfoAsTo(targetUUID, mode, matrix, capabilities, ref history));
            results.AddRange(FindRelocInfoAsFrom(targetUUID, mode, matrix, capabilities, ref history));

            return results;
        }

        // Check links where the target UUID appeared as "To"
        private List<RelocalizationInformationRelocObjectsInner> FindRelocInfoAsTo(Guid targetUUID, ModeWorldStorage mode, Matrix4x4 matrix, List<Capability> capabilities, ref List<Guid> history)
        {
            TrackableService _trackableService = TrackableService.Singleton as TrackableService;
            WorldAnchorService _worldAnchorService = WorldAnchorService.Singleton as WorldAnchorService;
            WorldLinkService _worldLinkService = WorldLinkService.Singleton as WorldLinkService;

            var results = new List<RelocalizationInformationRelocObjectsInner>();

            // Check links where the target UUID appeared as "To"
            List<WorldLink> linksTo;

            linksTo = _worldLinkService.GetWorldLinkUUIDTo(targetUUID);
            foreach (var link in linksTo)
            {
                var found = history.Find(uuid => uuid == link.UUIDFrom);
                if (found != Guid.Empty)
                {
                    // Skip link, already processed!
                    Console.WriteLine($"Skip link ({link.UUIDFrom} -> {link.UUIDTo}) as it was already processed");
                    continue;
                }

                history.Add(link.UUIDFrom);

                if (link.TypeFrom == TypeWorldStorage.TRACKABLEEnum)
                {
                    // handle "From" as a trackable
                    Trackable trackable = _trackableService.Get(link.UUIDFrom);

                    if (trackable != null)
                    {
                        // Check if trackable is compatible with the request
                        if (!trackable.Match(capabilities))
                        {
                            continue;
                        }

                        Matrix4x4 m;

                        if (mode == ModeWorldStorage.REQUESTTOTRACKABLESEnum)
                        {
                            Matrix4x4 invert;
                            if (Matrix4x4.Invert(link.Matrix(), out invert))
                            {
                                m = matrix * invert;
                            }
                            else
                            {
                                Console.WriteLine("Fail to invert 3D transform!");
                                continue;
                            }
                        }
                        else if (mode == ModeWorldStorage.TRACKABLESTOREQUESTEnum)
                        {
                            m = link.Matrix() * matrix;
                        }
                        else
                        {
                            // Invalid mode
                            continue;
                        }

                        // We found a valid trackable, add it to the results
                        var result = new RelocalizationInformationRelocObjectsInner();
                        result.Trackable = trackable;
                        result.Mode = mode;
                        result.Transform3D = new List<float>()
                        {
                            m.M11, m.M12, m.M13, m.M14,
                            m.M21, m.M22, m.M23, m.M24,
                            m.M31, m.M32, m.M33, m.M34,
                            m.M41, m.M42, m.M43, m.M44,
                        };

                        results.Add(result);

                        // Recursive search starting with the attached trackable
                        results.AddRange(FindRelocInfo(trackable.UUID, mode, m, capabilities, ref history));
                    }
                    else
                    {
                        Console.WriteLine($"Trackable with UUID {link.UUIDFrom} does not exist in database");
                    }
                }
                else if (link.TypeFrom == TypeWorldStorage.ANCHOREnum)
                {
                    WorldAnchor anchor = _worldAnchorService.Get(link.UUIDFrom);

                    if (anchor != null)
                    {
                        
                        Matrix4x4 m;
                        m = link.Matrix()*matrix;

                        if (mode == ModeWorldStorage.REQUESTTOTRACKABLESEnum)
                        {
                            Matrix4x4 invert;
                            if (Matrix4x4.Invert(link.Matrix(), out invert))
                            {
                                m = matrix * invert;
                            }
                            else
                            {
                                Console.WriteLine("Fail to invert 3D transform!");
                                continue;
                            }
                        }
                        else if (mode == ModeWorldStorage.TRACKABLESTOREQUESTEnum)
                        {
                            m = link.Matrix() * matrix;
                        }
                        else
                        {
                            // Invalid mode
                            continue;
                        }

                        // Recursive search starting with the attached anchor
                        results.AddRange(FindRelocInfo(anchor.UUID, mode, m, capabilities, ref history));
                    }
                    else
                    {
                        Console.WriteLine($"WorldAnchor with UUID {link.UUIDFrom} does not exist in database");
                    }
                }
                else
                {
                    // Skip link, invalid type
                    continue;
                }
            }

            return results;
        }

        // Check links where the target UUID appeared as "From"
        private List<RelocalizationInformationRelocObjectsInner> FindRelocInfoAsFrom(Guid targetUUID, ModeWorldStorage mode, Matrix4x4 matrix, List<Capability> capabilities, ref List<Guid> history)
        {
            TrackableService _trackableService = TrackableService.Singleton as TrackableService;
            WorldAnchorService _worldAnchorService = WorldAnchorService.Singleton as WorldAnchorService;
            WorldLinkService _worldLinkService = WorldLinkService.Singleton as WorldLinkService;

            var results = new List<RelocalizationInformationRelocObjectsInner>();

            // Check links where the anchor appeared as "From"
            List<WorldLink> linksTo;

            linksTo = _worldLinkService.GetWorldLinkUUIDFrom(targetUUID);
            foreach (var link in linksTo)
            {
                var found = history.Find(uuid => uuid == link.UUIDTo);
                if (found != Guid.Empty)
                {
                    // Skip link, already processed!
                    Console.WriteLine($"Skip link ({link.UUIDFrom} -> {link.UUIDTo}) as it was already processed");
                    continue;
                }

                history.Add(link.UUIDTo);

                if (link.TypeTo == TypeWorldStorage.TRACKABLEEnum)
                {
                    // handle "To" as a trackable
                    Trackable trackable = _trackableService.Get(link.UUIDTo);

                    if (trackable != null)
                    {
                        // Check if trackable is compatible with the request
                        if (!trackable.Match(capabilities))
                        {
                            continue;
                        }

                        Matrix4x4 m;

                        if (mode == ModeWorldStorage.REQUESTTOTRACKABLESEnum)
                        {
                            m = link.Matrix() * matrix;
                        }
                        else if (mode == ModeWorldStorage.TRACKABLESTOREQUESTEnum)
                        {
                            Matrix4x4 invert;
                            if (Matrix4x4.Invert(link.Matrix(), out invert))
                            {
                                m = matrix * invert;
                            }
                            else
                            {
                                Console.WriteLine("Fail to invert 3D transform!");
                                continue;
                            }
                        }
                        else
                        {
                            // Invalid mode
                            continue;
                        }

                        // We found a valid trackable, add it to the results
                        var result = new RelocalizationInformationRelocObjectsInner();
                        result.Trackable = trackable;
                        result.Mode = mode;
                        result.Transform3D = new List<float>()
                        {
                            m.M11, m.M12, m.M13, m.M14,
                            m.M21, m.M22, m.M23, m.M24,
                            m.M31, m.M32, m.M33, m.M34,
                            m.M41, m.M42, m.M43, m.M44,
                        };

                        results.Add(result);

                        // Recursive search starting with the attached trackable
                        results.AddRange(FindRelocInfo(trackable.UUID, mode, m, capabilities, ref history));
                    }
                    else
                    {
                        Console.WriteLine($"Trackable with UUID {link.UUIDTo} does not exist in database");
                    }
                }
                else if (link.TypeTo == TypeWorldStorage.ANCHOREnum)
                {
                    WorldAnchor anchor = _worldAnchorService.Get(link.UUIDTo);

                    if (anchor != null)
                    {

                        Matrix4x4 m;
                        m = link.Matrix() * matrix;

                        if (mode == ModeWorldStorage.REQUESTTOTRACKABLESEnum)
                        {
                            m = link.Matrix() * matrix;
                        }
                        else if (mode == ModeWorldStorage.TRACKABLESTOREQUESTEnum)
                        {
                            Matrix4x4 invert;
                            if (Matrix4x4.Invert(link.Matrix(), out invert))
                            {
                                m = matrix * invert;
                            }
                            else
                            {
                                Console.WriteLine("Fail to invert 3D transform!");
                                continue;
                            }
                        }
                        else
                        {
                            // Invalid mode
                            continue;
                        }

                        // Recursive search starting with the attached anchor
                        results.AddRange(FindRelocInfo(anchor.UUID, mode, m, capabilities, ref history));
                    }
                    else
                    {
                        Console.WriteLine($"WorldAnchor with UUID {link.UUIDTo} does not exist in database");
                    }
                }
                else
                {
                    // Skip link, invalid type
                    continue;
                }
            }

            return results;
        }
    }
}
+31 −0
Original line number Diff line number Diff line
using System;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Collections.Generic;
using System.ComponentModel;
@@ -38,5 +39,35 @@ namespace ETSI.ARF.OpenAPI.WorldStorage.Models
        /// </summary>
        //[BsonIgnore] - don't ignore, so mongo replace can use it!
        public ObjectId _mongoID { get => _id; set => _id = value; }

        public bool Match(List<Capability> capabilities)
        {
            if (capabilities.Count == 0)
            {
                return true;
            }

            foreach(var capability in capabilities)
            {
                if (capability.TrackableType == TrackableType &&
                    capability.EncodingInformation.DataFormat == TrackableEncodingInformation.DataFormat &&
                    capability.EncodingInformation.VarVersion == TrackableEncodingInformation.VarVersion)
                {
                    return true;
                }
            }
            
            return false;
        }

        public Matrix4x4 Matrix()
        {
            return new Matrix4x4(
                LocalCRS[0], LocalCRS[1], LocalCRS[2], LocalCRS[3],
                LocalCRS[4], LocalCRS[5], LocalCRS[6], LocalCRS[7],
                LocalCRS[8], LocalCRS[9], LocalCRS[10], LocalCRS[11],
                LocalCRS[12], LocalCRS[13], LocalCRS[14], LocalCRS[15]
            );
        }
    }
}
 No newline at end of file
+11 −0
Original line number Diff line number Diff line
using System;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Collections.Generic;
using System.ComponentModel;
@@ -44,5 +45,15 @@ namespace ETSI.ARF.OpenAPI.WorldStorage.Models
        /// </summary>
        //[BsonIgnore] - don't ignore, so mongo replace can use it!
        public ObjectId _mongoID { get => _id; set => _id = value; }

        public Matrix4x4 Matrix()
        {
            return new Matrix4x4(
                Transform[0], Transform[1], Transform[2], Transform[3],
                Transform[4], Transform[5], Transform[6], Transform[7],
                Transform[8], Transform[9], Transform[10], Transform[11],
                Transform[12], Transform[13], Transform[14], Transform[15]
            );
        }
    }
}
 No newline at end of file
Loading