public async void QueryHandHoles100MeterRadiusFromJ1_ShouldReturn4HandHandholes() { // Setup var stops = new RouteNodeKindEnum[] { RouteNodeKindEnum.CentralOfficeSmall }; var interests = new RouteNodeKindEnum[] { RouteNodeKindEnum.HandHole }; var nearestNodeQuery = new FindNearestRouteNodes(TestRouteNetwork.J_1, 10, 100, stops, interests); // Act var nearestNodeQueryResult = await _queryDispatcher.HandleAsync <FindNearestRouteNodes, Result <FindNearestRouteNodesResult> >(nearestNodeQuery); // Assert nearestNodeQueryResult.IsSuccess.Should().BeTrue(); // We should get 4 hand holes back nearestNodeQueryResult.Value.RouteNetworkTraces.Count().Should().Be(4); nearestNodeQueryResult.Value.RouteNetworkElements.Count().Should().Be(4); nearestNodeQueryResult.Value.RouteNetworkElements.Count(r => r.RouteNodeInfo.Kind == RouteNodeKindEnum.HandHole).Should().Be(4); // Check trace for handhole HH_10 var handHole10Trace = nearestNodeQueryResult.Value.RouteNetworkTraces[TestRouteNetwork.HH_10]; handHole10Trace.Name.Should().Be("HH-10"); handHole10Trace.RouteNetworkSegmentIds.Length.Should().Be(3); handHole10Trace.RouteNetworkSegmentGeometries.Length.Should().Be(3); handHole10Trace.RouteNetworkSegmentIds[0].Should().Be(TestRouteNetwork.S13); handHole10Trace.RouteNetworkSegmentIds[1].Should().Be(TestRouteNetwork.S5); handHole10Trace.RouteNetworkSegmentIds[2].Should().Be(TestRouteNetwork.S6); handHole10Trace.Distance.Should().BeInRange(94, 96); }
public async void QueryHandHoles30MeterRadiusFromJ1_ShouldReturn3HandHandholes() { // Setup var stops = new RouteNodeKindEnum[] { RouteNodeKindEnum.CentralOfficeSmall }; var interests = new RouteNodeKindEnum[] { RouteNodeKindEnum.HandHole }; var nearestNodeQuery = new FindNearestRouteNodes(TestRouteNetwork.J_1, 10, 30, stops, interests); // Act var nearestNodeQueryResult = await _queryDispatcher.HandleAsync <FindNearestRouteNodes, Result <FindNearestRouteNodesResult> >(nearestNodeQuery); // Assert nearestNodeQueryResult.IsSuccess.Should().BeTrue(); // We should get 4 hand holes back nearestNodeQueryResult.Value.RouteNetworkTraces.Count().Should().Be(3); nearestNodeQueryResult.Value.RouteNetworkElements.Count().Should().Be(3); }
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 ) )); }
public RouteNetworkServiceQueries(ILogger <RouteNetworkServiceQueries> logger, IQueryDispatcher queryDispatcher) { Description = "GraphQL API for querying data owned by route nodes and route segments"; Field <RouteNetworkElementType>( "routeElement", arguments: new QueryArguments(new QueryArgument <NonNullGraphType <IdGraphType> > { Name = "Id" }), resolve: context => { if (!Guid.TryParse(context.GetArgument <string>("id"), out Guid routeNodeId)) { context.Errors.Add(new ExecutionError("Wrong value for guid")); return(null); } var routeNodeQuery = new GetRouteNetworkDetails(new RouteNetworkElementIdList() { routeNodeId }) { RelatedInterestFilter = RelatedInterestFilterOptions.ReferencesFromRouteElementOnly }; var queryResult = queryDispatcher.HandleAsync <GetRouteNetworkDetails, Result <GetRouteNetworkDetailsResult> >(routeNodeQuery).Result; if (queryResult.IsFailed) { context.Errors.Add(new ExecutionError(queryResult.Errors.First().Message)); return(null); } return(queryResult.Value.RouteNetworkElements[routeNodeId]); } ); Field <ListGraphType <RouteNetworkTraceType> >( "nearestNeighborNodes", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <IdGraphType> > { Name = "sourceRouteNodeId" }, new QueryArgument <NonNullGraphType <ListGraphType <RouteNodeKindEnumType> > > { Name = "stops" }, new QueryArgument <NonNullGraphType <ListGraphType <RouteNodeKindEnumType> > > { Name = "interests" }, new QueryArgument <NonNullGraphType <IntGraphType> > { Name = "maxHits" }, new QueryArgument <NonNullGraphType <IntGraphType> > { Name = "maxBirdFlyDistanceMeters" } ), resolve: context => { Guid routeNodeId = context.GetArgument <Guid>("sourceRouteNodeId"); List <RouteNodeKindEnum> stops = context.GetArgument <List <RouteNodeKindEnum> >("stops"); List <RouteNodeKindEnum> interests = context.GetArgument <List <RouteNodeKindEnum> >("interests"); int maxHits = context.GetArgument <int>("maxHits"); int maxBirdFlyDistanceMeters = context.GetArgument <int>("maxBirdFlyDistanceMeters"); var nearestNodeQuery = new FindNearestRouteNodes(routeNodeId, maxHits, maxBirdFlyDistanceMeters, stops.ToArray(), interests.ToArray()); var nearestNodeQueryResult = queryDispatcher.HandleAsync <FindNearestRouteNodes, Result <FindNearestRouteNodesResult> >(nearestNodeQuery).Result; if (nearestNodeQueryResult.IsFailed) { context.Errors.Add(new ExecutionError(nearestNodeQueryResult.Errors.First().Message)); return(null); } return(nearestNodeQueryResult.Value.RouteNetworkTraces); } ); }