Skip to content

Commit 4af19c2

Browse files
authored
Merge pull request #9 from IOES-Lab/codex/shallow-exit-speed-scope
Scope shallow-exit speed phase to its appended route tail
2 parents a960032 + dc9d455 commit 4af19c2

3 files changed

Lines changed: 55 additions & 3 deletions

File tree

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "posim-routing"
7-
version = "0.1.6"
7+
version = "0.1.7"
88
description = "Global maritime and terrain checked coastal route planning"
99
requires-python = ">=3.10"
1010
license = {text = "Apache-2.0"}

‎src/posim_routing/regional.py‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,19 @@ def active_point(self,state,key):
109109
self.discard(state,'regional_clearance_policy_changed')
110110
return None
111111
from .course import passed_vertex
112+
# Persisted renewals from the previous coordinator may label their
113+
# entire retained runway as an exit. Only the appended tail is an exit.
114+
if plan.get('mode')=='shallow_exit' and plan.get('retained_checked_points',0):
115+
plan.setdefault('shallow_exit_start_index',plan['retained_checked_points'])
116+
exit_index=plan.get('shallow_exit_start_index')
112117
while plan['index']<len(plan['points']):
113118
index=plan['index'];point=plan['points'][index]
114-
reached=distance(state['position'],point)<(5 if plan.get('mode') in ('port_departure','shallow_exit') else 12 if plan.get('mode')=='port_approach' else 80)
119+
if exit_index is not None:
120+
plan['mode']='shallow_exit' if index>=exit_index else plan.get('retained_mode','coastal')
121+
exit_handoff=exit_index is not None and index==exit_index-1
122+
reached=distance(state['position'],point)<(5 if exit_handoff or plan.get('mode') in ('port_departure','shallow_exit') else 12 if plan.get('mode')=='port_approach' else 80)
115123
previous=plan['points'][index-1] if index else plan.get('probe_position')
116-
passed=(plan.get('mode') in ('coastal','coastal_transfer','coastal_approach') and previous is not None
124+
passed=(not exit_handoff and plan.get('mode') in ('coastal','coastal_transfer','coastal_approach') and previous is not None
117125
and index<len(plan['points'])-1 and passed_vertex(previous,point,plan['points'][index+1],
118126
state['position'],maximum_offset=200.,minimum_leg=0.,corner_margin=40.))
119127
if not reached and not passed:break
@@ -237,6 +245,8 @@ def update(self,state,target,needed=False,terminal=False,retain_coast=False,prog
237245
renew_coast=renew_coast or (point is not None and nearest is not None
238246
and plan.get('mode')=='coastal'
239247
and (plan.get('policy')!=REGIONAL_POLICY or not plan.get('onward_verified') or plan.get('waypoint_format')!=WAYPOINT_FORMAT))
248+
# Finish a known outward tail before asking for another continuation.
249+
renew_coast=renew_coast and plan.get('shallow_exit_start_index') is None
240250
coast_needed=nearest is not None and (self.probed is None or distance(self.probed,state['position'])>=3000)
241251
prefer_coast=(point is not None and coast_needed and not needed and
242252
(state.get('regional_navigation') or {}).get('mode') not in ('coastal','coastal_transfer','coastal_approach'))
@@ -263,6 +273,10 @@ def update(self,state,target,needed=False,terminal=False,retain_coast=False,prog
263273
retained=plan['points'][plan['index']:end+1]
264274
value['points']=retained+value['points'];value['index']=0
265275
value['retained_checked_points']=len(retained)
276+
if value.get('mode')=='shallow_exit':
277+
value['shallow_exit_start_index']=len(retained)
278+
value['retained_mode']=plan.get('mode','coastal')
279+
value['mode']=value['retained_mode']
266280
value['renewed_from']=connection
267281
value['probe_position']=list(state['position'])
268282
for metric in ('minimum_regional_clearance_m',):

‎tests/test_coastal_navigation.py‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,44 @@ async def result():return dict(points=[new],index=0,mode='coastal',route_key=key
399399
self.assertNotIn('regional_waiting',sample)
400400
await navigator.close()
401401

402+
async def test_outward_tail_does_not_relabel_retained_forward_runway(self):
403+
key=[0,0,1];start,first,end,exit_point=geo(800,1000),geo(800,2000),geo(800,3000),geo(1000,3000)
404+
navigator=RegionalNavigator(None);navigator.key=key
405+
sample=dict(lap=0,leg=0,waypoint=1,position=start,native={},
406+
regional_navigation=dict(points=[first,end],index=0,mode='coastal',route_key=key,
407+
policy=REGIONAL_POLICY,job='runway',probe_position=geo(800,0)))
408+
async def result():return dict(points=[exit_point],index=0,mode='shallow_exit',route_key=key,
409+
policy=REGIONAL_POLICY,job='exit',probe_position=end,
410+
continuation_of=dict(job='runway',endpoint=end))
411+
navigator.task=asyncio.create_task(result());await navigator.task
412+
self.assertEqual(navigator.update(sample,geo(800,90000)),first)
413+
plan=sample['regional_navigation']
414+
self.assertEqual(plan['mode'],'coastal');self.assertEqual(plan['shallow_exit_start_index'],2)
415+
sample['position']=first
416+
self.assertEqual(navigator.active_point(sample,key),end)
417+
sample['position']=geo(800,2950)
418+
self.assertEqual(navigator.active_point(sample,key),end)
419+
self.assertEqual(plan['mode'],'coastal')
420+
sample['position']=end
421+
self.assertEqual(navigator.active_point(sample,key),exit_point)
422+
self.assertEqual(plan['mode'],'shallow_exit');self.assertEqual(plan['index'],2)
423+
await navigator.close()
424+
425+
async def test_saved_exit_with_retained_points_migrates_only_its_phase(self):
426+
key=[0,0,1];first,end,exit_point=geo(800,2000),geo(800,3000),geo(1000,3000)
427+
plan=dict(points=[first,end,exit_point],index=0,mode='shallow_exit',route_key=key,
428+
policy=REGIONAL_POLICY,job='saved',probe_position=geo(800,0),retained_checked_points=2)
429+
sample=dict(position=geo(800,1000),native={},regional_navigation=plan)
430+
navigator=RegionalNavigator(None)
431+
self.assertEqual(navigator.active_point(sample,key),first)
432+
self.assertEqual(plan['mode'],'coastal');self.assertEqual(plan['points'],[first,end,exit_point])
433+
sample['position']=first
434+
self.assertEqual(navigator.active_point(sample,key),end)
435+
sample['position']=end
436+
self.assertEqual(navigator.active_point(sample,key),exit_point)
437+
self.assertEqual(plan['mode'],'shallow_exit')
438+
await navigator.close()
439+
402440
async def test_exhausted_coast_accepts_checked_replacement_water_route(self):
403441
async def rpc(*args,**kwargs):await asyncio.Event().wait()
404442
class Near:

0 commit comments

Comments
 (0)