@@ -259,25 +259,36 @@ def xy(node):
259259 nodes = nodes [:end + 1 ]
260260 # Shorten the grid path without erasing its coastal preference. Long
261261 # offshore shortcuts across bays have a higher coast-weighted cost.
262- points , index = [[* origin , 0. ]], 0
263- while index < len (nodes )- 1 :
264- chosen = index + 1
265- for end in range (min (len (nodes )- 1 , index + 10 ), index , - 1 ):
266- a , b = xy (nodes [index ]), xy (nodes [end ])
267- length = math .dist (a , b )
268- count = max (2 , math .ceil (length / min (dx , dy )* 3 ))
269- ix = np .rint (np .linspace (nodes [index ][1 ], nodes [end ][1 ], count )).astype (int )
270- iy = np .rint (np .linspace (nodes [index ][0 ], nodes [end ][0 ], count )).astype (int )
271- weighted = length * float (np .mean (penalty [iy , ix ]))
272- old = costs [nodes [end ]]- costs [nodes [index ]]
273- if safe [iy , ix ].all () and weighted <= old * 1.08 :
274- chosen = end
275- break
276- points .append (xy (nodes [chosen ]))
277- index = chosen
262+ def shorten (route , lookahead = None ):
263+ points , index = [xy (route [0 ])], 0
264+ while index < len (route )- 1 :
265+ chosen = index + 1
266+ last = min (len (route )- 1 , index + lookahead ) if lookahead else len (route )- 1
267+ for candidate in range (last , index , - 1 ):
268+ if time .monotonic () > deadline :
269+ raise RuntimeError ("coastal_planning_budget_exceeded" )
270+ a , b = xy (route [index ]), xy (route [candidate ])
271+ length = math .dist (a , b )
272+ count = max (2 , math .ceil (length / min (dx , dy )* 3 ))
273+ ix = np .rint (np .linspace (route [index ][1 ], route [candidate ][1 ], count )).astype (int )
274+ iy = np .rint (np .linspace (route [index ][0 ], route [candidate ][0 ], count )).astype (int )
275+ weighted = length * float (np .mean (penalty [iy , ix ]))
276+ old = costs [route [candidate ]]- costs [route [index ]]
277+ if (safe [iy , ix ].all () and weighted <= old * 1.08
278+ and validator .segment (a , b )):
279+ chosen = candidate
280+ break
281+ points .append (xy (route [chosen ]))
282+ index = chosen
283+ return points
284+
285+ points = shorten (nodes , lookahead = 10 )
286+ points [0 ] = [* origin , 0. ]
287+ onward = shorten ([endpoint , * onward_nodes ])
278288 if sum (math .dist (a , b ) for a , b in zip (points , points [1 :])) > 40000 :
279289 continue
280- if not all (validator .segment (a , b , record = True ) for a , b in zip (points , points [1 :])):
290+ if not all (validator .segment (a , b , record = True ) for route in (points , onward )
291+ for a , b in zip (route , route [1 :])):
281292 continue
282293 return dict (points = [list (inverse .transform (* point [:2 ])) for point in points [1 :]],
283294 index = 0 , mode = "coastal" , planning_seconds = time .monotonic ()- started ,
@@ -286,7 +297,7 @@ def xy(node):
286297 endpoint_standoff_m = float (coast_distance [endpoint ]),
287298 maximum_preferred_standoff_m = MAXIMUM_STANDOFF_M ,
288299 progress_to_course_waypoint_m = float (progress [endpoint ]),
289- onward_points = [list (inverse .transform (* xy ( node ) [:2 ])) for node in onward_nodes ],
300+ onward_points = [list (inverse .transform (* point [:2 ])) for point in onward [ 1 :] ],
290301 onward_exit = list (inverse .transform (* xy (goal )[:2 ])),
291302 onward_exit_progress_m = float (progress [goal ]),
292303 onward_verified = True ,
0 commit comments