public Task <Result <FindNearestRouteNodesResult> > HandleAsync(FindNearestRouteNodes query) { Stopwatch sw = new(); sw.Start(); var getRouteNetworkElementsResult = _routeNodeRepository.GetRouteElements(new RouteNetworkElementIdList() { query.SourceRouteNodeId }); // Here we return a error result, because we're dealing with invalid route network ids provided by the client if (getRouteNetworkElementsResult.IsFailed || getRouteNetworkElementsResult.Value.Count != 1) { return(Task.FromResult( Result.Fail <FindNearestRouteNodesResult>(new FindNearestRouteNodesError(FindNearestRouteNodesErrorCodes.INVALID_QUERY_ARGUMENT_ERROR_LOOKING_UP_SPECIFIED_ROUTE_NETWORK_ELEMENT_BY_ID, $"Error looking up route network node with id: {query.SourceRouteNodeId}")). WithError(getRouteNetworkElementsResult.Errors.First()) )); } var sourceRouteNode = getRouteNetworkElementsResult.Value.First() as RouteNode; if (sourceRouteNode == null) { return(Task.FromResult( Result.Fail <FindNearestRouteNodesResult>(new FindNearestRouteNodesError(FindNearestRouteNodesErrorCodes.INVALID_QUERY_ARGUMENT_ERROR_LOOKING_UP_SPECIFIED_ROUTE_NETWORK_ELEMENT_BY_ID, $"Error looking up route network node. Got { getRouteNetworkElementsResult.Value.First().GetType().Name} querying element with id: {query.SourceRouteNodeId}")). WithError(getRouteNetworkElementsResult.Errors.First()) )); } var sourceRouteNodePoint = GetPoint(sourceRouteNode.Coordinates); long version = _routeNetworkState.GetLatestCommitedVersion(); var stopHash = query.NodeKindStops.ToHashSet(); var interestHash = query.NodeKindOfInterests.ToHashSet(); // Fetch objects from route network graph to query on var routeNetworkSubset = sourceRouteNode.UndirectionalDFS <RouteNode, RouteSegment>( version: version, nodeCriteria: n => (n.RouteNodeInfo == null || n.RouteNodeInfo.Kind == null || !stopHash.Contains(n.RouteNodeInfo.Kind.Value)) && GetPoint(n.Coordinates).Distance(sourceRouteNodePoint) < query.SearchRadiusMeters, includeElementsWhereCriteriaIsFalse: true ); // Find nodes to check/trace shortest path var nodeCandidates = GetAllNodeCandidates(sourceRouteNode, interestHash, routeNetworkSubset); var graphForTracing = GetGraphForTracing(version, nodeCandidates, routeNetworkSubset); var nodesOfInterest = GetNodesOfInterest(nodeCandidates, interestHash).ToList(); ConcurrentBag <NearestRouteNodeTraceResult> nodeTraceResults = new(); int nShortestPathTraces = 0; ParallelOptions po = new ParallelOptions(); po.MaxDegreeOfParallelism = Environment.ProcessorCount; foreach (var nodeToTrace in nodesOfInterest) { var shortestPathTrace = ShortestPath(nodeToTrace.Node, sourceRouteNode.Id, graphForTracing); nodeTraceResults.Add(shortestPathTrace); nShortestPathTraces++; if (NumberOfShortestPathTracesWithinDistance(nodeTraceResults, nodeToTrace.BirdDistanceToSource) >= query.MaxHits) { break; } } var nodeTraceResultOrdered = nodeTraceResults.OrderBy(n => n.Distance).ToList(); sw.Stop(); _logger.LogInformation($"{nShortestPathTraces} shortets path trace(s) processed in {sw.ElapsedMilliseconds} milliseconds finding the {query.MaxHits} nearest nodes to source node with id: {sourceRouteNode.Id}"); List <NearestRouteNodeTraceResult> tracesToReturn = new(); List <IRouteNetworkElement> routeNodeElementsToReturn = new(); for (int i = 0; i < query.MaxHits && i < nodeTraceResultOrdered.Count; i++) { // Add trace var traceToAdd = nodeTraceResultOrdered[i]; tracesToReturn.Add(traceToAdd); var routeElementToAdd = _routeNodeRepository.NetworkState.GetRouteNetworkElement(traceToAdd.DestNodeId); if (routeElementToAdd != null) { routeNodeElementsToReturn.Add(routeElementToAdd); } } var result = new FindNearestRouteNodesResult( sourceRouteNodeId: sourceRouteNode.Id, routeNetworkElements: GetRouteNetworkDetailsQueryHandler.MapRouteElementDomainObjectsToQueryObjects(query.RouteNetworkElementFilter, routeNodeElementsToReturn), routeNetworkTraces: tracesToReturn ); return(Task.FromResult( Result.Ok <FindNearestRouteNodesResult>( result ) )); }