RobotNet/RobotNet.RobotManager/Services/MapManager.cs
2025-10-15 15:15:53 +07:00

268 lines
12 KiB
C#

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<MapManager> Logger) : BackgroundService
{
private MapHubClient? MapHub;
private readonly Dictionary<Guid, MapDataDto> MapData = [];
public async Task<MessageResult<MapDataDto?>> 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<MessageResult<MapInfoDto>> 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<MessageResult<MapInfoDto>> 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<NodeDto>();
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<EdgeDto> 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<Guid, NodeDto[]>();
var currentPath = new List<NodeDto> { node };
var visitedNodes = new Dictionary<Guid, double> { { 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<MapHubClient>();
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);
}
}