268 lines
12 KiB
C#
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);
|
|
}
|
|
}
|