Conditions | 3 |
Total Lines | 98 |
Code Lines | 59 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
1 | import numpy as np |
||
172 | def direct(lats1: 'list', lons1: 'list', brgs: 'list', dists: 'list') -> 'dict': |
||
173 | """ |
||
174 | Direct geodesic using Vincenty approach. |
||
175 | |||
176 | Given a start point, initial bearing (0° is North, clockwise) |
||
177 | and distance in meters, this will calculate the destination point |
||
178 | and final bearing travelling along a (shortest distance) great circle arc. |
||
179 | |||
180 | Bearing in 0-360deg starting from North clockwise. |
||
181 | |||
182 | all variables must be of same length |
||
183 | |||
184 | Ref: |
||
185 | https://www.movable-type.co.uk/scripts/latlong.html |
||
186 | https://www.movable-type.co.uk/scripts/latlong-vincenty.html |
||
187 | """ |
||
188 | |||
189 | lon1, lat1, brg = map(np.radians, [lons1, lats1, brgs]) |
||
190 | |||
191 | # WGS84 |
||
192 | a = 6378137.0 |
||
193 | b = 6356752.314245 |
||
194 | f = 1.0 / 298.257223563 |
||
195 | |||
196 | azi1 = brg |
||
197 | s = dists |
||
198 | |||
199 | sin_azi1 = np.sin(azi1) |
||
200 | cos_azi1 = np.cos(azi1) |
||
201 | |||
202 | tan_U1 = (1 - f) * np.tan(lat1) |
||
203 | cos_U1 = 1 / np.sqrt((1 + tan_U1 * tan_U1)) |
||
204 | sin_U1 = tan_U1 * cos_U1 |
||
205 | |||
206 | # sigma1 = angular distance on the sphere from the equator to P1 |
||
207 | sigma1 = np.arctan2(tan_U1, cos_azi1) |
||
208 | |||
209 | sin_azi = cos_U1 * sin_azi1 # azi = azimuth of the geodesic at the equator |
||
210 | cos_Sq_azi = 1 - sin_azi * sin_azi |
||
211 | uSq = cos_Sq_azi * (a * a - b * b) / (b * b) |
||
212 | A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))) |
||
213 | B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))) |
||
214 | |||
215 | sigma = s / (b * A) |
||
216 | # sigma = angular distance P₁ P₂ on the sphere |
||
217 | # sigmam = angular distance on the sphere from the equator to |
||
218 | # the midpoint of the line |
||
219 | sin_sigma = np.sin(sigma) |
||
220 | cos_sigma = np.cos(sigma) |
||
221 | cos_2_sigma_m = np.cos(2 * sigma1 + sigma) |
||
222 | |||
223 | iterations = 0 |
||
224 | sigma_prime = 0 |
||
225 | |||
226 | while (np.abs(sigma - sigma_prime) > 1e-12).any(): |
||
227 | cos_2_sigma_m = np.cos(2 * sigma1 + sigma) |
||
228 | sin_sigma = np.sin(sigma) |
||
229 | cos_sigma = np.cos(sigma) |
||
230 | delta_sigma = (B * sin_sigma) * ( |
||
231 | cos_2_sigma_m |
||
232 | + B |
||
233 | / 4 |
||
234 | * ( |
||
235 | cos_sigma * (-1 + 2 * cos_2_sigma_m * cos_2_sigma_m) |
||
236 | - (B / 6 * cos_2_sigma_m) |
||
237 | * (-3 + 4 * sin_sigma * sin_sigma) |
||
238 | * (-3 + 4 * cos_2_sigma_m * cos_2_sigma_m) |
||
239 | ) |
||
240 | ) |
||
241 | sigma_prime = sigma |
||
242 | sigma = s / (b * A) + delta_sigma |
||
243 | iterations += 1 |
||
244 | if iterations >= 50: |
||
245 | raise Exception('Vincenty formula failed to converge') |
||
246 | |||
247 | x = sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_azi1 |
||
248 | lat2 = np.arctan2( |
||
249 | sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_azi1, |
||
250 | (1 - f) * np.sqrt(sin_azi * sin_azi + x * x), |
||
251 | ) |
||
252 | lambda_ = np.arctan2( |
||
253 | sin_sigma * sin_azi1, cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_azi1 |
||
254 | ) |
||
255 | C = f / 16 * cos_Sq_azi * (4 + f * (4 - 3 * cos_Sq_azi)) |
||
256 | L = lambda_ - (1 - C) * f * sin_azi * ( |
||
257 | sigma |
||
258 | + C |
||
259 | * sin_sigma |
||
260 | * (cos_2_sigma_m + C * cos_sigma * (-1 + 2 * cos_2_sigma_m * cos_2_sigma_m)) |
||
261 | ) |
||
262 | lon2 = lon1 + L |
||
263 | azi2 = np.arctan2(sin_azi, -x) |
||
264 | |||
265 | lat2 = wrap90deg(lat2 * 180.0 / np.pi) |
||
266 | lon2 = wrap180deg(lon2 * 180.0 / np.pi) |
||
267 | azi2 = wrap360deg(azi2 * 180.0 / np.pi) |
||
268 | |||
269 | return {'lat2': lat2, 'lon2': lon2, 'azi2': azi2, 'iterations': iterations} |
||
270 |