@@ -448,6 +448,48 @@ function HybridAStar.NodeList:iterator()
448448 end
449449end
450450
451+ --- Cache penalties for nodes to avoid calling getNodePenalty() multiple times for the same node
452+ --- This is a 2D grid discretized to the gridSize, anything falling in the same grid cell will have the same
453+ --- penalty. This also assumes the penalty is the same for all theta values in the cell, that is, getNodePenalty()
454+ --- is not theta dependent.
455+ --- @class HybridAStar.PenaltyCache
456+ HybridAStar .PenaltyCache = CpObject ()
457+
458+ --- @param gridSize number size of the cell in the x /y dimensions
459+ function HybridAStar .PenaltyCache :init (gridSize )
460+ self .nodes = {}
461+ self .gridSize = gridSize
462+ end
463+
464+ --- @param node State3D
465+ function HybridAStar .PenaltyCache :getNodeIndexes (node )
466+ local x = math.floor (node .x / self .gridSize )
467+ local y = math.floor (node .y / self .gridSize )
468+ return x , y
469+ end
470+
471+ function HybridAStar .PenaltyCache :inSameCell (n1 , n2 )
472+ local x1 , y1 = self :getNodeIndexes (n1 )
473+ local x2 , y2 = self :getNodeIndexes (n2 )
474+ return x1 == x2 and y1 == y2
475+ end
476+
477+ --- @param node State3D
478+ function HybridAStar .PenaltyCache :get (node )
479+ local x , y , t = self :getNodeIndexes (node )
480+ return self .nodes [x ] and self .nodes [x ][y ]
481+ end
482+
483+ --- @param node State3D
484+ function HybridAStar .PenaltyCache :add (node , penalty )
485+ local x , y , t = self :getNodeIndexes (node )
486+ if not self .nodes [x ] then
487+ self .nodes [x ] = {}
488+ end
489+ self .nodes [x ][y ] = penalty
490+ end
491+
492+
451493--- A reasonable default maximum iterations that works for the majority of our use cases
452494HybridAStar .defaultMaxIterations = 40000
453495
@@ -524,6 +566,8 @@ function HybridAStar:initRun(start, goal, turnRadius, allowReverse, constraints,
524566 -- create the configuration space
525567 --- @type HybridAStar.NodeList closedList
526568 self .nodes = HybridAStar .NodeList (self .deltaPos , self .deltaThetaDeg )
569+ --- @type HybridAStar.NodeList penaltyCache is not direction dependent
570+ self .penaltyCache = HybridAStar .PenaltyCache (self .deltaPos )
527571 if allowReverse then
528572 self .analyticSolver = self .analyticSolver or ReedsSheppSolver ()
529573 else
@@ -637,7 +681,12 @@ function HybridAStar:run(start, goal, turnRadius, allowReverse, constraints, hit
637681 -- we end up being in overlap with another vehicle when we start the pathfinding and all we need is
638682 -- an iteration or two to bring us out of that position
639683 if (self .ignoreValidityAtStart and self .iterations < 3 ) or self .constraints :isValidNode (succ ) then
640- succ :updateG (primitive , self .constraints :getNodePenalty (succ ))
684+ local penalty = self .penaltyCache :get (succ )
685+ if penalty == nil then
686+ penalty = self .constraints :getNodePenalty (succ )
687+ self .penaltyCache :add (succ , penalty )
688+ end
689+ succ :updateG (primitive , penalty )
641690 local analyticSolutionCost = 0
642691 if self .analyticSolverEnabled then
643692 local analyticSolution = self .analyticSolver :solve (succ , self .goal , self .turnRadius )
0 commit comments