2022-05-05 16:12:40 +02:00
using Logging ;
using Graph ;
2022-11-13 14:02:27 +01:00
using Graph.Utils ;
2022-05-05 02:00:55 +02:00
namespace astar
{
public class Astar
{
2022-11-13 14:02:27 +01:00
Dictionary < Node , float > timeRequired = new ( ) ;
Dictionary < Node , float > goalDistance = new ( ) ;
Dictionary < Node , Node > previousNode = new ( ) ;
2022-05-06 00:31:26 +02:00
2022-11-13 14:02:27 +01:00
public Route FindPath ( Graph . Graph graph , Node start , Node goal , Logger ? logger )
2022-05-06 00:02:28 +02:00
{
2022-11-03 19:35:04 +01:00
logger ? . Log ( LogLevel . INFO , "From {0:000.00000}#{1:000.00000} to {2:000.00000}#{3:000.00000} Great-Circle {4:00000.00}km" , start . lat , start . lon , goal . lat , goal . lon , Utils . DistanceBetweenNodes ( start , goal ) / 1000 ) ;
2022-05-11 20:25:13 +02:00
List < Node > toVisit = new ( ) ;
2022-05-06 00:02:28 +02:00
toVisit . Add ( start ) ;
Node currentNode = start ;
2022-11-13 14:02:27 +01:00
timeRequired . Add ( start , 0 ) ;
goalDistance . Add ( start , Convert . ToSingle ( Utils . DistanceBetweenNodes ( start , goal ) ) ) ;
while ( toVisit . Count > 0 & & timeRequired [ toVisit [ 0 ] ] < timeRequired [ goal ] )
2022-05-06 00:02:28 +02:00
{
2022-11-01 05:08:09 +01:00
if ( currentNode = = goal )
{
logger ? . Log ( LogLevel . INFO , "Way found, checking for shorter option." ) ;
}
2022-05-06 00:31:26 +02:00
currentNode = toVisit . First ( ) ;
2022-11-13 14:02:27 +01:00
logger ? . Log ( LogLevel . VERBOSE , "toVisit-length: {0} path-length: {1} goal-distance: {2}" , toVisit . Count , timeRequired [ currentNode ] , goalDistance [ currentNode ] ) ;
2022-05-06 00:31:26 +02:00
//Check all neighbors of current node
2022-05-06 00:02:28 +02:00
foreach ( Edge e in currentNode . edges )
{
2022-11-13 14:02:27 +01:00
if ( timeRequired [ e . neighbor ] > timeRequired [ currentNode ] + e . time )
2022-05-06 00:31:26 +02:00
{
2022-11-13 14:02:27 +01:00
goalDistance [ e . neighbor ] = Convert . ToSingle ( Utils . DistanceBetweenNodes ( e . neighbor , goal ) ) ;
timeRequired [ e . neighbor ] = timeRequired [ currentNode ] + e . time ;
previousNode [ e . neighbor ] = currentNode ;
2022-05-06 00:31:26 +02:00
toVisit . Add ( e . neighbor ) ;
2022-05-06 00:02:28 +02:00
}
}
2022-11-01 05:08:09 +01:00
2022-05-06 00:31:26 +02:00
toVisit . Remove ( currentNode ) ; //"Mark" as visited
2022-11-01 05:08:09 +01:00
toVisit . Sort ( CompareDistance ) ;
2022-05-06 00:02:28 +02:00
}
2022-11-13 14:02:27 +01:00
if ( previousNode [ goal ] ! = null )
2022-05-11 22:17:44 +02:00
{
2022-11-01 05:08:09 +01:00
logger ? . Log ( LogLevel . INFO , "Way found, shortest option." ) ;
2022-11-03 19:14:14 +01:00
currentNode = goal ;
2022-05-11 22:17:44 +02:00
}
else
2022-05-06 00:02:28 +02:00
{
2022-11-03 19:14:14 +01:00
logger ? . Log ( LogLevel . INFO , "No path between {0:000.00000}#{1:000.00000} and {2:000.00000}#{3:000.00000}" , start . lat , start . lon , goal . lat , goal . lon ) ;
2022-11-13 14:02:27 +01:00
return new Route ( new List < Step > ( ) , false , float . MaxValue , float . MaxValue ) ;
2022-05-06 00:02:28 +02:00
}
2022-11-03 19:14:14 +01:00
List < Node > tempNodes = new ( ) ;
tempNodes . Add ( goal ) ;
2022-05-06 00:02:28 +02:00
while ( currentNode ! = start )
{
2022-11-03 19:35:04 +01:00
#pragma warning disable CS8604 // Route was found, so has to have a previous node
2022-11-13 14:02:27 +01:00
tempNodes . Add ( previousNode [ currentNode ] ) ;
2022-11-03 19:35:04 +01:00
#pragma warning restore CS8604
2022-11-13 14:02:27 +01:00
currentNode = previousNode [ currentNode ] ;
2022-11-03 19:14:14 +01:00
}
tempNodes . Reverse ( ) ;
2022-11-13 14:02:27 +01:00
List < Step > steps = new ( ) ;
float totalDistance = 0 ;
2022-11-03 19:14:14 +01:00
for ( int i = 0 ; i < tempNodes . Count - 1 ; i + + )
{
2022-11-03 19:35:04 +01:00
#pragma warning disable CS8600 , CS8604 // Route was found, so has to have an edge
2022-11-03 19:14:14 +01:00
Edge e = tempNodes [ i ] . GetEdgeToNode ( tempNodes [ i + 1 ] ) ;
2022-11-13 14:02:27 +01:00
steps . Add ( new Step ( tempNodes [ i ] , e , timeRequired [ tempNodes [ i ] ] , goalDistance [ tempNodes [ i ] ] ) ) ;
2022-11-03 19:35:04 +01:00
#pragma warning restore CS8600 , CS8604
2022-11-13 14:02:27 +01:00
totalDistance + = e . distance ;
2022-05-06 00:02:28 +02:00
}
2022-11-01 05:08:09 +01:00
2022-11-13 14:02:27 +01:00
Route _route = new Route ( steps , true , totalDistance , timeRequired [ goal ] ) ;
2022-11-01 05:08:09 +01:00
logger ? . Log ( LogLevel . INFO , "Path found" ) ;
2022-11-03 19:14:14 +01:00
if ( logger ? . level > LogLevel . INFO )
2022-11-01 05:08:09 +01:00
{
2022-11-03 19:14:14 +01:00
float time = 0 ;
float distance = 0 ;
2022-11-03 19:35:04 +01:00
logger ? . Log ( LogLevel . DEBUG , "Route Distance: {0:00000.00km} Time: {1}" , _route . distance / 1000 , TimeSpan . FromSeconds ( _route . time ) ) ;
2022-11-03 19:14:14 +01:00
for ( int i = 0 ; i < _route . steps . Count ; i + + )
2022-11-01 05:08:09 +01:00
{
2022-11-03 19:14:14 +01:00
Step s = _route . steps [ i ] ;
time + = s . edge . time ;
distance + = s . edge . distance ;
2022-11-13 14:02:27 +01:00
logger ? . Log ( LogLevel . DEBUG , "Step {0:000} From {1:000.00000}#{2:000.00000} To {3:000.00000}#{4:000.00000} along {5:0000000000} after {6} and {7:0000.00}km" , i , s . start . lat , s . start . lon , s . edge . neighbor . lat , s . edge . neighbor . lon , s . edge . id , TimeSpan . FromSeconds ( timeRequired [ s . start ] ) , distance / 1000 ) ;
2022-11-01 05:08:09 +01:00
}
}
2022-11-03 19:14:14 +01:00
return _route ;
2022-05-06 00:02:28 +02:00
}
2022-05-06 00:31:26 +02:00
/ *
* Compares two nodes and returns the node closer to the goal
2022-11-01 05:08:09 +01:00
* - 1 = > n1 smaller n2
* 0 = > n1 equal n2
* 1 = > n1 larger n2
2022-05-06 00:31:26 +02:00
* /
2022-11-13 14:02:27 +01:00
private int CompareDistance ( Node n1 , Node n2 )
2022-05-06 00:02:28 +02:00
{
if ( n1 = = null | | n2 = = null )
return 0 ;
else
{
2022-11-13 14:02:27 +01:00
if ( goalDistance [ n1 ] < goalDistance [ n2 ] )
2022-05-06 00:02:28 +02:00
return - 1 ;
2022-11-13 14:02:27 +01:00
else if ( goalDistance [ n1 ] > goalDistance [ n2 ] )
2022-05-11 22:17:44 +02:00
return 1 ;
2022-05-06 00:02:28 +02:00
else return 0 ;
}
2022-05-05 02:00:55 +02:00
}
2022-11-01 05:08:09 +01:00
/ *
* Compares two nodes and returns the node with the shorter path
* - 1 = > n1 smaller n2
* 0 = > n1 equal n2
* 1 = > n1 larger n2
* /
2022-11-13 14:02:27 +01:00
private int ComparePathLength ( Node n1 , Node n2 )
2022-11-01 05:08:09 +01:00
{
if ( n1 = = null | | n2 = = null )
return 0 ;
else
{
2022-11-13 14:02:27 +01:00
if ( timeRequired [ n1 ] < timeRequired [ n2 ] )
2022-11-01 05:08:09 +01:00
return - 1 ;
2022-11-13 14:02:27 +01:00
else if ( timeRequired [ n1 ] > timeRequired [ n2 ] )
2022-11-01 05:08:09 +01:00
return 1 ;
else return 0 ;
}
}
2022-11-03 19:14:14 +01:00
2022-05-05 02:00:55 +02:00
}
}