using RobotNet.MapShares.Dtos; using RobotNet.MapShares.Enums; using RobotNet.RobotManager.HubClients; using RobotNet.Shares; namespace RobotNet.RobotManager.Services; public class MapManager(IServiceProvider ServiceProvider, LoggerController Logger) : BackgroundService { private MapHubClient? MapHub; private readonly Dictionary MapData = []; public async Task> GetMapData(Guid mapId) { try { if (MapData.TryGetValue(mapId, out MapDataDto? mapData) && mapData is not null) { if (!mapData.Active) return new(false, "Bản đồ chưa được active"); return new(true) { Data = mapData }; } if (MapHub is null || !MapHub.IsConnected) return new(false, "Chưa khởi tạo kết nối với quản lí bản đồ"); var mapDataResult = await MapHub.GetMapData(mapId); if (mapDataResult is not null && mapDataResult.Data is not null) { if (!mapDataResult.IsSuccess) return new(false, mapDataResult.Message); MapData[mapId] = mapDataResult.Data; return new(true) { Data = mapDataResult.Data }; } return new(false, "Không thể lấy dữ liệu bản đồ"); } catch (Exception ex) { Logger.Warning($"GetMapData: Lấy dữ liệu bản đồ có lỗi xảy ra: {ex.Message}"); return new(false, $"GetMapData: Lấy dữ liệu bản đồ có lỗi xảy ra: {ex.Message}"); } } public async Task> GetMapInfo(Guid mapId) { try { if (MapHub is null || !MapHub.IsConnected) return new(false, "Chưa khởi tạo kết nối với quản lí bản đồ"); var mapInfoResult =await MapHub.GetMapInfoById(mapId); if (mapInfoResult is not null && mapInfoResult.Data is not null) { if (!mapInfoResult.IsSuccess) return new(false, mapInfoResult.Message); return new(true) { Data = mapInfoResult.Data }; } return new(false, "Không thể lấy dữ liệu bản đồ"); } catch (Exception ex) { Logger.Warning($"GetMapInfo: Lấy dữ liệu bản đồ có lỗi xảy ra: {ex.Message}"); return new(false, $"GetMapInfo: Lấy dữ liệu bản đồ có lỗi xảy ra: {ex.Message}"); } } public async Task> GetMapInfo(string mapName) { try { if (MapHub is null || !MapHub.IsConnected) return new(false, "Chưa khởi tạo kết nối với quản lí bản đồ"); var mapInfoResult = await MapHub.GetMapInfoByName(mapName); if (mapInfoResult is not null && mapInfoResult.Data is not null) { if (!mapInfoResult.IsSuccess) return new(false, mapInfoResult.Message); return new(true) { Data = mapInfoResult.Data }; } return new(false, "Không thể lấy dữ liệu bản đồ"); } catch (Exception ex) { Logger.Warning($"GetMapInfo: Lấy dữ liệu bản đồ có lỗi xảy ra: {ex.Message}"); return new(false, $"GetMapInfo: Lấy dữ liệu bản đồ có lỗi xảy ra: {ex.Message}"); } } public NodeDto[] GetNegativeNodes(Guid mapId, Guid nodeId) { var mapData = Task.Run(async () => await GetMapData(mapId)); mapData.Wait(); if (mapData is null || !mapData.Result.IsSuccess || mapData.Result.Data is null) return []; var map = mapData.Result.Data; var ListNodesNegative = new List(); var ListPaths = map.Edges.Where(p => p.EndNodeId == nodeId || p.StartNodeId == nodeId); foreach (var path in ListPaths) { if (path.StartNodeId == nodeId && (path.DirectionAllowed == DirectionAllowed.Both || path.DirectionAllowed == DirectionAllowed.Forward)) { var nodeAdd = map.Nodes.FirstOrDefault(p => p.Id == path.EndNodeId); if (nodeAdd is not null) ListNodesNegative.Add(nodeAdd); continue; } if (path.EndNodeId == nodeId && (path.DirectionAllowed == DirectionAllowed.Both || path.DirectionAllowed == DirectionAllowed.Backward)) { var nodeAdd = map.Nodes.FirstOrDefault(p => p.Id == path.StartNodeId); if (nodeAdd is not null) ListNodesNegative.Add(nodeAdd); continue; } } return [.. ListNodesNegative]; } public EdgeDto[] GetEdges(Guid mapId, NodeDto[] nodes) { if (nodes.Length < 2) return []; if (MapData.TryGetValue(mapId, out MapDataDto? mapData) && mapData is not null) { List edges = []; for (int i = 0; i < nodes.Length - 1; i++) { var edge = mapData.Edges.FirstOrDefault(e => e.StartNodeId == nodes[i].Id && e.EndNodeId == nodes[i + 1].Id || e.EndNodeId == nodes[i].Id && e.StartNodeId == nodes[i + 1].Id); if (edge is null) { if (i != 0) return []; edges.Add(new EdgeDto() { Id = Guid.NewGuid(), StartNodeId = nodes[i].Id, EndNodeId = nodes[i + 1].Id, DirectionAllowed = DirectionAllowed.Both, TrajectoryDegree = TrajectoryDegree.One, }); continue; } bool isReverse = nodes[i].Id != edge.StartNodeId && edge.TrajectoryDegree == TrajectoryDegree.Three; edges.Add(new() { Id = edge.Id, StartNodeId = nodes[i].Id, EndNodeId = nodes[i + 1].Id, DirectionAllowed = edge.DirectionAllowed, TrajectoryDegree = edge.TrajectoryDegree, ControlPoint1X = isReverse ? edge.ControlPoint2X : edge.ControlPoint1X, ControlPoint1Y = isReverse ? edge.ControlPoint2Y : edge.ControlPoint1Y, ControlPoint2X = isReverse ? edge.ControlPoint1X : edge.ControlPoint2X, ControlPoint2Y = isReverse ? edge.ControlPoint1Y : edge.ControlPoint2Y }); } return [.. edges]; } return []; } public EdgeDto? GetEdge(Guid startNodeId, Guid endNodeId, Guid mapId) { if (MapData.TryGetValue(mapId, out MapDataDto? mapData) && mapData is not null) { var edge = mapData.Edges.FirstOrDefault(e => (e.StartNodeId == startNodeId && e.EndNodeId == endNodeId) || (e.StartNodeId == endNodeId && e.EndNodeId == startNodeId)); if (edge is not null) { bool isReverse = startNodeId != edge.StartNodeId && edge.TrajectoryDegree == TrajectoryDegree.Three; return new EdgeDto { Id = edge.Id, StartNodeId = startNodeId, EndNodeId = endNodeId, TrajectoryDegree = edge.TrajectoryDegree, ControlPoint1X = isReverse ? edge.ControlPoint2X : edge.ControlPoint1X, ControlPoint1Y = isReverse ? edge.ControlPoint2Y : edge.ControlPoint1Y, ControlPoint2X = isReverse ? edge.ControlPoint1X : edge.ControlPoint2X, ControlPoint2Y = isReverse ? edge.ControlPoint1Y : edge.ControlPoint2Y }; } } return null; } public NodeDto[][] GetNegativePaths(Guid mapId, NodeDto node, double distance) { var negativePaths = new Dictionary(); var currentPath = new List { node }; var visitedNodes = new Dictionary { { node.Id, 0 } }; void DFS(NodeDto currentNode, double currentDistance, NodeDto[] path) { var negatvieNodes = GetNegativeNodes(mapId, currentNode.Id); foreach (var negativeNode in negatvieNodes) { if (IsHasElement(mapId, negativeNode.Id)) continue; NodeDto[] newPath = [.. path, negativeNode]; var newDistance = currentDistance + Math.Sqrt(Math.Pow(currentNode.X - negativeNode.X, 2) + Math.Pow(currentNode.Y - negativeNode.Y, 2)); if (visitedNodes.TryGetValue(negativeNode.Id, out double oldDistance)) { if (oldDistance > newDistance) { visitedNodes.Remove(negativeNode.Id); visitedNodes.Add(negativeNode.Id, newDistance); negativePaths.Remove(negativeNode.Id); if (newDistance >= distance) negativePaths.Add(negativeNode.Id, [.. newPath]); else DFS(negativeNode, newDistance, newPath); } } else { visitedNodes.Add(negativeNode.Id, newDistance); if (newDistance >= distance) negativePaths.Add(negativeNode.Id, [.. newPath]); else DFS(negativeNode, newDistance, newPath); } } } DFS(node, 0, [.. currentPath]); //foreach (var key in negativePaths.Keys.ToList()) //{ // var path = negativePaths[key]; // if (path != null && path.Length > 0) negativePaths[key] = [..path.Skip(1)]; // else negativePaths.Remove(key); //} return [.. negativePaths.Values]; } private bool IsHasElement(Guid mapId, Guid nodeId) { var mapData = Task.Run(async () => await GetMapData(mapId)); mapData.Wait(); if (mapData is null || !mapData.Result.IsSuccess || mapData.Result.Data is null) return false; var map = mapData.Result.Data; return map.Elements.Any(e => e.NodeId == nodeId); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await Task.Yield(); while (!stoppingToken.IsCancellationRequested) { try { using var scope = ServiceProvider.CreateAsyncScope(); MapHub = scope.ServiceProvider.GetRequiredService(); MapHub.MapUpdated += MapHub_Updated; await MapHub.StartAsync(); break; } catch (Exception ex) { Logger.Warning($"Map Manager Execute: Khởi tạo kết nối với MapManager có lỗi xảy ra: {ex.Message}"); await Task.Delay(2000, stoppingToken); } } } private void MapHub_Updated(Guid mapId) { Logger.Info($"Map update active: {mapId}"); if (MapHub is null || !MapHub.IsConnected) return; var mapDataResult = MapHub.GetMapData(mapId).Result; if (mapDataResult is not null && mapDataResult.Data is not null) { if (!mapDataResult.IsSuccess) return; MapData[mapId] = mapDataResult.Data; } } public override async Task StopAsync(CancellationToken cancellationToken) { if (MapHub is not null && MapHub.IsConnected) await MapHub.StopAsync(); await base.StopAsync(cancellationToken); } }