2022-05-05 16:12:40 +02:00
using Logging ;
using Graph ;
2022-05-05 02:00:55 +02:00
namespace astar
{
public class Astar
{
2022-05-06 00:31:26 +02:00
/ *
* Resets the calculated previous nodes and distance to goal
* /
2022-05-06 00:02:28 +02:00
private static void Reset ( ref Dictionary < ulong , Node > nodes )
{
foreach ( Node n in nodes . Values )
{
2022-11-02 18:07:22 +01:00
n . previousNode = null ;
2022-10-31 23:10:28 +01:00
n . goalDistance = float . MaxValue ;
2022-11-03 19:14:14 +01:00
n . timeRequired = float . MaxValue ;
2022-05-06 00:02:28 +02:00
}
}
2022-11-03 19:14:14 +01:00
public static Route FindPath ( ref Dictionary < ulong , Node > nodes , Node start , Node goal , Logger ? logger )
2022-05-06 00:02:28 +02:00
{
2022-11-03 19:14:14 +01:00
Route _route = new Route ( ) ;
logger ? . Log ( LogLevel . INFO , "From {0:000.00000}#{1:000.00000} to {2:000.00000}#{3:000.00000} Great-Circle {4}" , start . lat , start . lon , goal . lat , goal . lon , Utils . DistanceBetweenNodes ( start , goal ) ) ;
2022-05-06 00:31:26 +02:00
Reset ( ref nodes ) ;
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-03 19:14:14 +01:00
start . timeRequired = 0 ;
2022-05-06 00:31:26 +02:00
start . goalDistance = Utils . DistanceBetweenNodes ( start , goal ) ;
2022-11-03 19:14:14 +01:00
while ( toVisit . Count > 0 & & toVisit [ 0 ] . timeRequired < goal . timeRequired )
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-03 19:14:14 +01:00
logger ? . Log ( LogLevel . VERBOSE , "toVisit-length: {0} path-length: {1} goal-distance: {2}" , toVisit . Count , currentNode . timeRequired , currentNode . goalDistance ) ;
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-03 19:14:14 +01:00
if ( e . neighbor . timeRequired > currentNode . timeRequired + e . time )
2022-05-06 00:31:26 +02:00
{
2022-11-01 05:08:09 +01:00
e . neighbor . goalDistance = Utils . DistanceBetweenNodes ( e . neighbor , goal ) ;
2022-11-03 19:14:14 +01:00
e . neighbor . timeRequired = currentNode . timeRequired + e . time ;
2022-05-06 00:02:28 +02:00
e . neighbor . previousNode = 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-02 18:07:22 +01:00
if ( goal . previousNode ! = 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 ;
_route . routeFound = true ;
_route . time = goal . timeRequired ;
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 ) ;
_route . routeFound = false ;
return _route ;
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:14:14 +01:00
tempNodes . Add ( currentNode . previousNode ) ;
currentNode = currentNode . previousNode ;
}
tempNodes . Reverse ( ) ;
for ( int i = 0 ; i < tempNodes . Count - 1 ; i + + )
{
Edge e = tempNodes [ i ] . GetEdgeToNode ( tempNodes [ i + 1 ] ) ;
_route . AddStep ( tempNodes [ i ] , e ) ;
_route . distance + = e . distance ;
2022-05-06 00:02:28 +02:00
}
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 ;
logger ? . Log ( LogLevel . DEBUG , "Route Distance: {0} Time: {1}" , _route . distance , TimeSpan . FromSeconds ( _route . time ) ) ;
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 ;
logger ? . Log ( LogLevel . DEBUG , "Step {0:000} From {1:000.00000}#{2:000.00000} To {3:000.00000}#{4:000.00000} along {5}\tafter {6} and {7} m" , i , s . start . lat , s . start . lon , s . edge . neighbor . lat , s . edge . neighbor . lon , s . edge . id , TimeSpan . FromSeconds ( s . start . timeRequired ) , distance ) ;
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-01 05:08:09 +01:00
private static int CompareDistance ( Node n1 , Node n2 )
2022-05-06 00:02:28 +02:00
{
if ( n1 = = null | | n2 = = null )
return 0 ;
else
{
if ( n1 . goalDistance < n2 . goalDistance )
return - 1 ;
2022-05-11 22:17:44 +02:00
else if ( n1 . goalDistance > n2 . goalDistance )
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
* /
private static int ComparePathLength ( Node n1 , Node n2 )
{
if ( n1 = = null | | n2 = = null )
return 0 ;
else
{
2022-11-03 19:14:14 +01:00
if ( n1 . timeRequired < n2 . timeRequired )
2022-11-01 05:08:09 +01:00
return - 1 ;
2022-11-03 19:14:14 +01:00
else if ( n1 . timeRequired > n2 . timeRequired )
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
}
}