6969Mode = Enum ('Mode' , ['Config' , 'Ready' , 'Run' , 'Result' ])
7070rl = roaring_landmask .RoaringLandmask .new ()
7171
72+ def coastline_crossing (lon1 , lat1 , lon2 , lat2 , step_degrees , land_side = True ):
73+ """Return the coastline crossing points between positions in water (lon1,lat1) and positions on land (lon2, lat2).
74+
75+ This function uses the RoaringLandmask to find the coastline crossing points,
76+ but can be generalised to any landmask later.
77+
78+ Args:
79+ lon1, lat1: Coordinates of first point
80+ lon2, lat2: Coordinates of second point
81+ precision: Precision for coastline approximation, in degrees
82+ land_side: If True, return the last position in water and first position on land.
83+
84+ Returns:
85+ lon, lat
86+ Last position in water (if land_side is False) or first position on land (if land_side is True (default)) along transect
87+ """
88+
89+ lon1 = np .atleast_1d (lon1 )
90+ lat1 = np .atleast_1d (lat1 )
91+ lon2 = np .atleast_1d (lon2 )
92+ lat2 = np .atleast_1d (lat2 )
93+ if land_side is True :
94+ lon_c = lon2
95+ lat_c = lat2
96+ else :
97+ lon_c = lon1
98+ lat_c = lat1
99+ for i , (lon1 , lat1 , lon2 , lat2 ) in enumerate (zip (lon1 , lat1 , lon2 , lat2 )):
100+ x_degree_diff = np .abs (lon2 - lon1 )
101+ y_degree_diff = np .abs (lat2 - lat1 )
102+ if x_degree_diff == 0 and y_degree_diff == 0 :
103+ continue
104+ x_samples = np .floor (x_degree_diff / step_degrees ).astype (np .int64 ) if x_degree_diff > step_degrees else 1
105+ x = np .linspace (lon1 , lon2 , x_samples )
106+ y_samples = np .floor (y_degree_diff / step_degrees ).astype (np .int64 ) if y_degree_diff > step_degrees else 1
107+ y = np .linspace (lat1 , lat2 , y_samples )
108+
109+ xx , yy = np .meshgrid (x ,y )
110+ xx , yy = xx .ravel (), yy .ravel ()
111+
112+ rl_mask = rl .contains_many (xx , yy )
113+ if np .any (rl_mask ):
114+ index = np .argmax (rl_mask )
115+ if land_side is False :
116+ index = np .maximum (0 , index - 1 )
117+ lon_c [i ] = xx [index ]
118+ lat_c [i ] = yy [index ]
119+ return lon_c , lat_c
120+
72121def require_mode (mode : Union [Mode , List [Mode ]], post_next_mode = False , error = None ):
73122 if not isinstance (mode , list ):
74123 mode = [mode ]
@@ -643,34 +692,14 @@ def interact_with_coastline(self, final=False):
643692 if not coastline_approximation_precision :
644693 return
645694
646- for on_land_id , on_land_prev_id in zip (on_land , self .elements .ID [on_land ]):
647- lon = self .elements .lon [on_land_id ]
648- lat = self .elements .lat [on_land_id ]
649- prev_lon = self ._elements_previous .lon [on_land_prev_id ].data
650- prev_lat = self ._elements_previous .lat [on_land_prev_id ].data
651- step_degrees = float (coastline_approximation_precision )
652-
653- x_degree_diff = np .abs (prev_lon - lon )
654- y_degree_diff = np .abs (prev_lat - lat )
655- if x_degree_diff == 0 and y_degree_diff == 0 :
656- continue
657- x_samples = np .floor (x_degree_diff / step_degrees ).astype (np .int64 ) if x_degree_diff > step_degrees else 1
658- x = np .linspace (prev_lon , lon , x_samples )
659-
660- y_samples = np .floor (y_degree_diff / step_degrees ).astype (np .int64 ) if y_degree_diff > step_degrees else 1
661- y = np .linspace (prev_lat , lat , y_samples )
662-
663- xx , yy = np .meshgrid (x ,y )
664- xx , yy = xx .ravel (), yy .ravel ()
665-
666- rl_mask = rl .contains_many (xx , yy )
667- if np .any (rl_mask ):
668- index = np .argmax (rl_mask )
669- new_lon = xx [index ]
670- new_lat = yy [index ]
671-
672- self .elements .lon [on_land_id ] = new_lon
673- self .elements .lat [on_land_id ] = new_lat
695+ self .elements .lon [on_land ], self .elements .lat [on_land ] = coastline_crossing (
696+ self ._elements_previous .lon [on_land ],
697+ self ._elements_previous .lat [on_land ],
698+ self .elements .lon [on_land ],
699+ self .elements .lat [on_land ],
700+ coastline_approximation_precision ,
701+ land_side = True
702+ )
674703
675704 self .environment .land_binary_mask [on_land ] = 0
676705
@@ -687,8 +716,19 @@ def interact_with_coastline(self, final=False):
687716 logger .debug ('%s elements hit coastline, '
688717 'moving back to water' % len (on_land ))
689718 on_land_ID = self .elements .ID [on_land ]
690- self .elements .lon [on_land ] = self ._elements_previous .lon [on_land_ID ]
691- self .elements .lat [on_land ] = self ._elements_previous .lat [on_land_ID ]
719+
720+ if not coastline_approximation_precision :
721+ self .elements .lon [on_land ] = self ._elements_previous .lon [on_land_ID ]
722+ self .elements .lat [on_land ] = self ._elements_previous .lat [on_land_ID ]
723+ else :
724+ self .elements .lon [on_land ], self .elements .lat [on_land ] = coastline_crossing (
725+ self ._elements_previous .lon [on_land ],
726+ self ._elements_previous .lat [on_land ],
727+ self .elements .lon [on_land ],
728+ self .elements .lat [on_land ],
729+ coastline_approximation_precision ,
730+ land_side = False
731+ )
692732 self .environment .land_binary_mask [on_land ] = 0
693733
694734 def interact_with_seafloor (self ):
0 commit comments