RobotNavigationNodeResolver.cs 3.07 KB
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Rcs.Application.Services;
using Rcs.Application.Services.PathFind;
using Rcs.Application.Services.PathFind.Models;

namespace Rcs.Infrastructure.PathFinding.Services;

/// <summary>
/// 基于位置缓存、路径缓存和图结构解析机器人当前导航锚点节点编码。
/// </summary>
public static class RobotNavigationNodeResolver
{
    /// <summary>
    /// 尝试解析机器人当前导航锚点节点编码。
    /// </summary>
    public static async Task<string?> ResolveAsync(
        IAgvPathService agvPathService,
        Guid mapId,
        RobotLocationCache? locationCache,
        VdaSegmentedPathCache? pathCache = null,
        string? fallbackLastNodeCode = null,
        CancellationToken ct = default)
    {
        ct.ThrowIfCancellationRequested();

        if (locationCache?.NodeId is Guid locationNodeId && locationNodeId != Guid.Empty)
        {
            if (pathCache != null &&
                TryResolveNodeCodeFromPathCache(pathCache, locationNodeId, out var nodeCodeFromCache))
            {
                return nodeCodeFromCache;
            }

            var graph = await agvPathService.GetOrBuildGraphAsync(mapId);
            if (graph?.Nodes.TryGetValue(locationNodeId, out var pathNode) == true &&
                !string.IsNullOrWhiteSpace(pathNode.NodeCode))
            {
                return pathNode.NodeCode;
            }

            if (!string.IsNullOrWhiteSpace(fallbackLastNodeCode) &&
                graph?.Nodes.Values.Any(n => string.Equals(n.NodeCode, fallbackLastNodeCode, StringComparison.OrdinalIgnoreCase)) == true)
            {
                return fallbackLastNodeCode;
            }

            return null;
        }

        if (string.IsNullOrWhiteSpace(fallbackLastNodeCode))
        {
            return null;
        }

        var fallbackGraph = await agvPathService.GetOrBuildGraphAsync(mapId);
        return fallbackGraph?.Nodes.Values.Any(n => string.Equals(n.NodeCode, fallbackLastNodeCode, StringComparison.OrdinalIgnoreCase)) == true
            ? fallbackLastNodeCode
            : null;
    }

    private static bool TryResolveNodeCodeFromPathCache(
        VdaSegmentedPathCache cache,
        Guid nodeId,
        out string? nodeCode)
    {
        nodeCode = null;

        foreach (var junction in cache.JunctionSegments)
        {
            foreach (var resource in junction.ResourceSegments)
            {
                foreach (var segment in resource.Segments)
                {
                    if (segment.FromNodeId == nodeId && !string.IsNullOrWhiteSpace(segment.FromNodeCode))
                    {
                        nodeCode = segment.FromNodeCode;
                        return true;
                    }

                    if (segment.ToNodeId == nodeId && !string.IsNullOrWhiteSpace(segment.ToNodeCode))
                    {
                        nodeCode = segment.ToNodeCode;
                        return true;
                    }
                }
            }
        }

        return false;
    }
}